diff --git a/ALL_BUILD.vcproj b/ALL_BUILD.vcproj new file mode 100644 index 0000000..284ddd4 --- /dev/null +++ b/ALL_BUILD.vcproj @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..e69de29 diff --git a/AUTHORS.sim b/AUTHORS.sim new file mode 100644 index 0000000..2784d04 --- /dev/null +++ b/AUTHORS.sim @@ -0,0 +1,38 @@ +List of authors of original SIM: + +Maintainer: Vladimir Shutoff +Development: Christian Ehrlicher +KAddressBook sync and some art: Stanislav Klyuhin + +Translators: +Bulgarian: Atanas Mavrov +Brazilian: Carlos Tadeu Panato Jr. +Chinese: Stacker Liew +Czech: Pavel Rousar +Czech: Jiri Jurecek +German: Tobias Franz +German: Christoph Thielecke +Greek: Theodore Karkoulis +Hungarian: Kroly Barcza +French: Roméo VIU-BERGES +Italian: Lapo Luchini +Polish: Rafal Bera +Russian: Vladimir Shutoff +Slovak: Tomas Olah +Spain: Jorge Lopez Trescastro +Swabian: Robert Scheck +Thai: Narachai Sakorn +Turkish: Ismail Donmez +Ukranian: Ivan O.Krutyholova + +Currently no translator: +Catalan +Dutch - view nl.po +Hebrew - view he.po + +Bug hunter: +Christoph Thielecke +Marcel Meckel +Robert Scheck +Tobias Franz +Andrey Rahmatullin diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..06a1731 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,258 @@ +# main cmake file for SIM-IM + +PROJECT(Sim-IM) +SET(Sim-IM_VERSION 0.9.6) + +CMAKE_MINIMUM_REQUIRED(VERSION 2.6.0) +SET(CMAKE_COLOR_MAKEFILE ON) + +# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked +SET(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") + +if(COMMAND cmake_policy) + cmake_policy(SET CMP0003 NEW) +endif(COMMAND cmake_policy) + +SET(CMAKE_CXX_FLAGS "-g -Wall") +SET(LINK_FLAGS "-g") + +IF( APPLE ) + SET( PROGNAME Sim-IM ) + SET( MACOSX_BUNDLE_BUNDLE_NAME Sim-IM ) + SET( MACOSX_BUNDLE_ICON_FILE sim.icns ) + SET( MACOSX_BUNDLE_SHORT_VERSION_STRING 0.9.6 ) + SET( MACOSX_BUNDLE_VERSION 0.9.6 ) + SET( MACOSX_BUNDLE_LONG_VERSION_STRING Version 0.9.6 ) + SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -arch i386" ) + SET( CMAKE_C_FLAGS "-arch i386" ) +ELSE( APPLE ) + SET( PROGNAME sim ) +ENDIF( APPLE ) + +#SET(CMAKE_VERBOSE_MAKEFILE ON) + +INCLUDE(Flex) +INCLUDE(Jisp) +INCLUDE(MacroBoolTo01) +INCLUDE(Po) +INCLUDE(SimPlugins) +INCLUDE(DistTarget) +INCLUDE(CheckCXXCompilerFlag) + +OPTION(SIM_ENABLE_FPIE "Enable PIE linking") +OPTION(ENABLE_TARGET_UPDATE_MESSAGES "Enables target that allows to extract i18n messages from the code, and update *.po files with them") + +# need 4.3 for some QHttp functionality +SET(QT_MIN_VERSION 4.3.0) +FIND_PACKAGE(Qt4 REQUIRED) +IF(NOT QT_FOUND) + MESSAGE(FATAL_ERROR "Could not find Qt4 - cannot compile Sim-IM here") +ENDIF(NOT QT_FOUND) + +# needed packages +FIND_PACKAGE(LibXml2 REQUIRED) +FIND_PACKAGE(LibXslt REQUIRED) +FIND_PACKAGE(ZLIB REQUIRED) +FIND_PACKAGE(OpenSSL) +IF(WIN32) + FIND_PACKAGE(LibIconv REQUIRED) +ENDIF(WIN32) + +SET(QT_USE_QTXML 1) +SET(QT_USE_QTUITOOLS 1) +SET(QT_USE_QTNETWORK 1) +SET(QT_USE_PHONON 1) +SET(QT_USE_QTTEST 1) +SET(QT_PHONON_INCLUDE_DIR "/usr/include/phonon") +INCLUDE(${QT_USE_FILE}) + +# optional packages +FIND_PACKAGE(ASPELL) + +IF(NOT WIN32 AND NOT APPLE) + FIND_PACKAGE(KDE4) + IF(KDE4_FOUND) + OPTION(ENABLE_KDE4 "Enable KDE4 support" ON) + IF(ENABLE_KDE4) + ADD_DEFINITIONS(${KDE4_DEFINITIONS} -DUSE_KDE4) + INCLUDE_DIRECTORIES(${KDE4_INCLUDES}) + ENDIF(ENABLE_KDE4) + ENDIF(KDE4_FOUND) + + INCLUDE(FindX11) +ENDIF(NOT WIN32 AND NOT APPLE) + +# do config checks +INCLUDE(ConfigureChecks.cmake) + +MACRO_BOOL_TO_01(OPENSSL_FOUND ENABLE_OPENSSL) +MACRO_BOOL_TO_01(X11_FOUND HAVE_X) + +# development or release builds +OPTION(DEV_BUILD "Build development version" YES) +OPTION(BUILD_DROPPED "Build dropped plugins" NO) +MACRO_BOOL_TO_01(DEV_BUILD CVS_BUILD) + +# global settings for every project +ADD_DEFINITIONS(${QT_DEFINITIONS} -DHAVE_CONFIG_H) +INCLUDE_DIRECTORIES(${QT_INCLUDE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_BINARY_DIR}/sim + ${Sim-IM_SOURCE_DIR}/sim + ${Sim-IM_SOURCE_DIR}/sim/simgui + ${Sim-IM_SOURCE_DIR}/plugins/_core) +LINK_DIRECTORIES(${QT_LIB_DIR}) + +# windows, microsoft compiler +if(MSVC) + if(CMAKE_COMPILER_2005) + add_definitions( -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE ) + set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -wd4661" ) + endif(CMAKE_COMPILER_2005) +else(MSVC) + add_definitions( -Wno-non-virtual-dtor ) +endif(MSVC) + +add_definitions( -DUNICODE ) + +IF(CMAKE_COMPILER_IS_GNUCXX AND SIM_ENABLE_FPIE) + CHECK_CXX_COMPILER_FLAG(-fPIE HAVE_FPIE_SUPPORT) + IF(HAVE_FPIE_SUPPORT) + SET (SIM_CXX_FPIE_FLAGS "-fPIE") + SET (SIM_PIE_LDFLAGS "-pie") + ELSE(HAVE_FPIE_SUPPORT) + MESSAGE(STATUS "Your compiler doesn't support PIE flag") + ENDIF(HAVE_FPIE_SUPPORT) +ENDIF(CMAKE_COMPILER_IS_GNUCXX AND SIM_ENABLE_FPIE) + +SET(SIM_FLAVOUR "" CACHE STRING "Additional suffix for plugin dir and executable file") +if(WIN32) + SET(LIBDIR .) + SET(BINDIR .) + SET(SIM_I18N_DIR po) + SET(SIM_ICONS_DIR icons) + SET(SIM_PICT_DIR pict) + SET(SIM_PLUGIN_DIR plugins) + SET(SIM_SOUND_DIR sounds) + SET(SIM_STYLES_DIR styles) +else(WIN32) +if(APPLE) + SET(SIMBUNDLE ${CMAKE_BINARY_DIR}/sim/${PROGNAME}.app) + SET(LIBDIR ${SIMBUNDLE}/Contents/MacOS) + SET(BINDIR ${CMAKE_BINARY_DIR}) + SET(SIM_I18N_DIR ${SIMBUNDLE}/Contents/Resources/po) + SET(SIM_ICONS_DIR ${SIMBUNDLE}/Contents/Resources/icons) + SET(SIM_PICT_DIR ${SIMBUNDLE}/Contents/Resources/pict) + SET(SIM_PLUGIN_DIR ${SIMBUNDLE}/Contents/PlugIns) + SET(SIM_SOUND_DIR ${SIMBUNDLE}/Contents/Resources/sounds) + SET(SIM_STYLES_DIR ${SIMBUNDLE}/Contents/Resources/styles) +else(APPLE) + SET(LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)") + SET(LIBDIR ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX} CACHE PATH "Path to sim library") + SET(BINDIR ${CMAKE_INSTALL_PREFIX}/bin CACHE PATH "Path to sim binary") + SET(DATADIR ${CMAKE_INSTALL_PREFIX}/share/apps/sim CACHE PATH "Path to sim data") + SET(SIM_PLUGIN_DIR ${LIBDIR}/sim${SIM_FLAVOUR} CACHE PATH "Path to sim plugins") + SET(SIM_I18N_DIR ${CMAKE_INSTALL_PREFIX}/share/locale) + SET(SIM_ICONS_DIR ${DATADIR}/icons) + SET(SIM_PICT_DIR ${DATADIR}/pict) + SET(SIM_SOUND_DIR ${DATADIR}/sounds) + SET(SIM_STYLES_DIR ${DATADIR}/styles) + SET(SHARE_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}/share) + SET(XDG_APPS_DIR ${SHARE_INSTALL_PREFIX}/applications/kde) + SET(SERVICES_INSTALL_DIR ${SHARE_INSTALL_PREFIX}/services) +endif(APPLE) +endif(WIN32) + +IF(ENABLE_TARGET_UPDATE_MESSAGES) + MESSAGE(STATUS "Enabling target update-messages") + INCLUDE(XGetText) + + IF(XGETTEXT_EXECUTABLE AND MSGMERGE_EXECUTABLE) + MESSAGE(STATUS "Target update-messages successfuly enabled") + ELSE(XGETTEXT_EXECUTABLE AND MSGMERGE_EXECUTABLE) + MESSAGE(STATUS "Can't enable target update-messages: one or more componets are missing") + SET(ENABLE_TARGET_UPDATE_MESSAGES OFF) + ENDIF(XGETTEXT_EXECUTABLE AND MSGMERGE_EXECUTABLE) + +ENDIF(ENABLE_TARGET_UPDATE_MESSAGES) + +# subdirectories +ADD_SUBDIRECTORY(sim) +SIM_FIND_PLUGINS(${Sim-IM_SOURCE_DIR}/plugins) +SIM_INCLUDE_PLUGINS() + +# create config.h +CONFIGURE_FILE(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h) +add_definitions( -DHAVE_CONFIG_H ) + +# the (win32) flex generator doesn't care about HAVE_UNISTD_H - it simply has to +# be there. So create a dummy one if none exists +IF(NOT HAVE_UNISTD_H) + WRITE_FILE( ${CMAKE_CURRENT_BINARY_DIR}/sim/unistd.h + "/* dummy unistd.h file for flex generated parsers */" ) +ENDIF(NOT HAVE_UNISTD_H) + +# for uninstall target +CONFIGURE_FILE( + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" + IMMEDIATE @ONLY) + +# uninstall target +ADD_CUSTOM_TARGET(uninstall + "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") + + +######################################## +# update-messages target +####################################### +IF ( ENABLE_TARGET_UPDATE_MESSAGES ) + + ADD_CUSTOM_TARGET(update-messages) + + SET(new_pot "${CMAKE_CURRENT_BINARY_DIR}/new_messages") + EMPTY_PO_FILE(${new_pot}) + + ADD_CUSTOM_COMMAND(TARGET update-messages + COMMAND echo Processing simlib + ) + LIST(SORT sim_LIB_MESSAGE_SOURCES) + FOREACH(file ${sim_LIB_MESSAGE_SOURCES}) + EXTRACT_MESSAGES("${Sim-IM_SOURCE_DIR}/sim/${file}" ${new_pot}) + ENDFOREACH(file) + + LIST(SORT SIM_PLUGINS) + FOREACH(plugin ${SIM_PLUGINS}) + ADD_CUSTOM_COMMAND(TARGET update-messages + COMMAND echo Processing plugin ${plugin} + ) + IF(${plugin}_MESSAGE_SOURCES) + LIST(SORT ${plugin}_MESSAGE_SOURCES) + FOREACH(file ${${plugin}_MESSAGE_SOURCES}) + EXTRACT_MESSAGES("${Sim-IM_PLUGINS_SOURCE_DIR}/${plugin}/${file}" ${new_pot}) + ENDFOREACH(file) + ENDIF(${plugin}_MESSAGE_SOURCES) + ENDFOREACH(plugin) + + ADD_CUSTOM_COMMAND(TARGET update-messages + COMMAND echo Updating .po files + COMMAND mv ${CMAKE_SOURCE_DIR}/po/sim.pot ${CMAKE_SOURCE_DIR}/po/sim.pot.backup + COMMAND mv ${new_pot}.po ${CMAKE_SOURCE_DIR}/po/sim.pot + ) + + FILE(GLOB po_files ${CMAKE_SOURCE_DIR}/po/*.po) + FOREACH(po_file ${po_files}) + ADD_CUSTOM_COMMAND(TARGET update-messages + COMMAND mv ${po_file} ${po_file}.backup + ) + ENDFOREACH(po_file) + + FOREACH(po_file ${po_files}) + GET_FILENAME_COMPONENT(po_name ${po_file} NAME) + ADD_CUSTOM_COMMAND(TARGET update-messages + COMMAND echo ${po_name} + COMMAND ${MSGMERGE_EXECUTABLE} ${po_file}.backup ${CMAKE_SOURCE_DIR}/po/sim.pot >${po_file} + ) + ENDFOREACH(po_file) +ENDIF ( ENABLE_TARGET_UPDATE_MESSAGES ) + diff --git a/CMakeLists.txt.user b/CMakeLists.txt.user new file mode 100644 index 0000000..c0958eb --- /dev/null +++ b/CMakeLists.txt.user @@ -0,0 +1,222 @@ + + + + RunConfiguration0-BaseEnvironmentBase + 2 + + + RunConfiguration0-CMakeRunConfiguation.Title + sim + + + RunConfiguration0-CMakeRunConfiguration.Arguments + + + + RunConfiguration0-CMakeRunConfiguration.Target + /home/todin/projects/sim-im/sim-im-incoming/qtcreator-build/sim/sim + + + RunConfiguration0-CMakeRunConfiguration.UseTerminal + false + + + RunConfiguration0-CMakeRunConfiguration.UserEnvironmentChanges + + + + RunConfiguration0-CMakeRunConfiguration.UserWorkingDirectory + + + + RunConfiguration0-CMakeRunConfiguration.WorkingDirectory + + + + RunConfiguration0-RunConfiguration.name + sim + + + RunConfiguration0-type + CMakeProjectManager.CMakeRunConfiguration + + + RunConfiguration1-BaseEnvironmentBase + 2 + + + RunConfiguration1-CMakeRunConfiguation.Title + test + + + RunConfiguration1-CMakeRunConfiguration.Arguments + + + + RunConfiguration1-CMakeRunConfiguration.Target + /home/todin/projects/sim-im/sim-im-incoming/qtcreator-build/sim/test + + + RunConfiguration1-CMakeRunConfiguration.UseTerminal + false + + + RunConfiguration1-CMakeRunConfiguration.UserEnvironmentChanges + + + + RunConfiguration1-CMakeRunConfiguration.UserWorkingDirectory + + + + RunConfiguration1-CMakeRunConfiguration.WorkingDirectory + + + + RunConfiguration1-RunConfiguration.name + test + + + RunConfiguration1-type + CMakeProjectManager.CMakeRunConfiguration + + + activeRunConfiguration + 0 + + + activebuildconfiguration + all + + + buildConfiguration-all + + all + /home/todin/projects/sim-im/sim-im-incoming/qtcreator-build + + + + + buildconfiguration-all-buildstep0 + + all + + ALSA_PLUGINS_DIR=/usr/lib/alsa-lib + ANT_HOME=/usr/share/java/apache-ant + DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-EQjaPRDk1D,guid=ee9dfdf4a0e89ac54931d68d4b91ffee + DERBY_HOME=/opt/java/db + DESKTOP_SESSION=kde + DISPLAY=:0 + DM_CONTROL=/var/run/xdmctl + ECLIM_ECLIPSE_HOME=/usr/share/eclipse + EDITOR=vim + GPG_AGENT_INFO=/tmp/gpg-JdHoIz/S.gpg-agent:3876:1 + GS_LIB=/home/todin/.fonts + GTK2_RC_FILES=/etc/gtk-2.0/gtkrc:/home/todin/.gtkrc-2.0::/home/todin/.kde4/share/config/gtkrc-2.0 + GTK_RC_FILES=/etc/gtk/gtkrc:/home/todin/.gtkrc::/home/todin/.kde4/share/config/gtkrc + G_BROKEN_FILENAMES=1 + HG=/usr/bin/hg + HISTCONTROL=erasedups + HISTSIZE=1000 + HOME=/home/todin + INPUTRC=/etc/inputrc + J2SDKDIR=/opt/java + JAVA_HOME=/opt/java + KDE_FULL_SESSION=true + KDE_MULTIHEAD=false + KDE_SESSION_UID=1000 + KDE_SESSION_VERSION=4 + LANG=en_US.UTF-8 + LANGUAGE= + LESS=-R + LOGNAME=todin + MOZ_PLUGIN_PATH=/usr/lib/mozilla/plugins + PATH=/opt/wine/bin:/bin:/usr/bin:/sbin:/usr/sbin:/usr/share/java/apache-ant/bin:/opt/java/bin:/opt/java/jre/bin:/opt/kde/bin:/usr/bin/perlbin/site:/usr/bin/perlbin/vendor:/usr/bin/perlbin/core:/opt/qt/bin:/home/todin/x-tools/arm-unknown-eabi/bin:/home/todin/projects/arm/crosstool-ng/bin:/home/todin/bin + PKG_CONFIG_PATH=/usr/lib/pkgconfig:/opt/qt/lib/pkgconfig + PS3=> + PS4=+ + PWD=/home/todin + QTDIR=/opt/qt + QT_PLUGIN_PATH=/home/todin/.kde4/lib/kde4/plugins/:/usr/lib/kde4/plugins/ + QT_XFT=true + SESSION_MANAGER=local/hell:@/tmp/.ICE-unix/3930,unix/hell:/tmp/.ICE-unix/3930 + SHELL=/bin/bash + SHLVL=1 + SSH_AGENT_PID=3879 + SSH_AUTH_SOCK=/tmp/ssh-JqDPIk3878/agent.3878 + SVN_EDITOR=vim + USER=todin + WINDOWPATH=7 + WINELOADER=/opt/wine/bin/wine + XCURSOR_THEME=Oxygen_Black + XDG_CACHE_HOME=/home/todin/.cache + XDG_CONFIG_DIRS=/etc/xdg:/etc/xdg:/etc/xdg:/etc/xdg + XDG_CONFIG_HOME=/home/todin/.config + XDG_DATA_DIRS=/usr/share:/usr/local/share:/usr/share:/usr/local/share:/usr/share:/usr/local/share:/usr/share:/usr/local/share:/opt/kde/share:/opt/kde/share:/opt/kde/share:/opt/kde/share + XDG_DATA_HOME=/home/todin/.local/share + XDG_SESSION_COOKIE=46070e371950b58c8ac873a74ae405f7-1267859436.916749-723754984 + XDM_MANAGED=method=classic + _=/usr/lib/kde4/libexec/start_kdeinit_wrapper + + false + + -j6 + + make + true + /home/todin/projects/sim-im/sim-im-incoming/qtcreator-build + + -j6 + + + + + buildconfiguration-all-cleanstep0 + + all + + clean + + true + + + + buildconfigurations + + all + + + + buildstep0 + + + + + + buildsteps + + CMakeProjectManager.MakeStep + + + + cleanstep0 + + + true + + + + cleansteps + + CMakeProjectManager.MakeStep + + + + defaultFileEncoding + UTF-8 + + + project + + + diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..45645b4 --- /dev/null +++ b/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..50af5ee --- /dev/null +++ b/ChangeLog @@ -0,0 +1,99 @@ +USER-VISIBLE CHANGES IN SIM INSTANT MESSENGER + +[+] New +[-] Fixed error +[*] Changes + + +=== SIM 0.9.5 (not released yet) === + + +Build system +~~~~~~~~~~~~ +[*] Update admin/ dir to KDE 3.5.3. +[+] Make 'make dist' working. +[+] Add ability to build in separate directory. +[+] Unix: do not delete .la files after installing. +[+] MacOSX: fix build with X11. +[+] Win32/MSVC: switch to MSVC8. +[+] Win32/MSVC: use precompiled headers. +[+] Unix: issue error, not warning, if openssl wasn't found. +[-] Autotools: fix SMP builds. +[-] Autotools: add AC_LANG_C. +[+] Add hidden visibility support for GCC4.1 and cmake. +[-] Autotools: fix libXss detection. + +Core +~~~~ +[+] Command line option to run SIM with specified profile. +[+] Option to show contact list title in message window title. +[+] Contact list: search in contact list by a substring in contact name. +[+] History: option to use external viewer. +[+] Contact list: search in closed contact list groups too. +[-] Contact list: fix deleting contacts by pressing Del. +[*] Remove Qt2 code. +[*] Use QLibrary for plugins instead of libltdl. +[+] Contact list: search in contact list by user protocol IDs. +[+] Add profile (re)naming feature. +[-] Fix context menu shortcuts in dialog window. +[+] Save state on system logout with Qt Session Management. +[-] Win32: fix (un)setting autostart. +[-] Fix restoring font sizes. +[-] Disable history filter when it is empty. +[+] Replace libxml2-based SAX parser with Qt-provided one. +[+] Show user avatars in the dialog window. +[-] Remove "To container" menu when separate containers are disabled. +[*] Auto scroll message view only if it is scrolled to the bottom. +[-] XFree: fix problems with Composite extension enabled. + +ICQ plugin +~~~~~~~~~~ +[*] Improve client versions detection. +[-] Do not delete contacts if group changed while offline. +[*] Accept messages in Occupied/DND modes by default. +[+] Add new icons from ICQ 5 and ICQ 5.1. +[+] Add MD5 auth support for ICQ accounts. +[-] Fix user info saving. +[-] Fix birthday flag handling. +[-] Sync language and occupation lists with ICQ server. +[*] Disable "Automatically use HTTP polling if proxy required" by + default. +[+] Send and detect SIM patchlevel in version info. +[-] Fix receiving certain messages containing TLV(5) twice. +[-] Fix playing sounds for messages from QIP. + +Jabber plugin +~~~~~~~~~~~~~ +[-] Fix crash on auth request when "Receive message only from contacts from list". +[-] Fix handling of single quotes in roster item names. +[+] Add icons for sms and gadu-gadu transports. +[*] Detect jabber transports by missing "@" symbol in jid instead of + "/registered" ending. +[+] Allow auth messages for transports. +[*] Show protocol icons for jabber transports in roster. +[*] Ignore JID letter case. +[+] Add support for XEP-0092 client version info requests/replies. +[*] Show resource as a part of JID in contact tip, not as separate line. +[*] Remove SIM version from default resource value. + +Yahoo! plugin +~~~~~~~~~~~~~ + + +MSN plugin +~~~~~~~~~~ +[+] Add password recovery URL. + +Misc plugins +~~~~~~~~~~~~ +[-] LiveJournal: security level of message was set incorrectly. +[+] LiveJournal: add optional signature to all messages. +[+] LiveJournal: option to disable message text formatting. +[-] Proxy: fix some crashes. +[*] Logger: remove dangerous 'Events' logging facility +[-] Icons: fix handling of JISP files with non-ascii paths. +[-] Icons: fix handling of JISP files containing subdirectiories. +[*] Shortcuts: fix global shortcuts on X11 Qt-only build. +[*] LiveJournal: disable formatted messages by default. +[*] LiveJournal: add password recovery URL. +[-] LiveJournal: fix posting messages longer than 4 Kb. diff --git a/ChangeLog.old b/ChangeLog.old new file mode 100644 index 0000000..ed5d7f2 --- /dev/null +++ b/ChangeLog.old @@ -0,0 +1,189 @@ +Version 0.9.4 +Change Jabber browser +MSN: Add hotmail notification +GPG: Add support passphrase +ICQ: Add packets flow control +ICQ: Fix send URL and contacts +ICQ: Fix send large messages +Redesign search window +Remove support miranda icons and smiles +Add JISP icons and smiles +Yahoo: Support new authorisation +Win32: Fix support icons with alpha channel +Add history exporting to text files +Add UV-Intesity, Moonphases to Weather Plugin +Fix to big value for temperature in Weather Plugin +Fix Loading History +Fix compile KDE3.4 + +Version 0.9.3 +Add LiveJournal plugin +Add Greek translation +Jabber: fix send rich-text messages +ICQ: Fix set birthday flag +Fix apply custom fonts +Fix communication-problem with AIM-Screennames > 13 chars +Fix not receive AuthGrant from some ICQ-users +Proxy: add support listen sockets for SOCKS4 and SOCKS5 +Add Yahoo! plugin +MSN: Fix remove contact +Add replace text plugin +Add option "Show/hide empty groups" +Add weather plugin +WIN32: Use WinInet for HTTP connection (NTLM-auth on proxy and proxy autoconfig) +Move plugins from prefix/share into prefix/lib +Fix acinclude for automake-1.8 +MSN: add HTTP polling +Jabber: add HTTP polling +OSD: add show message content +Jabber: add select resource for send + +Version 0.9.2 +Add styles plugin +Add customizable history styles +ICQ: Fix receive messages from icq2003b +Jabber: Add disco request for search agents +Add history size config +Add remote control plugin +Add spell checking +Jabber: Add jabber browser/disco +Fix bind socket for direct connection +Fix save history on win32 +Add option "Ignore this phrase" in context menu +Jabber: Fix send multiline message +Jabber: Add configure to jabber browser +Jabber: Add headline support +ICQ: Change check invisible method +ICQ: Remove check invisible +Add action plugin - for call external programs +Add zodiak plugin + +Version 0.9.1 +ICQ: Fix login +Add GPG plugin +Fix HTTPS proxy auth +Add Hungarian translation + +Version 0.9 +Rewrite code, make plugin-based structure +Add MSN & Jabber protocols +Add metacontact support +ICQ: Add typing notification +ICQ: Add support users picture +ICQ: Add check invisible +Add Miranda emoticons support +ICQ: Add support AIM buddies +ICQ: Fix send to occupied and dnd mode +MSN: Upgrade protocol to V8 +Add quick search in contact list +MacOS X compile +Add AIM protocol +Jabber: Add rich-text support +Jabber: Add typing notification +ICQ: File transfer and reverse direct connections support +MSN: File transfer support +ICQ: Fix protocol for bigendian +Jabber: File transfer support +Jabber: Picture in vCard support +Jabber: Send & receive contacts list +AIM: Send & receive contacts list +Add Portuguese translation + +Version 0.8.2 +Add Bulgarian translation +Add Hebrew translation +Add random chat +Add settings for groups +Add GKrellM2 plugin +Add French translation + +Version 0.8.1 +Add option for using simple/double click +Add background picture for mainwindow +Add option "disable all sounds" +Add change UIN +Add GNOME 2 docklet support +Add Polish translation +Add Dutch translation +Add change history sort order +Add synchronization with KAddressBook +Add Spanish translation +Redesign setup window +Add customize toolbars +Add Czech translation +Add copy messages from history to conversation +Fix works with accel +Fix receiving unicode messages from ICQ2Go! +Add external programms in template +Add network monitor +Fix rtf parser and generator for fix font size problem +Switch support HTTP and HTTPS proxy from call CONNECT method to using AIM-HTTP gate +Add saving split position in chat mode message window + +Version 0.8 +Add optional own history and user info in separate window +Add filter for history +Add alphabticaly sorting user list +Add secure channel dialog +Add recognize various clients +Fix dock window and keyboard shortcuts for QT-only version +Add loging change status +Add smiles popup +Add autoforward to cellular +Fix work protocol on bigendian +Change message window button to tolbar +Change configure for FreeBSD +Change font saving +Use KExtendedSocket on KDE +Add HTTPS proxy support +Make abstract interface for socket +Fix receive messages from ICQLite +Fix drag-and-drop files +Fix user encoding for encode/decode RTF +Add process escape for close user window +Fix set status for icq2go +Fix save options "Alert if Away" and "Require authorization" + +Version 0.7 +Sending of the messages to several users added +Add message forwarding +Add autosplit SMS messages +Add support keyboard shortcuts +Add On-Screen display notification about messages and user status +Work with a history is improved, the speed is increased, search and adjustments is added +Add message mode for user window +Is corrected batch file transfer, transfer of several files and recursive directoryes now works +Direct connection with ICQ-clones is corrected +Add support secure direct connection with SIM and Licq +Add support user encoding +Fix bug with receive bug server-side contact list +Add spam filter + +Version 0.6 +Proxy support added (SOCKS4, SOCKS5, HTTP) +Germany translation added +Add miranda icon themes support (see README for details) +Add save flag "Close on send" +Fix bug with KCmdLineArgs, SIM may crash on start +Fix bug on update timezone - SIM may crash after logon +Fix compile on gcc 3.1 + +Version 0.5 (25.06.2002) + +The chat support added. +List of attributes for search of the user is extended +And some others fixes: +- The processing of network mistakes is corrected, resulted in that that on the + broken off connection could work very long, thus loading strongly enough + processor (the very unpleasant mistake was - on windows could result in + crash of system) +- The effect "strange sound" is corrected, that is it was really started to + play twice +- Are corrected acinclude - now normally is going on KDE 2 and does not require + of a key - disable-kde if KDE is not present + +Version 0.4 (11.06.2002) + +Configure with iconv bug fixed (const keyword missed) +Owner info dialog bug fixed + diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake new file mode 100644 index 0000000..c4b74ed --- /dev/null +++ b/ConfigureChecks.cmake @@ -0,0 +1,34 @@ +INCLUDE(CheckIncludeFiles) +INCLUDE(CheckSymbolExists) +INCLUDE(CheckFunctionExists) +INCLUDE(CheckLibraryExists) +INCLUDE(CheckStructMember) + +# FIXME: Please check if this is really needed! +# HAVE_GCC_VISIBILITY missing + +# Header +CHECK_INCLUDE_FILES(Carbon/Carbon.h HAVE_CARBON_CARBON_H) # autoaway.cpp, do we support mac? +CHECK_INCLUDE_FILES(inttypes.h HAVE_INTTYPES_H) # simapi.h +CHECK_INCLUDE_FILES(stddef.h HAVE_STDDEF_H) # simapi.h +CHECK_INCLUDE_FILES(stdint.h HAVE_STDINT_H) # simapi.h +CHECK_INCLUDE_FILES(stdlib.h HAVE_STDLIB_H) # simapi.h +CHECK_INCLUDE_FILES(string.h HAVE_STRING_H) # _core/libintl.cpp +CHECK_INCLUDE_FILES(sys/stat.h HAVE_SYS_STAT_H) # gpg/gpg.cpp +CHECK_INCLUDE_FILES(sys/types.h HAVE_SYS_TYPES_H) # simapi.h +CHECK_INCLUDE_FILES(unistd.h HAVE_UNISTD_H) # simapi.h +CHECK_INCLUDE_FILES(xutility HAVE_XUTILITY) # simapi.h + +# Symbols +CHECK_SYMBOL_EXISTS(strcasecmp "strings.h" HAVE_STRCASECMP) # simapi.h, various + +# Functions +IF(NOT WIN32) # there is a chmod function on win32, but not usable the way we want... + CHECK_FUNCTION_EXISTS(chmod HAVE_CHMOD) # __homedir/homedir.cpp, gpg/gpg.cpp +ENDIF(NOT WIN32) +CHECK_FUNCTION_EXISTS(mmap HAVE_MMAP) # _core/libintl.cpp +CHECK_FUNCTION_EXISTS(munmap HAVE_MUNMAP) # _core/libintl.cpp +CHECK_FUNCTION_EXISTS(uname HAVE_UNAME) # sim/fetch.cpp + +# check for structure member +CHECK_STRUCT_MEMBER(tm tm_gmtoff time.h HAVE_TM_GMTOFF) # icqclient.cpp diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 0000000..001ec4d --- /dev/null +++ b/Doxyfile @@ -0,0 +1,1557 @@ +# Doxyfile 1.6.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# 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. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = sim-im + +# 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 = 0.9.6 + +# 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 = /home/todin/projects/sim-im/local/doxy + +# 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, 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). +# 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 +# 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" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# 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 +# 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 +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# 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 = /Users/dimitri/doxygen/mail/1.5.7/doxywizard/ + +# 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 = + +# 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 +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# 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 +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = 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 +# 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 +# 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. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# 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 = + +# 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 = NO + +# 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 + +# 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, C#, 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 + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# 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 +# 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 +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# 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 +# 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 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. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# 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. +# 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 +# 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 +# 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 +# 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. +# 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 +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = NO + +# 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 +# of that file. + +SHOW_INCLUDE_FILES = YES + +# 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 +# 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 +# declaration order. + +SORT_BRIEF_DOCS = NO + +# 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 +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# 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 +# 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 +# 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 +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +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 +# 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 +# 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 +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# 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 = + +# 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 +# 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 +# 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 +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# 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 +# documentation. + +WARN_NO_PARAMDOC = NO + +# 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 +# to stderr. + +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 +# with spaces. + +INPUT = /home/todin/projects/sim-im/branches/branch-playground + +# 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 *.f90 + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.d \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.php \ + *.php3 \ + *.inc \ + *.m \ + *.mm \ + *.dox \ + *.py \ + *.f90 \ + *.f \ + *.vhd \ + *.vhdl + +# 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 = YES + +# 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 = + +# 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 +# for example use the pattern */test/* + +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 + +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 \include command). + +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 +# blank all files are included. + +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. +# 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 command). + +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 +# ignored. + +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 = + +# 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 + +#--------------------------------------------------------------------------- +# 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. + +SOURCE_BROWSER = YES + +# 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 +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# 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 = NO + +# 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 = NO + +# 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 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 +# 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 +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# 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 +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# 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 = 5 + +# 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 = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# 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 +# 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 +# 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 +# standard header. + +HTML_HEADER = + +# 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 = + +# 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 = + +# 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 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 + +# 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 = 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 +# written to the html output directory. + +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 +# the HTML help compiler on the generated index.hhp. + +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 +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# 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 +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# 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 = + +# 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 = + +# 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]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# 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 + +# 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 + +# 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 + +# When the SEARCHENGINE tag is enable 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) or Qt help (GENERATE_QHP) +# there is already a search function so this one should typically +# be disabled. + +SEARCHENGINE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# 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 +# 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 +# invoked. If left blank `latex' will be used as the default command name. + +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 +# 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 +# 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 +# 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 +# packages that should be included in the LaTeX output. + +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 +# standard header. Notice: only use this tag if you know what you are doing! + +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 +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# 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 = YES + +# 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.) +# 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 +# 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 +# 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 +# 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. +# 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 +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config 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 +# 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 +# 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 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 +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# 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 +# the code including all documentation. + +GENERATE_XML = NO + +# 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 +# syntax of the XML files. + +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 +# syntax of the XML files. + +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 +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# 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 +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# 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 +# 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 +# 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 +# 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 +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# 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 +# 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 +# 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 +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# 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 preprocessor. + +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 +# be used. + +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 +# instead of the = operator. + +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. +# Use the PREDEFINED tag if you want to use a different macro definition. + +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 +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# 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 +# 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 +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# 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 = + +# 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 +# be listed. + +EXTERNAL_GROUPS = YES + +# 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 +#--------------------------------------------------------------------------- + +# 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 = NO + +# 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 = + +# 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 +# have no effect if this option is set to NO (the default) + +HAVE_DOT = YES + +# 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 + +# 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 +# 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 +# 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 +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# 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 +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# 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 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 = YES + +# 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 +# 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 +# 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 +# found. If left blank, it is assumed the dot tool can be found in the 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 +# \dotfile command). + +DOTFILE_DIRS = + +# 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 +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# 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) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# 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 +# the various graphs. + +DOT_CLEANUP = YES diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..2e005e9 --- /dev/null +++ b/INSTALL @@ -0,0 +1,167 @@ +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, a file +`config.cache' that saves the results of its tests to speed up +reconfiguring, and a file `config.log' containing compiler output +(useful mainly for debugging `configure'). + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If at some point `config.cache' +contains results you don't want to keep, you may remove or edit it. + + The file `configure.in' is used to create `configure' by a program +called `autoconf'. You only need `configure.in' if you want to change +it or regenerate `configure' using a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes a while. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Type `make install' to install the programs and any data files and + documentation. + + 4. You can remove the program binaries and object files from the + source code directory by typing `make clean'. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment. Using +a Bourne-compatible shell, you can do that on the command line like +this: + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + +Or on systems that have the `env' program, you can do it like this: + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' +variable, you have to compile the package for one architecture at a time +in the source code directory. After you have installed the package for +one architecture, use `make distclean' before reconfiguring for another +architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' can not figure out +automatically, but needs to determine by the type of host the package +will run on. Usually `configure' can figure that out, but if it prints +a message saying it can not guess the host type, give it the +`--host=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name with three fields: + CPU-COMPANY-SYSTEM + +See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the host type. + + If you are building compiler tools for cross-compiling, you can also +use the `--target=TYPE' option to select the type of system they will +produce code for and the `--build=TYPE' option to select the type of +system on which you are compiling the package. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Operation Controls +================== + + `configure' recognizes the following options to control how it +operates. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`configure' also accepts some other, not widely useful, options. + diff --git a/README b/README new file mode 100644 index 0000000..df7f85b --- /dev/null +++ b/README @@ -0,0 +1,46 @@ +SIM-IM - SIM Instant Messenger + +A simple ICQ client with v8 protocol support (2001) for X win system (requires QT, can be build for KDE). It also runs under MS Windows. + +Features: +- receiving and sending SMS +- server-side contact list +- receiving and the sending messages in RTF-format +- phone directory support (it is possible to specify an access to the owner phone number - public or friends only) +- file transfers +- chat +- user search +- non-ICQ contacts + +http://sim-im.org/ + +SIM supports icon themes from Miranda. +On page http://www.nortiq.com/miranda/index.php?action=display&cat=Icon +the wide range of various icon themes suffices. +Load the necessary files and unpack from them dll in the catalogue, +from which SIM takes icon libraries. + +On KDE: +${KDE_DIR}/share/apps/sim/icons +On Qt: +${PREFIX}/share/sim/icons +On MS Windows: +${install_dir}/icons + +Choose in the menu item "Setup". +In a window of adjustments choose a page "Themes" also choose a subject +in the list "Icons" + + +SOUND-Plugin with audiere +_________ +The Sound plugin can be build with mp3, ogg, flac...-support. +For this modified Sources of audiere is used. +Get them here: http://sim.gosign.de/audiere-1.9.4.rar +Additionally add + +#define USE_AUDIERE + +to the sound.h +You will need to include libaudiere.la and audiere.h to the makefiles for building sound. +audiere.so is the library needed at runtime. \ No newline at end of file diff --git a/README.SVN b/README.SVN new file mode 100644 index 0000000..b6037a2 --- /dev/null +++ b/README.SVN @@ -0,0 +1,16 @@ +Here a short overview how to compile the svn-version: +First you'll need actual automake and autoconf. Also you'll need different +packages like openssl, libxml, libxslt and more. +If you haven't installed some of them, hopefully ./configure will complain +about missing libs (If not, let us know ) + +Steps: +1. make -f admin/Makefile.common +2. ./configure +3. make +4. make install +5. Start SIM :-) + +If you want to help us, it is better you did "./configure --enable-debug" +so we get more informations and can fix bugs better. + diff --git a/TODO.CMake b/TODO.CMake new file mode 100644 index 0000000..ea6ba5c --- /dev/null +++ b/TODO.CMake @@ -0,0 +1,15 @@ +Todo: +- merge trunk changes (rev. 2471/2472) for cmake files to playground and test. + + +Needed: +- create/update sim.pot and *.po +- install mo - files +- 'make dist' +- correct directories for linux (already fine?) +- FindQt3 needs a small change for win32 (http://www.cmake.org/Bug/bug.php?op=show&bugid=3514&pos=1) + +Nice to have: +- pch support +- detect gcc visibility support (kde has a working check for) +- disallow in-source builds (I don't like in-source builds...) diff --git a/TODO.MingW b/TODO.MingW new file mode 100644 index 0000000..e3ddd8f --- /dev/null +++ b/TODO.MingW @@ -0,0 +1,5 @@ ++ compiling resources with wndres +- make install ++ installer project ++ compiling .po files +* remote plugin? diff --git a/admin/Doxyfile.am b/admin/Doxyfile.am new file mode 100644 index 0000000..7abbf32 --- /dev/null +++ b/admin/Doxyfile.am @@ -0,0 +1,102 @@ +## generate API documentation with doxygen +apidox-am-yes: + @if test \! -d "$(top_srcdir)/doc/common/" && test -z "$$DOXDATA" ; then \ + export DOXDATA=$(kde_libs_htmldir)/en/common ; \ + fi ; \ + abs_top_srcdir=`cd $(top_srcdir) && pwd` ;\ + test -d $(top_builddir)/apidocs || \ + ( cd $(top_builddir) && sh $$abs_top_srcdir/admin/doxygen.sh \ + --no-modulename --installdir=$(kde_libs_htmldir)/en \ + --no-recurse $(abs_top_srcdir) . ) ; \ + cd $(top_builddir) && sh $$abs_top_srcdir/admin/doxygen.sh \ + --recurse --no-modulename --installdir=$(kde_libs_htmldir)/en \ + $$abs_top_srcdir $(subdir) + +apidox-am-toplevel-yes: + @if test \! -d "$(top_srcdir)/doc/common/" && test -z "$$ADMIN" ; then \ + export DOXDATA=$(kde_libs_htmldir)/en/common ; \ + fi ; \ + abs_top_srcdir=`cd $(top_srcdir) && pwd` ;\ + cd $(top_builddir) && sh $$abs_top_srcdir/admin/doxygen.sh \ + --no-modulename --installdir=$(kde_libs_htmldir)/en \ + $$abs_top_srcdir + +## Don't generate API documentation without doxygen +apidox-am-no: + +apidox-am-toplevel-no: + + +apidox: + @if test "$(subdir)" != "."; then \ + $(MAKE) apidox-am-@KDE_HAS_DOXYGEN@ ;\ + else \ + $(MAKE) apidox-am-toplevel-@KDE_HAS_DOXYGEN@ ;\ + fi + + + +install-data-local: install-apidox + +## install API documentation +install-apidox: + @if test "$(subdir)" != "."; then \ + $(mkinstalldirs) $(DESTDIR)$(kde_htmldir)/en/$(PACKAGE)-apidocs/$(subdir)/html ; \ + if test -f $(top_builddir)/apidocs/$(subdir)/$(subdir).tag; then \ + echo $(INSTALL_DATA) $(top_builddir)/apidocs/$(subdir)/$(subdir).tag $(DESTDIR)$(kde_htmldir)/en/$(PACKAGE)-apidocs/$(subdir); \ + $(INSTALL_DATA) $(top_builddir)/apidocs/$(subdir)/$(subdir).tag $(DESTDIR)$(kde_htmldir)/en/$(PACKAGE)-apidocs/$(subdir); \ + fi; \ + if test -d $(top_builddir)/apidocs/$(subdir)/html; then \ + list=`ls $(top_builddir)/apidocs/$(subdir)/html`; \ + echo "installing $(top_builddir)/apidocs/$(subdir)/html" ;\ + for file in $$list; do \ + $(INSTALL_DATA) $(top_builddir)/apidocs/$(subdir)/html/$$file $(DESTDIR)$(kde_htmldir)/en/$(PACKAGE)-apidocs/$(subdir)/html; \ + done; \ + fi; \ + else\ + if test -d $(top_builddir)/apidocs; then \ + $(mkinstalldirs) $(DESTDIR)$(kde_htmldir)/en/$(PACKAGE)-apidocs ;\ + list=`cd $(top_builddir)/apidocs && ls -1`; \ + echo "installing $(top_builddir)/apidocs/$$file" ;\ + echo "target directory $(DESTDIR)$(kde_htmldir)/en/$(PACKAGE)-apidocs" ; \ + for file in $$list; do \ + if test -f $(top_builddir)/apidocs/$$file; then \ + $(INSTALL_DATA) $(top_builddir)/apidocs/$$file $(DESTDIR)$(kde_htmldir)/en/$(PACKAGE)-apidocs; \ + fi; \ + done ; fi; \ + fi + +uninstall-local: uninstall-apidox + +## uninstall API documentation +uninstall-apidox: + @if test "$(subdir)" != "."; then \ + if test -d $(DESTDIR)$(kde_htmldir)/en/$(PACKAGE)-apidocs/$(subdir); then \ + rm -rfv $(DESTDIR)$(kde_htmldir)/en/$(PACKAGE)-apidocs/$(subdir); \ + fi \ + else \ + if test -d $(DESTDIR)$(kde_htmldir)/en/$(PACKAGE)-apidocs; then \ + rm -rfv $(DESTDIR)$(kde_htmldir)/en/$(PACKAGE)-apidocs; \ + fi \ + fi + +install-apidox-recurse: install-apidox + @set fnord $(MAKEFLAGS); amf=$$2; if test -n '$(SUBDIRS)'; then \ + list='$(SUBDIRS)'; \ + for subdir in $$list; do \ + if grep '^include .*Doxyfile.am' $(srcdir)/$$subdir/Makefile.am > /dev/null ; then \ + echo "Installing apidox from $$subdir"; \ + if test "$$subdir" != "."; then \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) GENERATE_FLAG=no install-apidox-recurse) || exit 1; \ + fi ; fi ;\ + done; \ + fi + + + +.PHONY: apidox-am-yes apidox-am-no install-data-local install-apidox install-apidox uninstall-local uninstall-apidox uninstall-apidox apidox apidox-am-toplevel-no apidox-am-toplevel-yes + + +# Local Variables: +# mode: makefile +# End: diff --git a/admin/Doxyfile.global b/admin/Doxyfile.global new file mode 100755 index 0000000..4a06c7f --- /dev/null +++ b/admin/Doxyfile.global @@ -0,0 +1,192 @@ +OUTPUT_LANGUAGE = English +USE_WINDOWS_ENCODING = NO +BRIEF_MEMBER_DESC = NO +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = +ALWAYS_DETAILED_SEC = YES +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = NO +STRIP_FROM_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = YES +MULTILINE_CPP_IS_BRIEF = NO +INHERIT_DOCS = YES +DISTRIBUTE_GROUP_DOC = NO +TAB_SIZE = 4 +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +SUBGROUPING = YES +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = YES +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_BRIEF_DOCS = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TESTLIST = NO +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +QUIET = YES +WARNINGS = NO +WARN_IF_UNDOCUMENTED = NO +WARN_IF_DOC_ERROR = YES +WARN_FORMAT = +WARN_LOGFILE = +INPUT = +FILE_PATTERNS = *.h \ + *.cpp \ + *.cc \ + *.hpp \ + *.dox \ + *.c++ \ + *.cxx \ + *.h++ \ + *.hh +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = *.moc.* \ + moc* \ + *.all_cpp.* \ + *unload.* \ + */test/* \ + */tests/* \ + *_p.h +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_SOURCE_FILES = NO +SOURCE_BROWSER = YES +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +VERBATIM_HEADERS = YES +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 3 +HTML_OUTPUT = +HTML_FILE_EXTENSION = .html +HTML_HEADER = ../apidocs/common/header.html +HTML_FOOTER = ../apidocs/common/footer.html +HTML_STYLESHEET = ../apidocs/common/doxygen.css +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = YES +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +GENERATE_LATEX = NO +LATEX_OUTPUT = +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +GENERATE_RTF = NO +RTF_OUTPUT = +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +GENERATE_MAN = NO +MAN_OUTPUT = +MAN_EXTENSION = .kde3 +MAN_LINKS = YES +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = NO +GENERATE_AUTOGEN_DEF = NO +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +ENABLE_PREPROCESSING = YES +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = QT_VERSION=320 \ + __cplusplus \ + Q_WS_X11 +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = NO +PERL_PATH = +CLASS_DIAGRAMS = YES +HIDE_UNDOC_RELATIONS = NO +HAVE_DOT = NO +UML_LOOK = NO +TEMPLATE_RELATIONS = YES +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +MAX_DOT_GRAPH_WIDTH = 800 +MAX_DOT_GRAPH_HEIGHT = 1024 +MAX_DOT_GRAPH_DEPTH = 0 +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +SEARCHENGINE = NO + +### KDE Settings +ALIASES = \ + "intern=\parInternal use only." \ + "reimp=\parReimplemented from superclass." \ + "obsolete=@deprecated" \ + "feature=\xrefitem features \"Feature(s)\" \"Features\"" \ + "maintainer=\xrefitem maintainers \"Maintainer(s)\" \"Maintainers\"" \ + "unmaintained=\xrefitem unmaintained \"Unmaintained\" \"Unmaintained\"" \ + "requirement=\xrefitem requirements \"Requirement(s)\" \"Requirements\"" \ + "faq=\xrefitem FAQ \"F.A.Q.\" \"F.A.Q.\"" \ + "authors=\xrefitem authors \"Author(s)\" \"Authors\"" \ + "FIXME=\xrefitem fixme \"Fixme\" \"Fixme\"" + +HTML_ALIGN_MEMBERS = YES +REFERENCED_BY_RELATION = NO +REFERENCES_RELATION = NO +VERBATIM_HEADERS = NO +GENERATE_HTML = YES +SOURCE_BROWSER = YES +GENERATE_AUTOGEN_DEF = NO +DETAILS_AT_TOP = YES +SORT_MEMBER_DOCS = YES +GENERATE_TODOLIST = YES +IGNORE_PREFIX = K +GENERATE_HTML = YES +CLASS_GRAPH = YES +COLLABORATION_GRAPH = NO + + +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = YES + diff --git a/admin/acinclude.m4.in b/admin/acinclude.m4.in new file mode 100644 index 0000000..46848d0 --- /dev/null +++ b/admin/acinclude.m4.in @@ -0,0 +1,6040 @@ +## -*- autoconf -*- + +dnl This file is part of the KDE libraries/packages +dnl Copyright (C) 1997 Janos Farkas (chexum@shadow.banki.hu) +dnl (C) 1997,98,99 Stephan Kulow (coolo@kde.org) + +dnl This file is free software; you can redistribute it and/or +dnl modify it under the terms of the GNU Library General Public +dnl License as published by the Free Software Foundation; either +dnl version 2 of the License, or (at your option) any later version. + +dnl This library is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl Library General Public License for more details. + +dnl You should have received a copy of the GNU Library General Public License +dnl along with this library; see the file COPYING.LIB. If not, write to +dnl the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +dnl Boston, MA 02110-1301, USA. + +dnl IMPORTANT NOTE: +dnl Please do not modify this file unless you expect your modifications to be +dnl carried into every other module in the repository. +dnl +dnl Single-module modifications are best placed in configure.in for kdelibs +dnl and kdebase or configure.in.in if present. + +# KDE_PATH_X_DIRECT +dnl Internal subroutine of AC_PATH_X. +dnl Set ac_x_includes and/or ac_x_libraries. +AC_DEFUN([KDE_PATH_X_DIRECT], +[ +AC_REQUIRE([KDE_CHECK_LIB64]) + +if test "$ac_x_includes" = NO; then + # Guess where to find include files, by looking for this one X11 .h file. + test -z "$x_direct_test_include" && x_direct_test_include=X11/Intrinsic.h + + # First, try using that file with no special directory specified. +AC_TRY_CPP([#include <$x_direct_test_include>], +[# We can compile using X headers with no special include directory. +ac_x_includes=], +[# Look for the header file in a standard set of common directories. +# Check X11 before X11Rn because it is often a symlink to the current release. + for ac_dir in \ + /usr/X11/include \ + /usr/X11R6/include \ + /usr/X11R5/include \ + /usr/X11R4/include \ + \ + /usr/include/X11 \ + /usr/include/X11R6 \ + /usr/include/X11R5 \ + /usr/include/X11R4 \ + \ + /usr/local/X11/include \ + /usr/local/X11R6/include \ + /usr/local/X11R5/include \ + /usr/local/X11R4/include \ + \ + /usr/local/include/X11 \ + /usr/local/include/X11R6 \ + /usr/local/include/X11R5 \ + /usr/local/include/X11R4 \ + \ + /usr/X386/include \ + /usr/x386/include \ + /usr/XFree86/include/X11 \ + \ + /usr/include \ + /usr/local/include \ + /usr/unsupported/include \ + /usr/athena/include \ + /usr/local/x11r5/include \ + /usr/lpp/Xamples/include \ + \ + /usr/openwin/include \ + /usr/openwin/share/include \ + ; \ + do + if test -r "$ac_dir/$x_direct_test_include"; then + ac_x_includes=$ac_dir + break + fi + done]) +fi # $ac_x_includes = NO + +if test "$ac_x_libraries" = NO; then + # Check for the libraries. + + test -z "$x_direct_test_library" && x_direct_test_library=Xt + test -z "$x_direct_test_function" && x_direct_test_function=XtMalloc + + # See if we find them without any special options. + # Don't add to $LIBS permanently. + ac_save_LIBS="$LIBS" + LIBS="-l$x_direct_test_library $LIBS" +AC_TRY_LINK([#include ], [${x_direct_test_function}(1)], +[LIBS="$ac_save_LIBS" +# We can link X programs with no special library path. +ac_x_libraries=], +[LIBS="$ac_save_LIBS" +# First see if replacing the include by lib works. +# Check X11 before X11Rn because it is often a symlink to the current release. +for ac_dir in `echo "$ac_x_includes" | sed s/include/lib${kdelibsuff}/` \ + /usr/X11/lib${kdelibsuff} \ + /usr/X11R6/lib${kdelibsuff} \ + /usr/X11R5/lib${kdelibsuff} \ + /usr/X11R4/lib${kdelibsuff} \ + \ + /usr/lib${kdelibsuff}/X11 \ + /usr/lib${kdelibsuff}/X11R6 \ + /usr/lib${kdelibsuff}/X11R5 \ + /usr/lib${kdelibsuff}/X11R4 \ + \ + /usr/local/X11/lib${kdelibsuff} \ + /usr/local/X11R6/lib${kdelibsuff} \ + /usr/local/X11R5/lib${kdelibsuff} \ + /usr/local/X11R4/lib${kdelibsuff} \ + \ + /usr/local/lib${kdelibsuff}/X11 \ + /usr/local/lib${kdelibsuff}/X11R6 \ + /usr/local/lib${kdelibsuff}/X11R5 \ + /usr/local/lib${kdelibsuff}/X11R4 \ + \ + /usr/X386/lib${kdelibsuff} \ + /usr/x386/lib${kdelibsuff} \ + /usr/XFree86/lib${kdelibsuff}/X11 \ + \ + /usr/lib${kdelibsuff} \ + /usr/local/lib${kdelibsuff} \ + /usr/unsupported/lib${kdelibsuff} \ + /usr/athena/lib${kdelibsuff} \ + /usr/local/x11r5/lib${kdelibsuff} \ + /usr/lpp/Xamples/lib${kdelibsuff} \ + /lib/usr/lib${kdelibsuff}/X11 \ + \ + /usr/openwin/lib${kdelibsuff} \ + /usr/openwin/share/lib${kdelibsuff} \ + ; \ +do +dnl Don't even attempt the hair of trying to link an X program! + for ac_extension in a so sl; do + if test -r $ac_dir/lib${x_direct_test_library}.$ac_extension; then + ac_x_libraries=$ac_dir + break 2 + fi + done +done]) +fi # $ac_x_libraries = NO +]) + + +dnl ------------------------------------------------------------------------ +dnl Find a file (or one of more files in a list of dirs) +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([AC_FIND_FILE], +[ +$3=NO +for i in $2; +do + for j in $1; + do + echo "configure: __oline__: $i/$j" >&AC_FD_CC + if test -r "$i/$j"; then + echo "taking that" >&AC_FD_CC + $3=$i + break 2 + fi + done +done +]) + +dnl KDE_FIND_PATH(program-name, variable-name, list-of-dirs, +dnl if-not-found, test-parameter, prepend-path) +dnl +dnl Look for program-name in list-of-dirs+$PATH. +dnl If prepend-path is set, look in $PATH+list-of-dirs instead. +dnl If found, $variable-name is set. If not, if-not-found is evaluated. +dnl test-parameter: if set, the program is executed with this arg, +dnl and only a successful exit code is required. +AC_DEFUN([KDE_FIND_PATH], +[ + AC_MSG_CHECKING([for $1]) + if test -n "$$2"; then + kde_cv_path="$$2"; + else + kde_cache=`echo $1 | sed 'y%./+-%__p_%'` + + AC_CACHE_VAL(kde_cv_path_$kde_cache, + [ + kde_cv_path="NONE" + kde_save_IFS=$IFS + IFS=':' + dirs="" + for dir in $PATH; do + dirs="$dirs $dir" + done + if test -z "$6"; then dnl Append dirs in PATH (default) + dirs="$3 $dirs" + else dnl Prepend dirs in PATH (if 6th arg is set) + dirs="$dirs $3" + fi + IFS=$kde_save_IFS + + for dir in $dirs; do + if test -x "$dir/$1"; then + if test -n "$5" + then + evalstr="$dir/$1 $5 2>&1 " + if eval $evalstr; then + kde_cv_path="$dir/$1" + break + fi + else + kde_cv_path="$dir/$1" + break + fi + fi + done + + eval "kde_cv_path_$kde_cache=$kde_cv_path" + + ]) + + eval "kde_cv_path=\"`echo '$kde_cv_path_'$kde_cache`\"" + + fi + + if test -z "$kde_cv_path" || test "$kde_cv_path" = NONE; then + AC_MSG_RESULT(not found) + $4 + else + AC_MSG_RESULT($kde_cv_path) + $2=$kde_cv_path + + fi +]) + +AC_DEFUN([KDE_MOC_ERROR_MESSAGE], +[ + AC_MSG_ERROR([No Qt meta object compiler (moc) found! +Please check whether you installed Qt correctly. +You need to have a running moc binary. +configure tried to run $ac_cv_path_moc and the test didn't +succeed. If configure shouldn't have tried this one, set +the environment variable MOC to the right one before running +configure. +]) +]) + +AC_DEFUN([KDE_UIC_ERROR_MESSAGE], +[ + AC_MSG_WARN([No Qt ui compiler (uic) found! +Please check whether you installed Qt correctly. +You need to have a running uic binary. +configure tried to run $ac_cv_path_uic and the test didn't +succeed. If configure shouldn't have tried this one, set +the environment variable UIC to the right one before running +configure. +]) +]) + + +AC_DEFUN([KDE_CHECK_UIC_FLAG], +[ + AC_MSG_CHECKING([whether uic supports -$1 ]) + kde_cache=`echo $1 | sed 'y% .=/+-%____p_%'` + AC_CACHE_VAL(kde_cv_prog_uic_$kde_cache, + [ + cat >conftest.ui < +EOT + ac_uic_testrun="$UIC_PATH -$1 $2 conftest.ui >/dev/null" + if AC_TRY_EVAL(ac_uic_testrun); then + eval "kde_cv_prog_uic_$kde_cache=yes" + else + eval "kde_cv_prog_uic_$kde_cache=no" + fi + rm -f conftest* + ]) + + if eval "test \"`echo '$kde_cv_prog_uic_'$kde_cache`\" = yes"; then + AC_MSG_RESULT([yes]) + : + $3 + else + AC_MSG_RESULT([no]) + : + $4 + fi +]) + + +dnl ------------------------------------------------------------------------ +dnl Find the meta object compiler and the ui compiler in the PATH, +dnl in $QTDIR/bin, and some more usual places +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([AC_PATH_QT_MOC_UIC], +[ + AC_REQUIRE([KDE_CHECK_PERL]) + qt_bindirs="" + for dir in $kde_qt_dirs; do + qt_bindirs="$qt_bindirs $dir/bin $dir/src/moc" + done + qt_bindirs="$qt_bindirs /usr/bin /usr/X11R6/bin /usr/local/qt/bin" + if test ! "$ac_qt_bindir" = "NO"; then + qt_bindirs="$ac_qt_bindir $qt_bindirs" + fi + + KDE_FIND_PATH(moc, MOC, [$qt_bindirs], [KDE_MOC_ERROR_MESSAGE]) + if test -z "$UIC_NOT_NEEDED"; then + KDE_FIND_PATH(uic, UIC_PATH, [$qt_bindirs], [UIC_PATH=""]) + if test -z "$UIC_PATH" ; then + KDE_UIC_ERROR_MESSAGE + exit 1 + else + UIC=$UIC_PATH + + if test $kde_qtver = 3; then + KDE_CHECK_UIC_FLAG(L,[/nonexistent],ac_uic_supports_libpath=yes,ac_uic_supports_libpath=no) + KDE_CHECK_UIC_FLAG(nounload,,ac_uic_supports_nounload=yes,ac_uic_supports_nounload=no) + + if test x$ac_uic_supports_libpath = xyes; then + UIC="$UIC -L \$(kde_widgetdir)" + fi + if test x$ac_uic_supports_nounload = xyes; then + UIC="$UIC -nounload" + fi + fi + fi + else + UIC="echo uic not available: " + fi + + AC_SUBST(MOC) + AC_SUBST(UIC) + + UIC_TR="i18n" + if test "$use_kde" = "yes"; then + if test "$kde_qtver" = "3"; then + UIC_TR="tr2i18n" + fi + fi + + AC_SUBST(UIC_TR) +]) + +AC_DEFUN([KDE_1_CHECK_PATHS], +[ + KDE_1_CHECK_PATH_HEADERS + + KDE_TEST_RPATH= + + if test -n "$USE_RPATH"; then + + if test -n "$kde_libraries"; then + KDE_TEST_RPATH="-R $kde_libraries" + fi + + if test -n "$qt_libraries"; then + KDE_TEST_RPATH="$KDE_TEST_RPATH -R $qt_libraries" + fi + + if test -n "$x_libraries"; then + KDE_TEST_RPATH="$KDE_TEST_RPATH -R $x_libraries" + fi + + KDE_TEST_RPATH="$KDE_TEST_RPATH $KDE_EXTRA_RPATH" + fi + +AC_MSG_CHECKING([for KDE libraries installed]) +ac_link='$LIBTOOL_SHELL --silent --mode=link ${CXX-g++} -o conftest $CXXFLAGS $all_includes $CPPFLAGS $LDFLAGS $all_libraries conftest.$ac_ext $LIBS -lkdecore $LIBQT $KDE_TEST_RPATH 1>&5' + +if AC_TRY_EVAL(ac_link) && test -s conftest; then + AC_MSG_RESULT(yes) +else + AC_MSG_ERROR([your system fails at linking a small KDE application! +Check, if your compiler is installed correctly and if you have used the +same compiler to compile Qt and kdelibs as you did use now. +For more details about this problem, look at the end of config.log.]) +fi + +if eval `KDEDIR= ./conftest 2>&5`; then + kde_result=done +else + kde_result=problems +fi + +KDEDIR= ./conftest 2> /dev/null >&5 # make an echo for config.log +kde_have_all_paths=yes + +KDE_SET_PATHS($kde_result) + +]) + +AC_DEFUN([KDE_SET_PATHS], +[ + kde_cv_all_paths="kde_have_all_paths=\"yes\" \ + kde_htmldir=\"$kde_htmldir\" \ + kde_appsdir=\"$kde_appsdir\" \ + kde_icondir=\"$kde_icondir\" \ + kde_sounddir=\"$kde_sounddir\" \ + kde_datadir=\"$kde_datadir\" \ + kde_locale=\"$kde_locale\" \ + kde_cgidir=\"$kde_cgidir\" \ + kde_confdir=\"$kde_confdir\" \ + kde_kcfgdir=\"$kde_kcfgdir\" \ + kde_mimedir=\"$kde_mimedir\" \ + kde_toolbardir=\"$kde_toolbardir\" \ + kde_wallpaperdir=\"$kde_wallpaperdir\" \ + kde_templatesdir=\"$kde_templatesdir\" \ + kde_bindir=\"$kde_bindir\" \ + kde_servicesdir=\"$kde_servicesdir\" \ + kde_servicetypesdir=\"$kde_servicetypesdir\" \ + kde_moduledir=\"$kde_moduledir\" \ + kde_styledir=\"$kde_styledir\" \ + kde_widgetdir=\"$kde_widgetdir\" \ + xdg_appsdir=\"$xdg_appsdir\" \ + xdg_menudir=\"$xdg_menudir\" \ + xdg_directorydir=\"$xdg_directorydir\" \ + kde_result=$1" +]) + +AC_DEFUN([KDE_SET_DEFAULT_PATHS], +[ +if test "$1" = "default"; then + + if test -z "$kde_htmldir"; then + kde_htmldir='${datadir}/doc/HTML' + fi + if test -z "$kde_appsdir"; then + kde_appsdir='${datadir}/applnk' + fi + if test -z "$kde_icondir"; then + kde_icondir='${datadir}/icons' + fi + if test -z "$kde_sounddir"; then + kde_sounddir='${datadir}/sounds' + fi + if test -z "$kde_datadir"; then + kde_datadir='${datadir}/apps' + fi + if test -z "$kde_locale"; then + kde_locale='${datadir}/locale' + fi + if test -z "$kde_cgidir"; then + kde_cgidir='${exec_prefix}/cgi-bin' + fi + if test -z "$kde_confdir"; then + kde_confdir='${datadir}/config' + fi + if test -z "$kde_kcfgdir"; then + kde_kcfgdir='${datadir}/config.kcfg' + fi + if test -z "$kde_mimedir"; then + kde_mimedir='${datadir}/mimelnk' + fi + if test -z "$kde_toolbardir"; then + kde_toolbardir='${datadir}/toolbar' + fi + if test -z "$kde_wallpaperdir"; then + kde_wallpaperdir='${datadir}/wallpapers' + fi + if test -z "$kde_templatesdir"; then + kde_templatesdir='${datadir}/templates' + fi + if test -z "$kde_bindir"; then + kde_bindir='\${exec_prefix}/bin' + fi + if test -z "$kde_servicesdir"; then + kde_servicesdir='${datadir}/services' + fi + if test -z "$kde_servicetypesdir"; then + kde_servicetypesdir='${datadir}/servicetypes' + fi + if test -z "$kde_moduledir"; then + if test "$kde_qtver" = "2"; then + kde_moduledir='${libdir}/kde2' + else + kde_moduledir='${libdir}/kde3' + fi + fi + if test -z "$kde_styledir"; then + kde_styledir='${libdir}/kde3/plugins/styles' + fi + if test -z "$kde_widgetdir"; then + kde_widgetdir='${libdir}/kde3/plugins/designer' + fi + if test -z "$xdg_appsdir"; then + xdg_appsdir='${datadir}/applications/kde' + fi + if test -z "$xdg_menudir"; then + xdg_menudir='${sysconfdir}/xdg/menus' + fi + if test -z "$xdg_directorydir"; then + xdg_directorydir='${datadir}/desktop-directories' + fi + + KDE_SET_PATHS(defaults) + +else + + if test $kde_qtver = 1; then + AC_MSG_RESULT([compiling]) + KDE_1_CHECK_PATHS + else + AC_MSG_ERROR([path checking not yet supported for KDE 2]) + fi + +fi +]) + +AC_DEFUN([KDE_CHECK_PATHS_FOR_COMPLETENESS], +[ if test -z "$kde_htmldir" || test -z "$kde_appsdir" || + test -z "$kde_icondir" || test -z "$kde_sounddir" || + test -z "$kde_datadir" || test -z "$kde_locale" || + test -z "$kde_cgidir" || test -z "$kde_confdir" || + test -z "$kde_kcfgdir" || + test -z "$kde_mimedir" || test -z "$kde_toolbardir" || + test -z "$kde_wallpaperdir" || test -z "$kde_templatesdir" || + test -z "$kde_bindir" || test -z "$kde_servicesdir" || + test -z "$kde_servicetypesdir" || test -z "$kde_moduledir" || + test -z "$kde_styledir" || test -z "kde_widgetdir" || + test -z "$xdg_appsdir" || test -z "$xdg_menudir" || test -z "$xdg_directorydir" || + test "x$kde_have_all_paths" != "xyes"; then + kde_have_all_paths=no + fi +]) + +AC_DEFUN([KDE_MISSING_PROG_ERROR], +[ + AC_MSG_ERROR([The important program $1 was not found! +Please check whether you installed KDE correctly. +]) +]) + +AC_DEFUN([KDE_MISSING_ARTS_ERROR], +[ + AC_MSG_ERROR([The important program $1 was not found! +Please check whether you installed aRts correctly or use +--without-arts to compile without aRts support (this will remove functionality). +]) +]) + +AC_DEFUN([KDE_SET_DEFAULT_BINDIRS], +[ + kde_default_bindirs="/usr/bin /usr/local/bin /opt/local/bin /usr/X11R6/bin /opt/kde/bin /opt/kde3/bin /usr/kde/bin /usr/local/kde/bin" + test -n "$KDEDIR" && kde_default_bindirs="$KDEDIR/bin $kde_default_bindirs" + if test -n "$KDEDIRS"; then + kde_save_IFS=$IFS + IFS=: + for dir in $KDEDIRS; do + kde_default_bindirs="$dir/bin $kde_default_bindirs " + done + IFS=$kde_save_IFS + fi +]) + +AC_DEFUN([KDE_SUBST_PROGRAMS], +[ + AC_ARG_WITH(arts, + AC_HELP_STRING([--without-arts],[build without aRts [default=no]]), + [build_arts=$withval], + [build_arts=yes] + ) + AM_CONDITIONAL(include_ARTS, test "$build_arts" '!=' "no") + if test "$build_arts" = "no"; then + AC_DEFINE(WITHOUT_ARTS, 1, [Defined if compiling without arts]) + fi + + KDE_SET_DEFAULT_BINDIRS + kde_default_bindirs="$exec_prefix/bin $prefix/bin $kde_libs_prefix/bin $kde_default_bindirs" + KDE_FIND_PATH(dcopidl, DCOPIDL, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(dcopidl)]) + KDE_FIND_PATH(dcopidl2cpp, DCOPIDL2CPP, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(dcopidl2cpp)]) + if test "$build_arts" '!=' "no"; then + KDE_FIND_PATH(mcopidl, MCOPIDL, [$kde_default_bindirs], [KDE_MISSING_ARTS_ERROR(mcopidl)]) + KDE_FIND_PATH(artsc-config, ARTSCCONFIG, [$kde_default_bindirs], [KDE_MISSING_ARTS_ERROR(artsc-config)]) + fi + KDE_FIND_PATH(meinproc, MEINPROC, [$kde_default_bindirs]) + + kde32ornewer=1 + kde33ornewer=1 + if test -n "$kde_qtver" && test "$kde_qtver" -lt 3; then + kde32ornewer= + kde33ornewer= + else + if test "$kde_qtver" = "3"; then + if test "$kde_qtsubver" -le 1; then + kde32ornewer= + fi + if test "$kde_qtsubver" -le 2; then + kde33ornewer= + fi + if test "$KDECONFIG" != "compiled"; then + if test `$KDECONFIG --version | grep KDE | sed 's/KDE: \(...\).*/\1/'` = 3.2; then + kde33ornewer= + fi + fi + fi + fi + + if test -n "$kde32ornewer"; then + KDE_FIND_PATH(kconfig_compiler, KCONFIG_COMPILER, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(kconfig_compiler)]) + KDE_FIND_PATH(dcopidlng, DCOPIDLNG, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(dcopidlng)]) + fi + if test -n "$kde33ornewer"; then + KDE_FIND_PATH(makekdewidgets, MAKEKDEWIDGETS, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(makekdewidgets)]) + AC_SUBST(MAKEKDEWIDGETS) + fi + KDE_FIND_PATH(xmllint, XMLLINT, [${prefix}/bin ${exec_prefix}/bin], [XMLLINT=""]) + + if test -n "$MEINPROC" -a "$MEINPROC" != "compiled"; then + kde_sharedirs="/usr/share/kde /usr/local/share /usr/share /opt/kde3/share /opt/kde/share $prefix/share" + test -n "$KDEDIR" && kde_sharedirs="$KDEDIR/share $kde_sharedirs" + AC_FIND_FILE(apps/ksgmltools2/customization/kde-chunk.xsl, $kde_sharedirs, KDE_XSL_STYLESHEET) + if test "$KDE_XSL_STYLESHEET" = "NO"; then + KDE_XSL_STYLESHEET="" + else + KDE_XSL_STYLESHEET="$KDE_XSL_STYLESHEET/apps/ksgmltools2/customization/kde-chunk.xsl" + fi + fi + + DCOP_DEPENDENCIES='$(DCOPIDL)' + if test -n "$kde32ornewer"; then + KCFG_DEPENDENCIES='$(KCONFIG_COMPILER)' + DCOP_DEPENDENCIES='$(DCOPIDL) $(DCOPIDLNG)' + AC_SUBST(KCONFIG_COMPILER) + AC_SUBST(KCFG_DEPENDENCIES) + AC_SUBST(DCOPIDLNG) + fi + AC_SUBST(DCOPIDL) + AC_SUBST(DCOPIDL2CPP) + AC_SUBST(DCOP_DEPENDENCIES) + AC_SUBST(MCOPIDL) + AC_SUBST(ARTSCCONFIG) + AC_SUBST(MEINPROC) + AC_SUBST(KDE_XSL_STYLESHEET) + AC_SUBST(XMLLINT) +])dnl + +AC_DEFUN([AC_CREATE_KFSSTND], +[ +AC_REQUIRE([AC_CHECK_RPATH]) + +AC_MSG_CHECKING([for KDE paths]) +kde_result="" +kde_cached_paths=yes +AC_CACHE_VAL(kde_cv_all_paths, +[ + KDE_SET_DEFAULT_PATHS($1) + kde_cached_paths=no +]) +eval "$kde_cv_all_paths" +KDE_CHECK_PATHS_FOR_COMPLETENESS +if test "$kde_have_all_paths" = "no" && test "$kde_cached_paths" = "yes"; then + # wrong values were cached, may be, we can set better ones + kde_result= + kde_htmldir= kde_appsdir= kde_icondir= kde_sounddir= + kde_datadir= kde_locale= kde_cgidir= kde_confdir= kde_kcfgdir= + kde_mimedir= kde_toolbardir= kde_wallpaperdir= kde_templatesdir= + kde_bindir= kde_servicesdir= kde_servicetypesdir= kde_moduledir= + kde_have_all_paths= + kde_styledir= + kde_widgetdir= + xdg_appsdir = xdg_menudir= xdg_directorydir= + KDE_SET_DEFAULT_PATHS($1) + eval "$kde_cv_all_paths" + KDE_CHECK_PATHS_FOR_COMPLETENESS + kde_result="$kde_result (cache overridden)" +fi +if test "$kde_have_all_paths" = "no"; then + AC_MSG_ERROR([configure could not run a little KDE program to test the environment. +Since it had compiled and linked before, it must be a strange problem on your system. +Look at config.log for details. If you are not able to fix this, look at +http://www.kde.org/faq/installation.html or any www.kde.org mirror. +(If you're using an egcs version on Linux, you may update binutils!) +]) +else + rm -f conftest* + AC_MSG_RESULT($kde_result) +fi + +bindir=$kde_bindir + +KDE_SUBST_PROGRAMS + +]) + +AC_DEFUN([AC_SUBST_KFSSTND], +[ +AC_SUBST(kde_htmldir) +AC_SUBST(kde_appsdir) +AC_SUBST(kde_icondir) +AC_SUBST(kde_sounddir) +AC_SUBST(kde_datadir) +AC_SUBST(kde_locale) +AC_SUBST(kde_confdir) +AC_SUBST(kde_kcfgdir) +AC_SUBST(kde_mimedir) +AC_SUBST(kde_wallpaperdir) +AC_SUBST(kde_bindir) +dnl X Desktop Group standards +AC_SUBST(xdg_appsdir) +AC_SUBST(xdg_menudir) +AC_SUBST(xdg_directorydir) +dnl for KDE 2 +AC_SUBST(kde_templatesdir) +AC_SUBST(kde_servicesdir) +AC_SUBST(kde_servicetypesdir) +AC_SUBST(kde_moduledir) +AC_SUBST(kdeinitdir, '$(kde_moduledir)') +AC_SUBST(kde_styledir) +AC_SUBST(kde_widgetdir) +if test "$kde_qtver" = 1; then + kde_minidir="$kde_icondir/mini" +else +# for KDE 1 - this breaks KDE2 apps using minidir, but +# that's the plan ;-/ + kde_minidir="/dev/null" +fi +dnl AC_SUBST(kde_minidir) +dnl AC_SUBST(kde_cgidir) +dnl AC_SUBST(kde_toolbardir) +]) + +AC_DEFUN([KDE_MISC_TESTS], +[ + dnl Checks for libraries. + AC_CHECK_LIB(util, main, [LIBUTIL="-lutil"]) dnl for *BSD + AC_SUBST(LIBUTIL) + AC_CHECK_LIB(compat, main, [LIBCOMPAT="-lcompat"]) dnl for *BSD + AC_SUBST(LIBCOMPAT) + kde_have_crypt= + AC_CHECK_LIB(crypt, crypt, [LIBCRYPT="-lcrypt"; kde_have_crypt=yes], + AC_CHECK_LIB(c, crypt, [kde_have_crypt=yes], [ + AC_MSG_WARN([you have no crypt in either libcrypt or libc. +You should install libcrypt from another source or configure with PAM +support]) + kde_have_crypt=no + ])) + AC_SUBST(LIBCRYPT) + if test $kde_have_crypt = yes; then + AC_DEFINE_UNQUOTED(HAVE_CRYPT, 1, [Defines if your system has the crypt function]) + fi + AC_CHECK_SOCKLEN_T + AC_CHECK_LIB(dnet, dnet_ntoa, [X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet"]) + if test $ac_cv_lib_dnet_dnet_ntoa = no; then + AC_CHECK_LIB(dnet_stub, dnet_ntoa, + [X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet_stub"]) + fi + AC_CHECK_FUNC(inet_ntoa) + if test $ac_cv_func_inet_ntoa = no; then + AC_CHECK_LIB(nsl, inet_ntoa, X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl") + fi + AC_CHECK_FUNC(connect) + if test $ac_cv_func_connect = no; then + AC_CHECK_LIB(socket, connect, X_EXTRA_LIBS="-lsocket $X_EXTRA_LIBS", , + $X_EXTRA_LIBS) + fi + + AC_CHECK_FUNC(remove) + if test $ac_cv_func_remove = no; then + AC_CHECK_LIB(posix, remove, X_EXTRA_LIBS="$X_EXTRA_LIBS -lposix") + fi + + # BSDI BSD/OS 2.1 needs -lipc for XOpenDisplay. + AC_CHECK_FUNC(shmat, , + AC_CHECK_LIB(ipc, shmat, X_EXTRA_LIBS="$X_EXTRA_LIBS -lipc")) + + # more headers that need to be explicitly included on darwin + AC_CHECK_HEADERS(sys/types.h stdint.h) + + # sys/bitypes.h is needed for uint32_t and friends on Tru64 + AC_CHECK_HEADERS(sys/bitypes.h) + + # darwin requires a poll emulation library + AC_CHECK_LIB(poll, poll, LIB_POLL="-lpoll") + + # for some image handling on Mac OS X + AC_CHECK_HEADERS(Carbon/Carbon.h) + + # CoreAudio framework + AC_CHECK_HEADER(CoreAudio/CoreAudio.h, [ + AC_DEFINE(HAVE_COREAUDIO, 1, [Define if you have the CoreAudio API]) + FRAMEWORK_COREAUDIO="-Wl,-framework,CoreAudio" + ]) + + AC_CHECK_RES_INIT + AC_SUBST(LIB_POLL) + AC_SUBST(FRAMEWORK_COREAUDIO) + LIBSOCKET="$X_EXTRA_LIBS" + AC_SUBST(LIBSOCKET) + AC_SUBST(X_EXTRA_LIBS) + AC_CHECK_LIB(ucb, killpg, [LIBUCB="-lucb"]) dnl for Solaris2.4 + AC_SUBST(LIBUCB) + + case $host in dnl this *is* LynxOS specific + *-*-lynxos* ) + AC_MSG_CHECKING([LynxOS header file wrappers]) + [CFLAGS="$CFLAGS -D__NO_INCLUDE_WARN__"] + AC_MSG_RESULT(disabled) + AC_CHECK_LIB(bsd, gethostbyname, [LIBSOCKET="-lbsd"]) dnl for LynxOS + ;; + esac + + KDE_CHECK_TYPES + KDE_CHECK_LIBDL + KDE_CHECK_STRLCPY + KDE_CHECK_PIE_SUPPORT + +# darwin needs this to initialize the environment +AC_CHECK_HEADERS(crt_externs.h) +AC_CHECK_FUNC(_NSGetEnviron, [AC_DEFINE(HAVE_NSGETENVIRON, 1, [Define if your system needs _NSGetEnviron to set up the environment])]) + +AH_VERBATIM(_DARWIN_ENVIRON, +[ +#if defined(HAVE_NSGETENVIRON) && defined(HAVE_CRT_EXTERNS_H) +# include +# include +# define environ (*_NSGetEnviron()) +#endif +]) + +AH_VERBATIM(_AIX_STRINGS_H_BZERO, +[ +/* + * AIX defines FD_SET in terms of bzero, but fails to include + * that defines bzero. + */ + +#if defined(_AIX) +#include +#endif +]) + +AC_CHECK_FUNCS([vsnprintf snprintf]) + +AH_VERBATIM(_TRU64,[ +/* + * On HP-UX, the declaration of vsnprintf() is needed every time ! + */ + +#if !defined(HAVE_VSNPRINTF) || defined(hpux) +#if __STDC__ +#include +#include +#else +#include +#endif +#ifdef __cplusplus +extern "C" +#endif +int vsnprintf(char *str, size_t n, char const *fmt, va_list ap); +#ifdef __cplusplus +extern "C" +#endif +int snprintf(char *str, size_t n, char const *fmt, ...); +#endif +]) + +]) + +dnl ------------------------------------------------------------------------ +dnl Find the header files and libraries for X-Windows. Extended the +dnl macro AC_PATH_X +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([K_PATH_X], +[ +AC_REQUIRE([KDE_MISC_TESTS])dnl +AC_REQUIRE([KDE_CHECK_LIB64]) + +AC_ARG_ENABLE( + embedded, + AC_HELP_STRING([--enable-embedded],[link to Qt-embedded, don't use X]), + kde_use_qt_emb=$enableval, + kde_use_qt_emb=no +) + +AC_ARG_ENABLE( + qtopia, + AC_HELP_STRING([--enable-qtopia],[link to Qt-embedded, link to the Qtopia Environment]), + kde_use_qt_emb_palm=$enableval, + kde_use_qt_emb_palm=no +) + +AC_ARG_ENABLE( + mac, + AC_HELP_STRING([--enable-mac],[link to Qt/Mac (don't use X)]), + kde_use_qt_mac=$enableval, + kde_use_qt_mac=no +) + +AC_ARG_ENABLE( + win, + AC_HELP_STRING([--enable-win],[link to Qt/Win (don't use X)]), + kde_use_qt_win=$enableval, + kde_use_qt_win=no +) +# used to disable x11-specific stuff on special platforms +AM_CONDITIONAL(include_x11, test "$kde_use_qt_emb" = "no" && test "$kde_use_qt_mac" = "no" && test "$kde_use_qt_win" = "no") + +if test "$kde_use_qt_emb" = "no" && test "$kde_use_qt_mac" = "no" && test "$kde_use_qt_win" = "no"; then + +AC_MSG_CHECKING(for X) + +AC_CACHE_VAL(kde_cv_have_x, +[# One or both of the vars are not set, and there is no cached value. +if test "{$x_includes+set}" = set || test "$x_includes" = NONE; then + kde_x_includes=NO +else + kde_x_includes=$x_includes +fi +if test "{$x_libraries+set}" = set || test "$x_libraries" = NONE; then + kde_x_libraries=NO +else + kde_x_libraries=$x_libraries +fi + +# below we use the standard autoconf calls +ac_x_libraries=$kde_x_libraries +ac_x_includes=$kde_x_includes + +KDE_PATH_X_DIRECT +dnl AC_PATH_X_XMKMF picks /usr/lib as the path for the X libraries. +dnl Unfortunately, if compiling with the N32 ABI, this is not the correct +dnl location. The correct location is /usr/lib32 or an undefined value +dnl (the linker is smart enough to pick the correct default library). +dnl Things work just fine if you use just AC_PATH_X_DIRECT. +dnl Solaris has a similar problem. AC_PATH_X_XMKMF forces x_includes to +dnl /usr/openwin/include, which doesn't work. /usr/include does work, so +dnl x_includes should be left alone. +case "$host" in +mips-sgi-irix6*) + ;; +*-*-solaris*) + ;; +*) + _AC_PATH_X_XMKMF + if test -z "$ac_x_includes"; then + ac_x_includes="." + fi + if test -z "$ac_x_libraries"; then + ac_x_libraries="/usr/lib${kdelibsuff}" + fi +esac +#from now on we use our own again + +# when the user already gave --x-includes, we ignore +# what the standard autoconf macros told us. +if test "$kde_x_includes" = NO; then + kde_x_includes=$ac_x_includes +fi + +# for --x-libraries too +if test "$kde_x_libraries" = NO; then + kde_x_libraries=$ac_x_libraries +fi + +if test "$kde_x_includes" = NO; then + AC_MSG_ERROR([Can't find X includes. Please check your installation and add the correct paths!]) +fi + +if test "$kde_x_libraries" = NO; then + AC_MSG_ERROR([Can't find X libraries. Please check your installation and add the correct paths!]) +fi + +# Record where we found X for the cache. +kde_cv_have_x="have_x=yes \ + kde_x_includes=$kde_x_includes kde_x_libraries=$kde_x_libraries" +])dnl + +eval "$kde_cv_have_x" + +if test "$have_x" != yes; then + AC_MSG_RESULT($have_x) + no_x=yes +else + AC_MSG_RESULT([libraries $kde_x_libraries, headers $kde_x_includes]) +fi + +if test -z "$kde_x_includes" || test "x$kde_x_includes" = xNONE; then + X_INCLUDES="" + x_includes="."; dnl better than nothing :- + else + x_includes=$kde_x_includes + X_INCLUDES="-I$x_includes" +fi + +if test -z "$kde_x_libraries" || test "x$kde_x_libraries" = xNONE; then + X_LDFLAGS="" + x_libraries="/usr/lib"; dnl better than nothing :- + else + x_libraries=$kde_x_libraries + X_LDFLAGS="-L$x_libraries" +fi +all_includes="$X_INCLUDES" +all_libraries="$X_LDFLAGS $LDFLAGS_AS_NEEDED $LDFLAGS_NEW_DTAGS" + +# Check for libraries that X11R6 Xt/Xaw programs need. +ac_save_LDFLAGS="$LDFLAGS" +LDFLAGS="$LDFLAGS $X_LDFLAGS" +# SM needs ICE to (dynamically) link under SunOS 4.x (so we have to +# check for ICE first), but we must link in the order -lSM -lICE or +# we get undefined symbols. So assume we have SM if we have ICE. +# These have to be linked with before -lX11, unlike the other +# libraries we check for below, so use a different variable. +# --interran@uluru.Stanford.EDU, kb@cs.umb.edu. +AC_CHECK_LIB(ICE, IceConnectionNumber, + [LIBSM="-lSM -lICE"], , $X_EXTRA_LIBS) +LDFLAGS="$ac_save_LDFLAGS" + +LIB_X11='-lX11 $(LIBSOCKET)' + +AC_MSG_CHECKING(for libXext) +AC_CACHE_VAL(kde_cv_have_libXext, +[ +kde_ldflags_safe="$LDFLAGS" +kde_libs_safe="$LIBS" + +LDFLAGS="$LDFLAGS $X_LDFLAGS $USER_LDFLAGS" +LIBS="-lXext -lX11 $LIBSOCKET" + +AC_TRY_LINK([ +#include +#ifdef STDC_HEADERS +# include +#endif +], +[ +printf("hello Xext\n"); +], +kde_cv_have_libXext=yes, +kde_cv_have_libXext=no +) + +LDFLAGS=$kde_ldflags_safe +LIBS=$kde_libs_safe +]) + +AC_MSG_RESULT($kde_cv_have_libXext) + +if test "$kde_cv_have_libXext" = "no"; then + AC_MSG_ERROR([We need a working libXext to proceed. Since configure +can't find it itself, we stop here assuming that make wouldn't find +them either.]) +fi + +LIB_XEXT="-lXext" +QTE_NORTTI="" + +elif test "$kde_use_qt_emb" = "yes"; then + dnl We're using QT Embedded + CPPFLAGS=-DQWS + CXXFLAGS="$CXXFLAGS -fno-rtti" + QTE_NORTTI="-fno-rtti -DQWS" + X_PRE_LIBS="" + LIB_X11="" + LIB_XEXT="" + LIB_XRENDER="" + LIBSM="" + X_INCLUDES="" + X_LDFLAGS="" + x_includes="" + x_libraries="" +elif test "$kde_use_qt_mac" = "yes"; then + dnl We're using QT/Mac (I use QT_MAC so that qglobal.h doesn't *have* to + dnl be included to get the information) --Sam + CXXFLAGS="$CXXFLAGS -DQT_MAC -no-cpp-precomp" + CFLAGS="$CFLAGS -DQT_MAC -no-cpp-precomp" + X_PRE_LIBS="" + LIB_X11="" + LIB_XEXT="" + LIB_XRENDER="" + LIBSM="" + X_INCLUDES="" + X_LDFLAGS="" + x_includes="" + x_libraries="" +elif test "$kde_use_qt_win" = "yes"; then + CXXFLAGS="-mthreads -Wall -O2 -fno-exceptions -frtti -DUNICODE -DQT_DLL -DQT_THREAD_SUPPORT -DQT_NO_DEBUG" + CFLAGS="$CFLAGS -mthreads -Wall -O2 -fno-exceptions -DUNICODE -DQT_DLL -DQT_THREAD_SUPPORT -DQT_NO_DEBUG" + LDFLAGS="$LDFAGS -no-undefined -Wl,-export-all-symbols -Wl,-enable-runtime-pseudo-reloc -mthreads -Wl,-s -Wl,-subsystem,windows -e __Z19QtWinMainCRTStartupv" + LIBS="$LIBS -lkernel32 -luser32 -lgdi32 -lcomdlg32 -ladvapi32 -lshell32 -lole32 -loleaut32 -luuid -limm32 -lwinmm -lwsock32 -lwinspool" + X_PRE_LIBS="" + LIB_X11="" + LIB_XEXT="" + LIB_XRENDER="" + LIBSM="" + X_INCLUDES="" + X_LDFLAGS="" + x_includes="" + x_libraries="" +fi +AC_SUBST(X_PRE_LIBS) +AC_SUBST(LIB_X11) +AC_SUBST(LIB_XRENDER) +AC_SUBST(LIBSM) +AC_SUBST(X_INCLUDES) +AC_SUBST(X_LDFLAGS) +AC_SUBST(x_includes) +AC_SUBST(x_libraries) +AC_SUBST(QTE_NORTTI) +AC_SUBST(LIB_XEXT) + +]) + +AC_DEFUN([KDE_PRINT_QT_PROGRAM], +[ +AC_REQUIRE([KDE_USE_QT]) +cat > conftest.$ac_ext < +#include +EOF +if test "$kde_qtver" = "2"; then +cat >> conftest.$ac_ext < +#include +#include +EOF + +if test $kde_qtsubver -gt 0; then +cat >> conftest.$ac_ext <> conftest.$ac_ext < +#include +#include +EOF +fi + +echo "#if ! ($kde_qt_verstring)" >> conftest.$ac_ext +cat >> conftest.$ac_ext <> conftest.$ac_ext <> conftest.$ac_ext <> conftest.$ac_ext <> conftest.$ac_ext <&AC_FD_CC + cat conftest.$ac_ext >&AC_FD_CC +fi + +rm -f conftest* +CXXFLAGS="$ac_cxxflags_safe" +LDFLAGS="$ac_ldflags_safe" +LIBS="$ac_libs_safe" + +LD_LIBRARY_PATH="$ac_LD_LIBRARY_PATH_safe" +export LD_LIBRARY_PATH +LIBRARY_PATH="$ac_LIBRARY_PATH" +export LIBRARY_PATH +AC_LANG_RESTORE +]) + +if test "$kde_cv_qt_direct" = "yes"; then + AC_MSG_RESULT(yes) + $1 +else + AC_MSG_RESULT(no) + $2 +fi +]) + +dnl ------------------------------------------------------------------------ +dnl Try to find the Qt headers and libraries. +dnl $(QT_LDFLAGS) will be -Lqtliblocation (if needed) +dnl and $(QT_INCLUDES) will be -Iqthdrlocation (if needed) +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([AC_PATH_QT_1_3], +[ +AC_REQUIRE([K_PATH_X]) +AC_REQUIRE([KDE_USE_QT]) +AC_REQUIRE([KDE_CHECK_LIB64]) + +dnl ------------------------------------------------------------------------ +dnl Add configure flag to enable linking to MT version of Qt library. +dnl ------------------------------------------------------------------------ + +AC_ARG_ENABLE( + mt, + AC_HELP_STRING([--disable-mt],[link to non-threaded Qt (deprecated)]), + kde_use_qt_mt=$enableval, + [ + if test $kde_qtver = 3; then + kde_use_qt_mt=yes + else + kde_use_qt_mt=no + fi + ] +) + +USING_QT_MT="" + +dnl ------------------------------------------------------------------------ +dnl If we not get --disable-qt-mt then adjust some vars for the host. +dnl ------------------------------------------------------------------------ + +KDE_MT_LDFLAGS= +KDE_MT_LIBS= +if test "x$kde_use_qt_mt" = "xyes"; then + KDE_CHECK_THREADING + if test "x$kde_use_threading" = "xyes"; then + CPPFLAGS="$USE_THREADS -DQT_THREAD_SUPPORT $CPPFLAGS" + KDE_MT_LDFLAGS="$USE_THREADS" + KDE_MT_LIBS="$LIBPTHREAD" + else + kde_use_qt_mt=no + fi +fi +AC_SUBST(KDE_MT_LDFLAGS) +AC_SUBST(KDE_MT_LIBS) + +kde_qt_was_given=yes + +dnl ------------------------------------------------------------------------ +dnl If we haven't been told how to link to Qt, we work it out for ourselves. +dnl ------------------------------------------------------------------------ +if test -z "$LIBQT_GLOB"; then + if test "x$kde_use_qt_emb" = "xyes"; then + LIBQT_GLOB="libqte.*" + else + LIBQT_GLOB="libqt.*" + fi +fi + +dnl ------------------------------------------------------------ +dnl If we got --enable-embedded then adjust the Qt library name. +dnl ------------------------------------------------------------ +if test "x$kde_use_qt_emb" = "xyes"; then + qtlib="qte" +else + qtlib="qt" +fi + +kde_int_qt="-l$qtlib" + +if test -z "$LIBQPE"; then +dnl ------------------------------------------------------------ +dnl If we got --enable-palmtop then add -lqpe to the link line +dnl ------------------------------------------------------------ + if test "x$kde_use_qt_emb" = "xyes"; then + if test "x$kde_use_qt_emb_palm" = "xyes"; then + LIB_QPE="-lqpe" + else + LIB_QPE="" + fi + else + LIB_QPE="" + fi +fi + +dnl ------------------------------------------------------------------------ +dnl If we got --enable-qt-mt then adjust the Qt library name for the host. +dnl ------------------------------------------------------------------------ + +if test "x$kde_use_qt_mt" = "xyes"; then + LIBQT="-l$qtlib-mt" + kde_int_qt="-l$qtlib-mt" + LIBQT_GLOB="lib$qtlib-mt.*" + USING_QT_MT="using -mt" +else + LIBQT="-l$qtlib" +fi + +if test $kde_qtver != 1; then + + AC_REQUIRE([AC_FIND_PNG]) + AC_REQUIRE([AC_FIND_JPEG]) + LIBQT="$LIBQT $LIBPNG $LIBJPEG" +fi + +if test $kde_qtver = 3; then + AC_REQUIRE([KDE_CHECK_LIBDL]) + LIBQT="$LIBQT $LIBDL" +fi + +AC_MSG_CHECKING([for Qt]) + +if test "x$kde_use_qt_emb" != "xyes" && test "x$kde_use_qt_mac" != "xyes" && test "x$kde_use_qt_win" != "xyes"; then +LIBQT="$LIBQT $X_PRE_LIBS -lXext -lX11 $LIBSM $LIBSOCKET" +fi +ac_qt_includes=NO ac_qt_libraries=NO ac_qt_bindir=NO +qt_libraries="" +qt_includes="" +AC_ARG_WITH(qt-dir, + AC_HELP_STRING([--with-qt-dir=DIR],[where the root of Qt is installed ]), + [ ac_qt_includes="$withval"/include + ac_qt_libraries="$withval"/lib${kdelibsuff} + ac_qt_bindir="$withval"/bin + ]) + +AC_ARG_WITH(qt-includes, + AC_HELP_STRING([--with-qt-includes=DIR],[where the Qt includes are. ]), + [ + ac_qt_includes="$withval" + ]) + +kde_qt_libs_given=no + +AC_ARG_WITH(qt-libraries, + AC_HELP_STRING([--with-qt-libraries=DIR],[where the Qt library is installed.]), + [ ac_qt_libraries="$withval" + kde_qt_libs_given=yes + ]) + +AC_CACHE_VAL(ac_cv_have_qt, +[#try to guess Qt locations + +qt_incdirs="" +for dir in $kde_qt_dirs; do + qt_incdirs="$qt_incdirs $dir/include $dir" +done +qt_incdirs="$QTINC $qt_incdirs /usr/local/qt/include /usr/include/qt /usr/include /usr/X11R6/include/X11/qt /usr/X11R6/include/qt /usr/X11R6/include/qt2 /usr/include/qt3 $x_includes" +if test ! "$ac_qt_includes" = "NO"; then + qt_incdirs="$ac_qt_includes $qt_incdirs" +fi + +if test "$kde_qtver" != "1"; then + kde_qt_header=qstyle.h +else + kde_qt_header=qglobal.h +fi + +AC_FIND_FILE($kde_qt_header, $qt_incdirs, qt_incdir) +ac_qt_includes="$qt_incdir" + +qt_libdirs="" +for dir in $kde_qt_dirs; do + qt_libdirs="$qt_libdirs $dir/lib${kdelibsuff} $dir" +done +qt_libdirs="$QTLIB $qt_libdirs /usr/X11R6/lib /usr/lib /usr/local/qt/lib $x_libraries" +if test ! "$ac_qt_libraries" = "NO"; then + qt_libdir=$ac_qt_libraries +else + qt_libdirs="$ac_qt_libraries $qt_libdirs" + # if the Qt was given, the chance is too big that libqt.* doesn't exist + qt_libdir=NONE + for dir in $qt_libdirs; do + try="ls -1 $dir/${LIBQT_GLOB}" + if test -n "`$try 2> /dev/null`"; then qt_libdir=$dir; break; else echo "tried $dir" >&AC_FD_CC ; fi + done +fi +for a in $qt_libdir/lib`echo ${kde_int_qt} | sed 's,^-l,,'`_incremental.*; do + if test -e "$a"; then + LIBQT="$LIBQT ${kde_int_qt}_incremental" + break + fi +done + +ac_qt_libraries="$qt_libdir" + +AC_LANG_SAVE +AC_LANG_CPLUSPLUS + +ac_cxxflags_safe="$CXXFLAGS" +ac_ldflags_safe="$LDFLAGS" +ac_libs_safe="$LIBS" + +CXXFLAGS="$CXXFLAGS -I$qt_incdir $all_includes" +LDFLAGS="$LDFLAGS -L$qt_libdir $all_libraries $USER_LDFLAGS $KDE_MT_LDFLAGS" +LIBS="$LIBS $LIBQT $KDE_MT_LIBS" + +KDE_PRINT_QT_PROGRAM + +if AC_TRY_EVAL(ac_link) && test -s conftest; then + rm -f conftest* +else + echo "configure: failed program was:" >&AC_FD_CC + cat conftest.$ac_ext >&AC_FD_CC + ac_qt_libraries="NO" +fi +rm -f conftest* +CXXFLAGS="$ac_cxxflags_safe" +LDFLAGS="$ac_ldflags_safe" +LIBS="$ac_libs_safe" + +AC_LANG_RESTORE +if test "$ac_qt_includes" = NO || test "$ac_qt_libraries" = NO; then + ac_cv_have_qt="have_qt=no" + ac_qt_notfound="" + missing_qt_mt="" + if test "$ac_qt_includes" = NO; then + if test "$ac_qt_libraries" = NO; then + ac_qt_notfound="(headers and libraries)"; + else + ac_qt_notfound="(headers)"; + fi + else + if test "x$kde_use_qt_mt" = "xyes"; then + missing_qt_mt=" +Make sure that you have compiled Qt with thread support!" + ac_qt_notfound="(library $qtlib-mt)"; + else + ac_qt_notfound="(library $qtlib)"; + fi + fi + + AC_MSG_ERROR([Qt ($kde_qt_minversion) $ac_qt_notfound not found. Please check your installation! +For more details about this problem, look at the end of config.log.$missing_qt_mt]) +else + have_qt="yes" +fi +]) + +eval "$ac_cv_have_qt" + +if test "$have_qt" != yes; then + AC_MSG_RESULT([$have_qt]); +else + ac_cv_have_qt="have_qt=yes \ + ac_qt_includes=$ac_qt_includes ac_qt_libraries=$ac_qt_libraries" + AC_MSG_RESULT([libraries $ac_qt_libraries, headers $ac_qt_includes $USING_QT_MT]) + + qt_libraries="$ac_qt_libraries" + qt_includes="$ac_qt_includes" +fi + +if test ! "$kde_qt_libs_given" = "yes" && test ! "$kde_qtver" = 3; then + KDE_CHECK_QT_DIRECT(qt_libraries= ,[]) +fi + +AC_SUBST(qt_libraries) +AC_SUBST(qt_includes) + +if test "$qt_includes" = "$x_includes" || test -z "$qt_includes"; then + QT_INCLUDES="" +else + QT_INCLUDES="-I$qt_includes" + all_includes="$QT_INCLUDES $all_includes" +fi + +if test "$qt_libraries" = "$x_libraries" || test -z "$qt_libraries"; then + QT_LDFLAGS="" +else + QT_LDFLAGS="-L$qt_libraries" + all_libraries="$QT_LDFLAGS $all_libraries" +fi +test -z "$KDE_MT_LDFLAGS" || all_libraries="$all_libraries $KDE_MT_LDFLAGS" + +AC_SUBST(QT_INCLUDES) +AC_SUBST(QT_LDFLAGS) +AC_PATH_QT_MOC_UIC + +KDE_CHECK_QT_JPEG + +if test "x$kde_use_qt_emb" != "xyes" && test "x$kde_use_qt_mac" != "xyes" && test "x$kde_use_qt_win" != "xyes"; then +LIB_QT="$kde_int_qt $LIBJPEG_QT "'$(LIBZ) $(LIBPNG) -lXext $(LIB_X11) $(LIBSM)' +else +LIB_QT="$kde_int_qt $LIBJPEG_QT "'$(LIBZ) $(LIBPNG)' +fi +test -z "$KDE_MT_LIBS" || LIB_QT="$LIB_QT $KDE_MT_LIBS" +for a in $qt_libdir/lib`echo ${kde_int_qt} | sed 's,^-l,,'`_incremental.*; do + if test -e "$a"; then + LIB_QT="$LIB_QT ${kde_int_qt}_incremental" + break + fi +done + +AC_SUBST(LIB_QT) +AC_SUBST(LIB_QPE) + +AC_SUBST(kde_qtver) +]) + +AC_DEFUN([AC_PATH_QT], +[ +AC_PATH_QT_1_3 +]) + +AC_DEFUN([KDE_CHECK_UIC_PLUGINS], +[ +AC_REQUIRE([AC_PATH_QT_MOC_UIC]) + +if test x$ac_uic_supports_libpath = xyes; then + +AC_MSG_CHECKING([if UIC has KDE plugins available]) +AC_CACHE_VAL(kde_cv_uic_plugins, +[ +cat > actest.ui << EOF + +NewConnectionDialog + + + + testInput + + + + +EOF + + + +kde_cv_uic_plugins=no +kde_line="$UIC_PATH -L $kde_widgetdir" +if test x$ac_uic_supports_nounload = xyes; then + kde_line="$kde_line -nounload" +fi +kde_line="$kde_line -impl actest.h actest.ui > actest.cpp" +if AC_TRY_EVAL(kde_line); then + # if you're trying to debug this check and think it's incorrect, + # better check your installation. The check _is_ correct - your + # installation is not. + if test -f actest.cpp && grep klineedit actest.cpp > /dev/null; then + kde_cv_uic_plugins=yes + fi +fi +rm -f actest.ui actest.cpp +]) + +AC_MSG_RESULT([$kde_cv_uic_plugins]) +if test "$kde_cv_uic_plugins" != yes; then + AC_MSG_ERROR([ +you need to install kdelibs first. + +If you did install kdelibs, then the Qt version that is picked up by +this configure is not the same version you used to compile kdelibs. +The Qt Plugin installed by kdelibs is *ONLY* loadable if it is the +_same Qt version_, compiled with the _same compiler_ and the same Qt +configuration settings. +]) +fi +fi +]) + +AC_DEFUN([KDE_CHECK_FINAL], +[ + AC_ARG_ENABLE(final, + AC_HELP_STRING([--enable-final], + [build size optimized apps (experimental - needs lots of memory)]), + kde_use_final=$enableval, kde_use_final=no) + + if test "x$kde_use_final" = "xyes"; then + KDE_USE_FINAL_TRUE="" + KDE_USE_FINAL_FALSE="#" + else + KDE_USE_FINAL_TRUE="#" + KDE_USE_FINAL_FALSE="" + fi + AC_SUBST(KDE_USE_FINAL_TRUE) + AC_SUBST(KDE_USE_FINAL_FALSE) +]) + +AC_DEFUN([KDE_CHECK_CLOSURE], +[ + AC_ARG_ENABLE(closure, + AC_HELP_STRING([--enable-closure],[delay template instantiation]), + kde_use_closure=$enableval, kde_use_closure=no) + + KDE_NO_UNDEFINED="" + if test "x$kde_use_closure" = "xyes"; then + KDE_USE_CLOSURE_TRUE="" + KDE_USE_CLOSURE_FALSE="#" +# CXXFLAGS="$CXXFLAGS $REPO" + else + KDE_USE_CLOSURE_TRUE="#" + KDE_USE_CLOSURE_FALSE="" + KDE_NO_UNDEFINED="" + case $host in + *-*-linux-gnu) + KDE_CHECK_COMPILER_FLAG([Wl,--no-undefined], + [KDE_CHECK_COMPILER_FLAG([Wl,--allow-shlib-undefined], + [KDE_NO_UNDEFINED="-Wl,--no-undefined -Wl,--allow-shlib-undefined"], + [KDE_NO_UNDEFINED=""])], + [KDE_NO_UNDEFINED=""]) + ;; + esac + fi + AC_SUBST(KDE_USE_CLOSURE_TRUE) + AC_SUBST(KDE_USE_CLOSURE_FALSE) + AC_SUBST(KDE_NO_UNDEFINED) +]) + +dnl Check if the linker supports --enable-new-dtags and --as-needed +AC_DEFUN([KDE_CHECK_NEW_LDFLAGS], +[ + AC_ARG_ENABLE(new_ldflags, + AC_HELP_STRING([--enable-new-ldflags], + [enable the new linker flags]), + kde_use_new_ldflags=$enableval, + kde_use_new_ldflags=no) + + LDFLAGS_AS_NEEDED="" + LDFLAGS_NEW_DTAGS="" + if test "x$kde_use_new_ldflags" = "xyes"; then + LDFLAGS_NEW_DTAGS="" + KDE_CHECK_COMPILER_FLAG([Wl,--enable-new-dtags], + [LDFLAGS_NEW_DTAGS="-Wl,--enable-new-dtags"],) + + KDE_CHECK_COMPILER_FLAG([Wl,--as-needed], + [LDFLAGS_AS_NEEDED="-Wl,--as-needed"],) + fi + AC_SUBST(LDFLAGS_AS_NEEDED) + AC_SUBST(LDFLAGS_NEW_DTAGS) +]) + +AC_DEFUN([KDE_CHECK_NMCHECK], +[ + AC_ARG_ENABLE(nmcheck,AC_HELP_STRING([--enable-nmcheck],[enable automatic namespace cleanness check]), + kde_use_nmcheck=$enableval, kde_use_nmcheck=no) + + if test "$kde_use_nmcheck" = "yes"; then + KDE_USE_NMCHECK_TRUE="" + KDE_USE_NMCHECK_FALSE="#" + else + KDE_USE_NMCHECK_TRUE="#" + KDE_USE_NMCHECK_FALSE="" + fi + AC_SUBST(KDE_USE_NMCHECK_TRUE) + AC_SUBST(KDE_USE_NMCHECK_FALSE) +]) + +AC_DEFUN([KDE_EXPAND_MAKEVAR], [ +savex=$exec_prefix +test "x$exec_prefix" = xNONE && exec_prefix=$prefix +tmp=$$2 +while $1=`eval echo "$tmp"`; test "x$$1" != "x$tmp"; do tmp=$$1; done +exec_prefix=$savex +]) + +dnl ------------------------------------------------------------------------ +dnl Now, the same with KDE +dnl $(KDE_LDFLAGS) will be the kdeliblocation (if needed) +dnl and $(kde_includes) will be the kdehdrlocation (if needed) +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([AC_BASE_PATH_KDE], +[ +AC_REQUIRE([KDE_CHECK_STL]) +AC_REQUIRE([AC_PATH_QT])dnl + +if test "$use_kde" = "yes"; then +AC_REQUIRE([KDE_CHECK_LIB64]) + +AC_CHECK_RPATH +AC_MSG_CHECKING([for KDE]) + +if test "${prefix}" != NONE; then + kde_includes=${includedir} + KDE_EXPAND_MAKEVAR(ac_kde_includes, includedir) + + kde_libraries=${libdir} + KDE_EXPAND_MAKEVAR(ac_kde_libraries, libdir) + +else + ac_kde_includes= + ac_kde_libraries= + kde_libraries="" + kde_includes="" +fi + +AC_CACHE_VAL(ac_cv_have_kde, +[#try to guess kde locations + +if test "$kde_qtver" = 1; then + kde_check_header="ksock.h" + kde_check_lib="libkdecore.la" +else + kde_check_header="ksharedptr.h" + kde_check_lib="libkio.la" +fi + +if test -z "$1"; then + +kde_incdirs="$kde_libs_prefix/include /usr/lib/kde/include /usr/local/kde/include /usr/local/include /usr/kde/include /usr/include/kde /usr/include /opt/kde3/include /opt/kde/include $x_includes $qt_includes" +test -n "$KDEDIR" && kde_incdirs="$KDEDIR/include $KDEDIR/include/kde $KDEDIR $kde_incdirs" +kde_incdirs="$ac_kde_includes $kde_incdirs" +AC_FIND_FILE($kde_check_header, $kde_incdirs, kde_incdir) +ac_kde_includes="$kde_incdir" + +if test -n "$ac_kde_includes" && test ! -r "$ac_kde_includes/$kde_check_header"; then + AC_MSG_ERROR([ +in the prefix, you've chosen, are no KDE headers installed. This will fail. +So, check this please and use another prefix!]) +fi + +kde_libdirs="$kde_libs_prefix/lib${kdelibsuff} /usr/lib/kde/lib${kdelibsuff} /usr/local/kde/lib${kdelibsuff} /usr/kde/lib${kdelibsuff} /usr/lib${kdelibsuff}/kde /usr/lib${kdelibsuff}/kde3 /usr/lib${kdelibsuff} /usr/X11R6/lib${kdelibsuff} /usr/local/lib${kdelibsuff} /opt/kde3/lib${kdelibsuff} /opt/kde/lib${kdelibsuff} /usr/X11R6/kde/lib${kdelibsuff}" +test -n "$KDEDIR" && kde_libdirs="$KDEDIR/lib${kdelibsuff} $KDEDIR $kde_libdirs" +kde_libdirs="$ac_kde_libraries $libdir $kde_libdirs" +AC_FIND_FILE($kde_check_lib, $kde_libdirs, kde_libdir) +ac_kde_libraries="$kde_libdir" + +kde_widgetdir=NO +dnl this might be somewhere else +AC_FIND_FILE("kde3/plugins/designer/kdewidgets.la", $kde_libdirs, kde_widgetdir) + +if test -n "$ac_kde_libraries" && test ! -r "$ac_kde_libraries/$kde_check_lib"; then +AC_MSG_ERROR([ +in the prefix, you've chosen, are no KDE libraries installed. This will fail. +So, check this please and use another prefix!]) +fi + +dnl Not needed for SIM ... +dnl if test -n "$kde_widgetdir" && test ! -r "$kde_widgetdir/kde3/plugins/designer/kdewidgets.la"; then +dnl AC_MSG_ERROR([ +dnl I can't find the designer plugins. These are required and should have been installed +dnl by kdelibs]) +dnl fi + +if test -n "$kde_widgetdir"; then + kde_widgetdir="$kde_widgetdir/kde3/plugins/designer" +fi + + +if test "$ac_kde_includes" = NO || test "$ac_kde_libraries" = NO || test "$kde_widgetdir" = NO; then + ac_cv_have_kde="have_kde=no" +else + ac_cv_have_kde="have_kde=yes \ + ac_kde_includes=$ac_kde_includes ac_kde_libraries=$ac_kde_libraries" +fi + +else dnl test -z $1, e.g. from kdelibs + + ac_cv_have_kde="have_kde=no" + +fi +])dnl + +eval "$ac_cv_have_kde" + +if test "$have_kde" != "yes"; then + if test "${prefix}" = NONE; then + ac_kde_prefix="$ac_default_prefix" + else + ac_kde_prefix="$prefix" + fi + if test "$exec_prefix" = NONE; then + ac_kde_exec_prefix="$ac_kde_prefix" + AC_MSG_RESULT([will be installed in $ac_kde_prefix]) + else + ac_kde_exec_prefix="$exec_prefix" + AC_MSG_RESULT([will be installed in $ac_kde_prefix and $ac_kde_exec_prefix]) + fi + + kde_libraries="${libdir}" + kde_includes="${includedir}" + +else + ac_cv_have_kde="have_kde=yes \ + ac_kde_includes=$ac_kde_includes ac_kde_libraries=$ac_kde_libraries" + AC_MSG_RESULT([libraries $ac_kde_libraries, headers $ac_kde_includes]) + + kde_libraries="$ac_kde_libraries" + kde_includes="$ac_kde_includes" +fi +AC_SUBST(kde_libraries) +AC_SUBST(kde_includes) + +if test "$kde_includes" = "$x_includes" || test "$kde_includes" = "$qt_includes" || test "$kde_includes" = "/usr/include"; then + KDE_INCLUDES="" +else + KDE_INCLUDES="-I$kde_includes" + all_includes="$KDE_INCLUDES $all_includes" +fi + +KDE_DEFAULT_CXXFLAGS="-DQT_CLEAN_NAMESPACE -DQT_NO_ASCII_CAST -DQT_NO_STL -DQT_NO_COMPAT -DQT_NO_TRANSLATION" + +KDE_LDFLAGS="-L$kde_libraries" +if test ! "$kde_libraries" = "$x_libraries" && test ! "$kde_libraries" = "$qt_libraries" ; then + all_libraries="$KDE_LDFLAGS $all_libraries" +fi +AC_DEFINE(USE_KDE,1,[Use KDE]) +else +kde_libraries="$qt_libraries" +AC_SUBST(kde_libraries) +fi + +AC_SUBST(KDE_LDFLAGS) +AC_SUBST(KDE_INCLUDES) + +AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) + +all_libraries="$all_libraries $USER_LDFLAGS" +all_includes="$all_includes $USER_INCLUDES" +AC_SUBST(all_includes) +AC_SUBST(all_libraries) + +if test "$use_kde" = "yes"; then + if test -z "$1"; then + KDE_CHECK_UIC_PLUGINS + fi +fi +ac_kde_libraries="$kde_libdir" + +AC_SUBST(AUTODIRS) + + +]) + +AC_DEFUN([KDE_CHECK_EXTRA_LIBS], +[ +AC_MSG_CHECKING(for extra includes) +AC_ARG_WITH(extra-includes,AC_HELP_STRING([--with-extra-includes=DIR],[adds non standard include paths]), + kde_use_extra_includes="$withval", + kde_use_extra_includes=NONE +) +kde_extra_includes= +if test -n "$kde_use_extra_includes" && \ + test "$kde_use_extra_includes" != "NONE"; then + + ac_save_ifs=$IFS + IFS=':' + for dir in $kde_use_extra_includes; do + kde_extra_includes="$kde_extra_includes $dir" + USER_INCLUDES="$USER_INCLUDES -I$dir" + done + IFS=$ac_save_ifs + kde_use_extra_includes="added" +else + kde_use_extra_includes="no" +fi +AC_SUBST(USER_INCLUDES) + +AC_MSG_RESULT($kde_use_extra_includes) + +kde_extra_libs= +AC_MSG_CHECKING(for extra libs) +AC_ARG_WITH(extra-libs,AC_HELP_STRING([--with-extra-libs=DIR],[adds non standard library paths]), + kde_use_extra_libs=$withval, + kde_use_extra_libs=NONE +) +if test -n "$kde_use_extra_libs" && \ + test "$kde_use_extra_libs" != "NONE"; then + + ac_save_ifs=$IFS + IFS=':' + for dir in $kde_use_extra_libs; do + kde_extra_libs="$kde_extra_libs $dir" + KDE_EXTRA_RPATH="$KDE_EXTRA_RPATH -R $dir" + USER_LDFLAGS="$USER_LDFLAGS -L$dir" + done + IFS=$ac_save_ifs + kde_use_extra_libs="added" +else + kde_use_extra_libs="no" +fi + +AC_SUBST(USER_LDFLAGS) + +AC_MSG_RESULT($kde_use_extra_libs) + +]) + +AC_DEFUN([KDE_1_CHECK_PATH_HEADERS], +[ + AC_MSG_CHECKING([for KDE headers installed]) + AC_LANG_SAVE + AC_LANG_CPLUSPLUS +cat > conftest.$ac_ext < +#endif +#include +#include "confdefs.h" +#include + +int main() { + printf("kde_htmldir=\\"%s\\"\n", KApplication::kde_htmldir().data()); + printf("kde_appsdir=\\"%s\\"\n", KApplication::kde_appsdir().data()); + printf("kde_icondir=\\"%s\\"\n", KApplication::kde_icondir().data()); + printf("kde_sounddir=\\"%s\\"\n", KApplication::kde_sounddir().data()); + printf("kde_datadir=\\"%s\\"\n", KApplication::kde_datadir().data()); + printf("kde_locale=\\"%s\\"\n", KApplication::kde_localedir().data()); + printf("kde_cgidir=\\"%s\\"\n", KApplication::kde_cgidir().data()); + printf("kde_confdir=\\"%s\\"\n", KApplication::kde_configdir().data()); + printf("kde_mimedir=\\"%s\\"\n", KApplication::kde_mimedir().data()); + printf("kde_toolbardir=\\"%s\\"\n", KApplication::kde_toolbardir().data()); + printf("kde_wallpaperdir=\\"%s\\"\n", + KApplication::kde_wallpaperdir().data()); + printf("kde_bindir=\\"%s\\"\n", KApplication::kde_bindir().data()); + printf("kde_partsdir=\\"%s\\"\n", KApplication::kde_partsdir().data()); + printf("kde_servicesdir=\\"/tmp/dummy\\"\n"); + printf("kde_servicetypesdir=\\"/tmp/dummy\\"\n"); + printf("kde_moduledir=\\"/tmp/dummy\\"\n"); + printf("kde_styledir=\\"/tmp/dummy\\"\n"); + printf("kde_widgetdir=\\"/tmp/dummy\\"\n"); + printf("xdg_appsdir=\\"/tmp/dummy\\"\n"); + printf("xdg_menudir=\\"/tmp/dummy\\"\n"); + printf("xdg_directorydir=\\"/tmp/dummy\\"\n"); + printf("kde_kcfgdir=\\"/tmp/dummy\\"\n"); + return 0; + } +EOF + + ac_save_CPPFLAGS=$CPPFLAGS + CPPFLAGS="$all_includes $CPPFLAGS" + if AC_TRY_EVAL(ac_compile); then + AC_MSG_RESULT(yes) + else + AC_MSG_ERROR([your system is not able to compile a small KDE application! +Check, if you installed the KDE header files correctly. +For more details about this problem, look at the end of config.log.]) + fi + CPPFLAGS=$ac_save_CPPFLAGS + + AC_LANG_RESTORE +]) + +AC_DEFUN([KDE_CHECK_KDEQTADDON], +[ +AC_MSG_CHECKING(for kde-qt-addon) +AC_CACHE_VAL(kde_cv_have_kdeqtaddon, +[ + kde_ldflags_safe="$LDFLAGS" + kde_libs_safe="$LIBS" + kde_cxxflags_safe="$CXXFLAGS" + + LIBS="-lkde-qt-addon $LIBQT $LIBS" + CXXFLAGS="$CXXFLAGS -I$prefix/include -I$prefix/include/kde $all_includes" + LDFLAGS="$LDFLAGS $all_libraries $USER_LDFLAGS" + + AC_TRY_LINK([ + #include + ], + [ + QDomDocument doc; + ], + kde_cv_have_kdeqtaddon=yes, + kde_cv_have_kdeqtaddon=no + ) + + LDFLAGS=$kde_ldflags_safe + LIBS=$kde_libs_safe + CXXFLAGS=$kde_cxxflags_safe +]) + +AC_MSG_RESULT($kde_cv_have_kdeqtaddon) + +if test "$kde_cv_have_kdeqtaddon" = "no"; then + AC_MSG_ERROR([Can't find libkde-qt-addon. You need to install it first. +It is a separate package (and CVS module) named kde-qt-addon.]) +fi +]) + +AC_DEFUN([KDE_CREATE_LIBS_ALIASES], +[ + AC_REQUIRE([KDE_MISC_TESTS]) + AC_REQUIRE([KDE_CHECK_LIBDL]) + AC_REQUIRE([K_PATH_X]) + + AC_REQUIRE([KDE_USE_QT]) +if test "$use_kde" = "yes"; then +if test $kde_qtver = 3; then + case $host in + *cygwin*) lib_kded="-lkdeinit_kded" ;; + *) lib_kded="" ;; + esac + AC_SUBST(LIB_KDED, $lib_kded) + AC_SUBST(LIB_KDECORE, "-lkdecore") + AC_SUBST(LIB_KDEUI, "-lkdeui") + AC_SUBST(LIB_KIO, "-lkio") + AC_SUBST(LIB_KJS, "-lkjs") + AC_SUBST(LIB_SMB, "-lsmb") + AC_SUBST(LIB_KAB, "-lkab") + AC_SUBST(LIB_KABC, "-lkabc") + AC_SUBST(LIB_KHTML, "-lkhtml") + AC_SUBST(LIB_KSPELL, "-lkspell") + AC_SUBST(LIB_KPARTS, "-lkparts") + AC_SUBST(LIB_KDEPRINT, "-lkdeprint") + AC_SUBST(LIB_KUTILS, "-lkutils") + AC_SUBST(LIB_KDEPIM, "-lkdepim") + AC_SUBST(LIB_KDEFX, "-lkdefx") + AC_SUBST(LIB_KIMPROXY, "-lkimproxy") + AC_SUBST(LIB_KNEWSTUFF, "-lknewstuff") + AC_SUBST(LIB_KDNSSD, "-lkdnssd") + AC_SUBST(LIB_KUNITTEST, "-lkunittest") +# these are for backward compatibility + AC_SUBST(LIB_KSYCOCA, "-lkio") + AC_SUBST(LIB_KFILE, "-lkio") +elif test $kde_qtver = 2; then + AC_SUBST(LIB_KDECORE, "-lkdecore") + AC_SUBST(LIB_KDEUI, "-lkdeui") + AC_SUBST(LIB_KIO, "-lkio") + AC_SUBST(LIB_KSYCOCA, "-lksycoca") + AC_SUBST(LIB_SMB, "-lsmb") + AC_SUBST(LIB_KFILE, "-lkfile") + AC_SUBST(LIB_KAB, "-lkab") + AC_SUBST(LIB_KHTML, "-lkhtml") + AC_SUBST(LIB_KSPELL, "-lkspell") + AC_SUBST(LIB_KPARTS, "-lkparts") + AC_SUBST(LIB_KDEPRINT, "-lkdeprint") +else + AC_SUBST(LIB_KDECORE, "-lkdecore -lXext $(LIB_QT)") + AC_SUBST(LIB_KDEUI, "-lkdeui $(LIB_KDECORE)") + AC_SUBST(LIB_KFM, "-lkfm $(LIB_KDECORE)") + AC_SUBST(LIB_KFILE, "-lkfile $(LIB_KFM) $(LIB_KDEUI)") + AC_SUBST(LIB_KAB, "-lkab $(LIB_KIMGIO) $(LIB_KDECORE)") +fi +fi +]) + +AC_DEFUN([AC_PATH_KDE], +[ + AC_BASE_PATH_KDE + AC_ARG_ENABLE(path-check,AC_HELP_STRING([--disable-path-check],[don't try to find out, where to install]), + [ + if test "$enableval" = "no"; + then ac_use_path_checking="default" + else ac_use_path_checking="" + fi + ], + [ + if test "$kde_qtver" = 1; + then ac_use_path_checking="" + else ac_use_path_checking="default" + fi + ] + ) + + if test "$use_kde" = "yes"; then + AC_CREATE_KFSSTND($ac_use_path_checking) + + AC_SUBST_KFSSTND + KDE_CREATE_LIBS_ALIASES + fi +]) + +dnl KDE_CHECK_FUNC_EXT(, [headers], [sample-use], [C prototype], [autoheader define], [call if found]) +AC_DEFUN([KDE_CHECK_FUNC_EXT], +[ +AC_MSG_CHECKING(for $1) +AC_CACHE_VAL(kde_cv_func_$1, +[ +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +save_CXXFLAGS="$CXXFLAGS" +kde_safe_LIBS="$LIBS" +LIBS="$LIBS $X_EXTRA_LIBS" +if test "$GXX" = "yes"; then +CXXFLAGS="$CXXFLAGS -pedantic-errors" +fi +AC_TRY_COMPILE([ +$2 +], +[ +$3 +], +kde_cv_func_$1=yes, +kde_cv_func_$1=no) +CXXFLAGS="$save_CXXFLAGS" +LIBS="$kde_safe_LIBS" +AC_LANG_RESTORE +]) + +AC_MSG_RESULT($kde_cv_func_$1) + +AC_MSG_CHECKING([if $1 needs custom prototype]) +AC_CACHE_VAL(kde_cv_proto_$1, +[ +if test "x$kde_cv_func_$1" = xyes; then + kde_cv_proto_$1=no +else + case "$1" in + setenv|unsetenv|usleep|random|srandom|seteuid|mkstemps|mkstemp|revoke|vsnprintf|strlcpy|strlcat) + kde_cv_proto_$1="yes - in libkdefakes" + ;; + *) + kde_cv_proto_$1=unknown + ;; + esac +fi + +if test "x$kde_cv_proto_$1" = xunknown; then + +AC_LANG_SAVE +AC_LANG_CPLUSPLUS + kde_safe_libs=$LIBS + LIBS="$LIBS $X_EXTRA_LIBS" + AC_TRY_LINK([ +$2 + +extern "C" $4; +], +[ +$3 +], +[ kde_cv_func_$1=yes + kde_cv_proto_$1=yes ], + [kde_cv_proto_$1="$1 unavailable"] +) +LIBS=$kde_safe_libs +AC_LANG_RESTORE +fi +]) +AC_MSG_RESULT($kde_cv_proto_$1) + +if test "x$kde_cv_func_$1" = xyes; then + AC_DEFINE(HAVE_$5, 1, [Define if you have $1]) + $6 +fi +if test "x$kde_cv_proto_$1" = xno; then + AC_DEFINE(HAVE_$5_PROTO, 1, + [Define if you have the $1 prototype]) +fi + +AH_VERBATIM([_HAVE_$5_PROTO], +[ +#if !defined(HAVE_$5_PROTO) +#ifdef __cplusplus +extern "C" { +#endif +$4; +#ifdef __cplusplus +} +#endif +#endif +]) +]) + +AC_DEFUN([AC_CHECK_SETENV], +[ + KDE_CHECK_FUNC_EXT(setenv, [ +#include +], + [setenv("VAR", "VALUE", 1);], + [int setenv (const char *, const char *, int)], + [SETENV]) +]) + +AC_DEFUN([AC_CHECK_UNSETENV], +[ + KDE_CHECK_FUNC_EXT(unsetenv, [ +#include +], + [unsetenv("VAR");], + [void unsetenv (const char *)], + [UNSETENV]) +]) + +AC_DEFUN([AC_CHECK_GETDOMAINNAME], +[ + KDE_CHECK_FUNC_EXT(getdomainname, [ +#include +#include +#include +], + [ +char buffer[200]; +getdomainname(buffer, 200); +], + [#include + int getdomainname (char *, size_t)], + [GETDOMAINNAME]) +]) + +AC_DEFUN([AC_CHECK_GETHOSTNAME], +[ + KDE_CHECK_FUNC_EXT(gethostname, [ +#include +#include +], + [ +char buffer[200]; +gethostname(buffer, 200); +], + [int gethostname (char *, unsigned int)], + [GETHOSTNAME]) +]) + +AC_DEFUN([AC_CHECK_USLEEP], +[ + KDE_CHECK_FUNC_EXT(usleep, [ +#include +], + [ +usleep(200); +], + [int usleep (unsigned int)], + [USLEEP]) +]) + + +AC_DEFUN([AC_CHECK_RANDOM], +[ + KDE_CHECK_FUNC_EXT(random, [ +#include +], + [ +random(); +], + [long int random(void)], + [RANDOM]) + + KDE_CHECK_FUNC_EXT(srandom, [ +#include +], + [ +srandom(27); +], + [void srandom(unsigned int)], + [SRANDOM]) + +]) + +AC_DEFUN([AC_CHECK_INITGROUPS], +[ + KDE_CHECK_FUNC_EXT(initgroups, [ +#include +#include +#include +], + [ +char buffer[200]; +initgroups(buffer, 27); +], + [int initgroups(const char *, gid_t)], + [INITGROUPS]) +]) + +AC_DEFUN([AC_CHECK_MKSTEMPS], +[ + KDE_CHECK_FUNC_EXT(mkstemps, [ +#include +#include +], + [ +mkstemps("/tmp/aaaXXXXXX", 6); +], + [int mkstemps(char *, int)], + [MKSTEMPS]) +]) + +AC_DEFUN([AC_CHECK_MKSTEMP], +[ + KDE_CHECK_FUNC_EXT(mkstemp, [ +#include +#include +], + [ +mkstemp("/tmp/aaaXXXXXX"); +], + [int mkstemp(char *)], + [MKSTEMP]) +]) + +AC_DEFUN([AC_CHECK_MKDTEMP], +[ + KDE_CHECK_FUNC_EXT(mkdtemp, [ +#include +#include +], + [ +mkdtemp("/tmp/aaaXXXXXX"); +], + [char *mkdtemp(char *)], + [MKDTEMP]) +]) + + +AC_DEFUN([AC_CHECK_RES_INIT], +[ + AC_MSG_CHECKING([if res_init needs -lresolv]) + kde_libs_safe="$LIBS" + LIBS="$LIBS $X_EXTRA_LIBS -lresolv" + AC_TRY_LINK( + [ +#include +#include +#include +#include + ], + [ + res_init(); + ], + [ + LIBRESOLV="-lresolv" + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_RES_INIT, 1, [Define if you have the res_init function]) + ], + [ AC_MSG_RESULT(no) ] + ) + LIBS=$kde_libs_safe + AC_SUBST(LIBRESOLV) + + KDE_CHECK_FUNC_EXT(res_init, + [ +#include +#include +#include +#include + ], + [res_init()], + [int res_init(void)], + [RES_INIT]) +]) + +AC_DEFUN([AC_CHECK_STRLCPY], +[ + KDE_CHECK_FUNC_EXT(strlcpy, [ +#include +], +[ char buf[20]; + strlcpy(buf, "KDE function test", sizeof(buf)); +], + [unsigned long strlcpy(char*, const char*, unsigned long)], + [STRLCPY]) +]) + +AC_DEFUN([AC_CHECK_STRLCAT], +[ + KDE_CHECK_FUNC_EXT(strlcat, [ +#include +], +[ char buf[20]; + buf[0]='\0'; + strlcat(buf, "KDE function test", sizeof(buf)); +], + [unsigned long strlcat(char*, const char*, unsigned long)], + [STRLCAT]) +]) + +AC_DEFUN([AC_CHECK_RES_QUERY], +[ + KDE_CHECK_FUNC_EXT(res_query, [ +#include +#include +#include +#include +#include +], +[ +res_query(NULL, 0, 0, NULL, 0); +], + [int res_query(const char *, int, int, unsigned char *, int)], + [RES_QUERY]) +]) + +AC_DEFUN([AC_CHECK_DN_SKIPNAME], +[ + KDE_CHECK_FUNC_EXT(dn_skipname, [ +#include +#include +#include +#include +], +[ +dn_skipname (NULL, NULL); +], + [int dn_skipname (unsigned char *, unsigned char *)], + [DN_SKIPNAME]) +]) + + +AC_DEFUN([AC_FIND_GIF], + [AC_MSG_CHECKING([for giflib]) +AC_CACHE_VAL(ac_cv_lib_gif, +[ac_save_LIBS="$LIBS" +if test "x$kde_use_qt_emb" != "xyes" && test "x$kde_use_qt_mac" != "xyes" && test "x$kde_use_qt_win" != "xyes"; then +LIBS="$all_libraries -lgif -lX11 $LIBSOCKET" +else +LIBS="$all_libraries -lgif" +fi +AC_TRY_LINK(dnl +[ +#ifdef __cplusplus +extern "C" { +#endif +int GifLastError(void); +#ifdef __cplusplus +} +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +], + [return GifLastError();], + eval "ac_cv_lib_gif=yes", + eval "ac_cv_lib_gif=no") +LIBS="$ac_save_LIBS" +])dnl +if eval "test \"`echo $ac_cv_lib_gif`\" = yes"; then + AC_MSG_RESULT(yes) + AC_DEFINE_UNQUOTED(HAVE_LIBGIF, 1, [Define if you have libgif]) +else + AC_MSG_ERROR(You need giflib30. Please install the kdesupport package) +fi +]) + +AC_DEFUN([KDE_FIND_JPEG_HELPER], +[ +AC_MSG_CHECKING([for libjpeg$2]) +AC_CACHE_VAL(ac_cv_lib_jpeg_$1, +[ +ac_save_LIBS="$LIBS" +LIBS="$all_libraries $USER_LDFLAGS -ljpeg$2 -lm" +ac_save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $all_includes $USER_INCLUDES" +AC_TRY_LINK( +[ +#ifdef __cplusplus +extern "C" { +#endif +void jpeg_CreateDecompress(); +#ifdef __cplusplus +} +#endif +], +[jpeg_CreateDecompress();], + eval "ac_cv_lib_jpeg_$1=-ljpeg$2", + eval "ac_cv_lib_jpeg_$1=no") +LIBS="$ac_save_LIBS" +CFLAGS="$ac_save_CFLAGS" +]) + +if eval "test ! \"`echo $ac_cv_lib_jpeg_$1`\" = no"; then + LIBJPEG="$ac_cv_lib_jpeg_$1" + AC_MSG_RESULT($ac_cv_lib_jpeg_$1) +else + AC_MSG_RESULT(no) + $3 +fi + +]) + +AC_DEFUN([AC_FIND_JPEG], +[ +dnl first look for libraries +KDE_FIND_JPEG_HELPER(6b, 6b, + KDE_FIND_JPEG_HELPER(normal, [], + [ + LIBJPEG= + ] + ) +) + +dnl then search the headers (can't use simply AC_TRY_xxx, as jpeglib.h +dnl requires system dependent includes loaded before it) +jpeg_incdirs="$includedir /usr/include /usr/local/include $kde_extra_includes" +AC_FIND_FILE(jpeglib.h, $jpeg_incdirs, jpeg_incdir) +test "x$jpeg_incdir" = xNO && jpeg_incdir= + +dnl if headers _and_ libraries are missing, this is no error, and we +dnl continue with a warning (the user will get no jpeg support in khtml) +dnl if only one is missing, it means a configuration error, but we still +dnl only warn +if test -n "$jpeg_incdir" && test -n "$LIBJPEG" ; then + AC_DEFINE_UNQUOTED(HAVE_LIBJPEG, 1, [Define if you have libjpeg]) +else + if test -n "$jpeg_incdir" || test -n "$LIBJPEG" ; then + AC_MSG_WARN([ +There is an installation error in jpeg support. You seem to have only one +of either the headers _or_ the libraries installed. You may need to either +provide correct --with-extra-... options, or the development package of +libjpeg6b. You can get a source package of libjpeg from http://www.ijg.org/ +Disabling JPEG support. +]) + else + AC_MSG_WARN([libjpeg not found. disable JPEG support.]) + fi + jpeg_incdir= + LIBJPEG= +fi + +AC_SUBST(LIBJPEG) +AH_VERBATIM(_AC_CHECK_JPEG, +[/* + * jpeg.h needs HAVE_BOOLEAN, when the system uses boolean in system + * headers and I'm too lazy to write a configure test as long as only + * unixware is related + */ +#ifdef _UNIXWARE +#define HAVE_BOOLEAN +#endif +]) +]) + +AC_DEFUN([KDE_CHECK_QT_JPEG], +[ +if test -n "$LIBJPEG"; then +AC_MSG_CHECKING([if Qt needs $LIBJPEG]) +AC_CACHE_VAL(kde_cv_qt_jpeg, +[ +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +ac_save_LIBS="$LIBS" +LIBS="$all_libraries $USER_LDFLAGS $LIBQT" +LIBS=`echo $LIBS | sed "s/$LIBJPEG//"` +ac_save_CXXFLAGS="$CXXFLAGS" +CXXFLAGS="$CXXFLAGS $all_includes $USER_INCLUDES" +AC_TRY_LINK( +[#include ], + [ + int argc; + char** argv; + QApplication app(argc, argv);], + eval "kde_cv_qt_jpeg=no", + eval "kde_cv_qt_jpeg=yes") +LIBS="$ac_save_LIBS" +CXXFLAGS="$ac_save_CXXFLAGS" +AC_LANG_RESTORE +fi +]) + +if eval "test ! \"`echo $kde_cv_qt_jpeg`\" = no"; then + AC_MSG_RESULT(yes) + LIBJPEG_QT='$(LIBJPEG)' +else + AC_MSG_RESULT(no) + LIBJPEG_QT= +fi + +]) + +AC_DEFUN([AC_FIND_ZLIB], +[ +AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) +AC_MSG_CHECKING([for libz]) +AC_CACHE_VAL(ac_cv_lib_z, +[ +kde_save_LIBS="$LIBS" +LIBS="$all_libraries $USER_LDFLAGS -lz $LIBSOCKET" +kde_save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $all_includes $USER_INCLUDES" +AC_TRY_LINK(dnl +[ +#include +], +[ + char buf[42]; + gzFile f = (gzFile) 0; + /* this would segfault.. but we only link, don't run */ + (void) gzgets(f, buf, sizeof(buf)); + + return (zlibVersion() == ZLIB_VERSION); +], + eval "ac_cv_lib_z='-lz'", + eval "ac_cv_lib_z=no") +LIBS="$kde_save_LIBS" +CFLAGS="$kde_save_CFLAGS" +])dnl +if test ! "$ac_cv_lib_z" = no; then + AC_DEFINE_UNQUOTED(HAVE_LIBZ, 1, [Define if you have libz]) + LIBZ="$ac_cv_lib_z" + AC_MSG_RESULT($ac_cv_lib_z) +else + AC_MSG_ERROR(not found. + Possibly configure picks up an outdated version + installed by XFree86. Remove it from your system. + + Check your installation and look into config.log) + LIBZ="" +fi +AC_SUBST(LIBZ) +]) + +AC_DEFUN([KDE_TRY_TIFFLIB], +[ +AC_MSG_CHECKING([for libtiff $1]) + +AC_CACHE_VAL(kde_cv_libtiff_$1, +[ +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +kde_save_LIBS="$LIBS" +if test "x$kde_use_qt_emb" != "xyes" && test "x$kde_use_qt_mac" != "xyes" && test "x$kde_use_qt_win" != "xyes"; then +LIBS="$all_libraries $USER_LDFLAGS -l$1 $LIBJPEG $LIBZ -lX11 $LIBSOCKET -lm" +else +LIBS="$all_libraries $USER_LDFLAGS -l$1 $LIBJPEG $LIBZ -lm" +fi +kde_save_CXXFLAGS="$CXXFLAGS" +CXXFLAGS="$CXXFLAGS $all_includes $USER_INCLUDES" + +AC_TRY_LINK(dnl +[ +#include +], + [return (TIFFOpen( "", "r") == 0); ], +[ + kde_cv_libtiff_$1="-l$1 $LIBJPEG $LIBZ" +], [ + kde_cv_libtiff_$1=no +]) + +LIBS="$kde_save_LIBS" +CXXFLAGS="$kde_save_CXXFLAGS" +AC_LANG_RESTORE +]) + +if test "$kde_cv_libtiff_$1" = "no"; then + AC_MSG_RESULT(no) + LIBTIFF="" + $3 +else + LIBTIFF="$kde_cv_libtiff_$1" + AC_MSG_RESULT(yes) + AC_DEFINE_UNQUOTED(HAVE_LIBTIFF, 1, [Define if you have libtiff]) + $2 +fi + +]) + +AC_DEFUN([AC_FIND_TIFF], +[ +AC_REQUIRE([K_PATH_X]) +AC_REQUIRE([AC_FIND_ZLIB]) +AC_REQUIRE([AC_FIND_JPEG]) +AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) + +KDE_TRY_TIFFLIB(tiff, [], + KDE_TRY_TIFFLIB(tiff34)) + +AC_SUBST(LIBTIFF) +]) + +AC_DEFUN([KDE_FIND_LIBEXR], +[ +AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) +AC_REQUIRE([AC_FIND_ZLIB]) +AC_CACHE_VAL(ac_cv_libexr, +[ + if test -z "$PKG_CONFIG"; then + AC_PATH_PROG(PKG_CONFIG, pkg-config, no) + fi + + AC_MSG_CHECKING([for OpenEXR libraries]) + + if test "$PKG_CONFIG" = "no" ; then + AC_MSG_RESULT(no) + echo "*** The pkg-config script could not be found. Make sure it is" + echo "*** in your path, or set the PKG_CONFIG environment variable" + echo "*** to the full path to pkg-config." + echo "*** Or see http://www.freedesktop.org/software/pkgconfig to get pkg-config." + else + if !(`$PKG_CONFIG --exists OpenEXR`) ; then + AC_MSG_RESULT(no) + EXRSTATUS=no + else + if !(`$PKG_CONFIG --atleast-version="1.1.1" OpenEXR`) ; then + AC_MSG_RESULT(no) + EXRSTATUS=old + else + kde_save_LIBS="$LIBS" + LIBS="$LIBS $all_libraries $USER_LDFLAGS `pkg-config --libs OpenEXR` $LIBZ" + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + kde_save_CXXFLAGS="$CXXFLAGS" + EXR_FLAGS=`$PKG_CONFIG --cflags OpenEXR` + CXXFLAGS="$CXXFLAGS $all_includes $USER_INCLUDES $EXR_FLAGS" + + AC_TRY_LINK(dnl + [ + #include + ], + [ + using namespace Imf; + RgbaInputFile file ("dummy"); + return 0; + ], + eval "ac_cv_libexr='`pkg-config --libs OpenEXR`'", + eval "ac_cv_libexr=no" + ) + LIBS="$kde_save_LIBS" + CXXFLAGS="$kde_save_CXXFLAGS" + AC_LANG_RESTORE + ])dnl + if eval "test ! \"`echo $ac_cv_libexr`\" = no"; then + AC_DEFINE_UNQUOTED(HAVE_EXR, 1, [Define if you have OpenEXR]) + LIB_EXR="$ac_cv_libexr" + AC_MSG_RESULT($ac_cv_libexr) + else + AC_MSG_RESULT(no) + LIB_EXR="" + fi + fi + fi + fi + AC_SUBST(LIB_EXR) + AC_SUBST(EXR_FLAGS) +]) + + + +AC_DEFUN([AC_FIND_PNG], +[ +AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) +AC_REQUIRE([AC_FIND_ZLIB]) +AC_MSG_CHECKING([for libpng]) +AC_CACHE_VAL(ac_cv_lib_png, +[ +kde_save_LIBS="$LIBS" +if test "x$kde_use_qt_emb" != "xyes" && test "x$kde_use_qt_mac" != "xyes" && test "x$kde_use_qt_win" != "xyes"; then +LIBS="$LIBS $all_libraries $USER_LDFLAGS -lpng $LIBZ -lm -lX11 $LIBSOCKET" +else +LIBS="$LIBS $all_libraries $USER_LDFLAGS -lpng $LIBZ -lm" +fi +kde_save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $all_includes $USER_INCLUDES" + +AC_TRY_LINK(dnl + [ + #include + ], + [ + png_structp png_ptr = png_create_read_struct( /* image ptr */ + PNG_LIBPNG_VER_STRING, 0, 0, 0 ); + return( png_ptr != 0 ); + ], + eval "ac_cv_lib_png='-lpng $LIBZ -lm'", + eval "ac_cv_lib_png=no" +) +LIBS="$kde_save_LIBS" +CFLAGS="$kde_save_CFLAGS" +])dnl +if eval "test ! \"`echo $ac_cv_lib_png`\" = no"; then + AC_DEFINE_UNQUOTED(HAVE_LIBPNG, 1, [Define if you have libpng]) + LIBPNG="$ac_cv_lib_png" + AC_SUBST(LIBPNG) + AC_MSG_RESULT($ac_cv_lib_png) +else + AC_MSG_RESULT(no) + LIBPNG="" + AC_SUBST(LIBPNG) +fi +]) + + +AC_DEFUN([AC_FIND_JASPER], +[ +AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) +AC_REQUIRE([AC_FIND_JPEG]) +AC_MSG_CHECKING([for jasper]) +AC_CACHE_VAL(ac_cv_jasper, +[ +kde_save_LIBS="$LIBS" +LIBS="$LIBS $all_libraries $USER_LDFLAGS -ljasper $LIBJPEG -lm" +kde_save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $all_includes $USER_INCLUDES" + +AC_TRY_LINK(dnl + [ + #include + ], + [ + return( jas_init() ); + ], + eval "ac_cv_jasper='-ljasper $LIBJPEG -lm'", + eval "ac_cv_jasper=no" +) +LIBS="$kde_save_LIBS" +CFLAGS="$kde_save_CFLAGS" +])dnl +if eval "test ! \"`echo $ac_cv_jasper`\" = no"; then + AC_DEFINE_UNQUOTED(HAVE_JASPER, 1, [Define if you have jasper]) + LIB_JASPER="$ac_cv_jasper" + AC_MSG_RESULT($ac_cv_jasper) +else + AC_MSG_RESULT(no) + LIB_JASPER="" +fi +AC_SUBST(LIB_JASPER) +]) + +AC_DEFUN([AC_CHECK_BOOL], +[ + AC_DEFINE_UNQUOTED(HAVE_BOOL, 1, [You _must_ have bool]) +]) + +AC_DEFUN([AC_CHECK_GNU_EXTENSIONS], +[ +AC_MSG_CHECKING(if you need GNU extensions) +AC_CACHE_VAL(ac_cv_gnu_extensions, +[ +cat > conftest.c << EOF +#include + +#ifdef __GNU_LIBRARY__ +yes +#endif +EOF + +if (eval "$ac_cpp conftest.c") 2>&5 | + egrep "yes" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_gnu_extensions=yes +else + ac_cv_gnu_extensions=no +fi +]) + +AC_MSG_RESULT($ac_cv_gnu_extensions) +if test "$ac_cv_gnu_extensions" = "yes"; then + AC_DEFINE_UNQUOTED(_GNU_SOURCE, 1, [Define if you need to use the GNU extensions]) +fi +]) + +AC_DEFUN([KDE_CHECK_COMPILER_FLAG], +[ +AC_MSG_CHECKING([whether $CXX supports -$1]) +kde_cache=`echo $1 | sed 'y% .=/+-,%____p__%'` +AC_CACHE_VAL(kde_cv_prog_cxx_$kde_cache, +[ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -$1" + AC_TRY_LINK([],[ return 0; ], [eval "kde_cv_prog_cxx_$kde_cache=yes"], []) + CXXFLAGS="$save_CXXFLAGS" + AC_LANG_RESTORE +]) +if eval "test \"`echo '$kde_cv_prog_cxx_'$kde_cache`\" = yes"; then + AC_MSG_RESULT(yes) + : + $2 +else + AC_MSG_RESULT(no) + : + $3 +fi +]) + +AC_DEFUN([KDE_CHECK_C_COMPILER_FLAG], +[ +AC_MSG_CHECKING([whether $CC supports -$1]) +kde_cache=`echo $1 | sed 'y% .=/+-,%____p__%'` +AC_CACHE_VAL(kde_cv_prog_cc_$kde_cache, +[ + AC_LANG_SAVE + AC_LANG_C + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -$1" + AC_TRY_LINK([],[ return 0; ], [eval "kde_cv_prog_cc_$kde_cache=yes"], []) + CFLAGS="$save_CFLAGS" + AC_LANG_RESTORE +]) +if eval "test \"`echo '$kde_cv_prog_cc_'$kde_cache`\" = yes"; then + AC_MSG_RESULT(yes) + : + $2 +else + AC_MSG_RESULT(no) + : + $3 +fi +]) + + +dnl AC_REMOVE_FORBIDDEN removes forbidden arguments from variables +dnl use: AC_REMOVE_FORBIDDEN(CC, [-forbid -bad-option whatever]) +dnl it's all white-space separated +AC_DEFUN([AC_REMOVE_FORBIDDEN], +[ __val=$$1 + __forbid=" $2 " + if test -n "$__val"; then + __new="" + ac_save_IFS=$IFS + IFS=" " + for i in $__val; do + case "$__forbid" in + *" $i "*) AC_MSG_WARN([found forbidden $i in $1, removing it]) ;; + *) # Careful to not add spaces, where there were none, because otherwise + # libtool gets confused, if we change e.g. CXX + if test -z "$__new" ; then __new=$i ; else __new="$__new $i" ; fi ;; + esac + done + IFS=$ac_save_IFS + $1=$__new + fi +]) + + +AC_DEFUN([KDE_CHECK_FOR_BAD_COMPILER], +[ + AC_MSG_CHECKING([whether $CC is blacklisted]) + + dnl In theory we have tu run this test against $CC and $CXX + dnl in C and in C++ mode, because its perfectly legal for + dnl the user to mix compiler versions, since C has a defined + dnl ABI. + dnl + dnl For now, we assume the user is not on crack. + + AC_TRY_COMPILE([ +#ifdef __GNUC__ +#if __GNUC__ == 4 && __GNUC_MINOR__ == 0 && __GNUC_PATCHLEVEL__ == 0 +choke me +#endif +#endif +], , + kde_bad_compiler=no, + kde_bad_compiler=yes +) + + AC_MSG_RESULT($kde_bad_compiler) + +if test "$kde_bad_compiler" = "yes"; then + AC_MSG_ERROR([ + +This particular compiler version is blacklisted because it +is known to miscompile KDE. Please use a newer version, or +if that is not yet available, choose an older version. + +Please do not report a bug or bother us reporting this +configure error. We know about it, and we introduced +it by intention to avoid untraceable bugs or crashes in KDE. + +]) +fi + +]) + + +AC_DEFUN([KDE_CHECK_FOR_OPT_NOINLINE_MATCH], +[ + AC_CACHE_CHECK([whether system headers can cope with -O2 -fno-inline], + kde_cv_opt_noinline_match, + [ + kde_cv_opt_noinline_match=irrelevant + dnl if we don't use both -O2 and -fno-inline, this check is moot + if echo "$CFLAGS" | grep -e -O2 >/dev/null 2>/dev/null \ + && echo "$CFLAGS" | grep -e -fno-inline >/dev/null 2>/dev/null ; then + + ac_cflags_save="$CFLAGS" + CFLAGS="$CFLAGS -D_USE_GNU" + + AC_TRY_LINK([ + #include +], [ const char *pt, *et; + et = __extension__ ({ char __a0, __a1, __a2; (__builtin_constant_p ( ";," ) && ((size_t)(const void *)(( ";," )+ 1) - (size_t)(const void *)( ";," ) == 1) ? ((__a0 =((__const char *) ( ";," ))[0], __a0 == '\0') ? ((void) ( pt ),((void *)0) ) : ((__a1 = ((__const char *) ( ";," ))[1], __a1== '\0') ? (__extension__ (__builtin_constant_p ( __a0 ) && ( __a0 ) == '\0' ? (char *) __rawmemchr ( pt , __a0) : strchr( pt , __a0 ))) : ((__a2 = ((__const char *) ( ";," ))[2], __a2 == '\0') ? __strpbrk_c2 ( pt , __a0, __a1) :(((__const char *) ( ";," ))[3] == '\0' ? __strpbrk_c3 ( pt ,__a0, __a1, __a2): strpbrk ( pt , ";," ))))) : strpbrk ( pt , ";," )); }) ; +], + kde_cv_opt_noinline_match=yes, + kde_cv_opt_noinline_match=no + ) + + CFLAGS="$ac_cflags_save" + fi + ]) +]) + + +dnl AC_VALIDIFY_CXXFLAGS checks for forbidden flags the user may have given +AC_DEFUN([AC_VALIDIFY_CXXFLAGS], +[dnl +if test "x$kde_use_qt_emb" != "xyes"; then + AC_REMOVE_FORBIDDEN(CXX, [-fno-rtti -rpath]) + AC_REMOVE_FORBIDDEN(CXXFLAGS, [-fno-rtti -rpath]) +else + AC_REMOVE_FORBIDDEN(CXX, [-rpath]) + AC_REMOVE_FORBIDDEN(CXXFLAGS, [-rpath]) +fi +]) + +AC_DEFUN([AC_CHECK_COMPILERS], +[ + AC_ARG_ENABLE(debug, + AC_HELP_STRING([--enable-debug=ARG],[enables debug symbols (yes|no|full) [default=no]]), + [ + case $enableval in + yes) + kde_use_debug_code="yes" + kde_use_debug_define=no + ;; + full) + kde_use_debug_code="full" + kde_use_debug_define=no + ;; + *) + kde_use_debug_code="no" + kde_use_debug_define=yes + ;; + esac + ], + [kde_use_debug_code="no" + kde_use_debug_define=no + ]) + + dnl Just for configure --help + AC_ARG_ENABLE(dummyoption, + AC_HELP_STRING([--disable-debug], + [disables debug output and debug symbols [default=no]]), + [],[]) + + AC_ARG_ENABLE(strict, + AC_HELP_STRING([--enable-strict], + [compiles with strict compiler options (may not work!)]), + [ + if test $enableval = "no"; then + kde_use_strict_options="no" + else + kde_use_strict_options="yes" + fi + ], [kde_use_strict_options="no"]) + + AC_ARG_ENABLE(warnings,AC_HELP_STRING([--disable-warnings],[disables compilation with -Wall and similar]), + [ + if test $enableval = "no"; then + kde_use_warnings="no" + else + kde_use_warnings="yes" + fi + ], [kde_use_warnings="yes"]) + + dnl enable warnings for debug build + if test "$kde_use_debug_code" != "no"; then + kde_use_warnings=yes + fi + + AC_ARG_ENABLE(profile,AC_HELP_STRING([--enable-profile],[creates profiling infos [default=no]]), + [kde_use_profiling=$enableval], + [kde_use_profiling="no"] + ) + + dnl this prevents stupid AC_PROG_CC to add "-g" to the default CFLAGS + CFLAGS=" $CFLAGS" + + AC_PROG_CC + + AC_PROG_CPP + + if test "$GCC" = "yes"; then + if test "$kde_use_debug_code" != "no"; then + if test $kde_use_debug_code = "full"; then + CFLAGS="-g3 -fno-inline $CFLAGS" + else + CFLAGS="-g -O2 -fno-schedule-insns -fno-inline $CFLAGS" + fi + else + CFLAGS="-O2 $CFLAGS" + fi + fi + + if test "$kde_use_debug_define" = "yes"; then + CFLAGS="-DNDEBUG $CFLAGS" + fi + + + case "$host" in + *-*-sysv4.2uw*) CFLAGS="-D_UNIXWARE $CFLAGS";; + *-*-sysv5uw7*) CFLAGS="-D_UNIXWARE7 $CFLAGS";; + esac + + if test -z "$LDFLAGS" && test "$kde_use_debug_code" = "no" && test "$GCC" = "yes"; then + LDFLAGS="" + fi + + CXXFLAGS=" $CXXFLAGS" + + AC_PROG_CXX + + KDE_CHECK_FOR_BAD_COMPILER + + if test "$GXX" = "yes" || test "$CXX" = "KCC"; then + if test "$kde_use_debug_code" != "no"; then + if test "$CXX" = "KCC"; then + CXXFLAGS="+K0 -Wall -pedantic -W -Wpointer-arith -Wwrite-strings $CXXFLAGS" + else + if test "$kde_use_debug_code" = "full"; then + CXXFLAGS="-g3 -fno-inline $CXXFLAGS" + else + CXXFLAGS="-g -O2 -fno-schedule-insns -fno-inline $CXXFLAGS" + fi + fi + KDE_CHECK_COMPILER_FLAG(fno-builtin,[CXXFLAGS="-fno-builtin $CXXFLAGS"]) + + dnl convenience compiler flags + KDE_CHECK_COMPILER_FLAG(Woverloaded-virtual, [WOVERLOADED_VIRTUAL="-Woverloaded-virtual"], [WOVERLOADED_VRITUAL=""]) + AC_SUBST(WOVERLOADED_VIRTUAL) + else + if test "$CXX" = "KCC"; then + CXXFLAGS="+K3 $CXXFLAGS" + else + CXXFLAGS="-O2 $CXXFLAGS" + fi + fi + fi + + if test "$kde_use_debug_define" = "yes"; then + CXXFLAGS="-DNDEBUG -DNO_DEBUG $CXXFLAGS" + fi + + if test "$kde_use_profiling" = "yes"; then + KDE_CHECK_COMPILER_FLAG(pg, + [ + CFLAGS="-pg $CFLAGS" + CXXFLAGS="-pg $CXXFLAGS" + ]) + fi + + if test "$kde_use_warnings" = "yes"; then + if test "$GCC" = "yes"; then + CXXFLAGS="-Wall -W -Wpointer-arith $CXXFLAGS" + case $host in + *-*-linux-gnu) + CFLAGS="-std=iso9899:1990 -W -Wall -Wchar-subscripts -Wshadow -Wpointer-arith -Wmissing-prototypes -Wwrite-strings -D_XOPEN_SOURCE=500 -D_BSD_SOURCE $CFLAGS" + CXXFLAGS="-ansi -D_XOPEN_SOURCE=500 -D_BSD_SOURCE -Wcast-align -Wconversion -Wchar-subscripts $CXXFLAGS" + KDE_CHECK_COMPILER_FLAG(Wmissing-format-attribute, [CXXFLAGS="$CXXFLAGS -Wformat-security -Wmissing-format-attribute"]) + KDE_CHECK_C_COMPILER_FLAG(Wmissing-format-attribute, [CFLAGS="$CFLAGS -Wformat-security -Wmissing-format-attribute"]) + ;; + esac + KDE_CHECK_COMPILER_FLAG(Wundef,[CXXFLAGS="-Wundef $CXXFLAGS"]) + KDE_CHECK_COMPILER_FLAG(Wno-long-long,[CXXFLAGS="-Wno-long-long $CXXFLAGS"]) + dnl ### FIXME: revert for KDE 4 + KDE_CHECK_COMPILER_FLAG(Wno-non-virtual-dtor,[CXXFLAGS="$CXXFLAGS -Wno-non-virtual-dtor"]) + fi + fi + + if test "$GXX" = "yes" && test "$kde_use_strict_options" = "yes"; then + CXXFLAGS="-Wcast-qual -Wshadow -Wcast-align $CXXFLAGS" + fi + + AC_ARG_ENABLE(pch, + AC_HELP_STRING([--enable-pch], + [enables precompiled header support (currently only KCC or gcc >=3.4+unsermake) [default=no]]), + [ kde_use_pch=$enableval ],[ kde_use_pch=no ]) + + HAVE_GCC_VISIBILITY=0 + AC_SUBST([HAVE_GCC_VISIBILITY]) + + if test "$GXX" = "yes"; then + gcc_no_reorder_blocks=NO + KDE_CHECK_COMPILER_FLAG(fno-reorder-blocks,[gcc_no_reorder_blocks=YES]) + if test $kde_use_debug_code != "no" && \ + test $kde_use_debug_code != "full" && \ + test "YES" = "$gcc_no_reorder_blocks" ; then + CXXFLAGS="$CXXFLAGS -fno-reorder-blocks" + CFLAGS="$CFLAGS -fno-reorder-blocks" + fi + KDE_CHECK_COMPILER_FLAG(fno-exceptions,[CXXFLAGS="$CXXFLAGS -fno-exceptions"]) + KDE_CHECK_COMPILER_FLAG(fno-check-new, [CXXFLAGS="$CXXFLAGS -fno-check-new"]) + KDE_CHECK_COMPILER_FLAG(fno-common, [CXXFLAGS="$CXXFLAGS -fno-common"]) + KDE_CHECK_COMPILER_FLAG(fexceptions, [USE_EXCEPTIONS="-fexceptions"], USE_EXCEPTIONS= ) + ENABLE_PERMISSIVE_FLAG="-fpermissive" + + if test "$kde_use_pch" = "yes"; then + AC_MSG_CHECKING(whether gcc supports precompiling c header files) + echo >conftest.h + if $CC -x c-header conftest.h >/dev/null 2>/dev/null; then + kde_gcc_supports_pch=yes + AC_MSG_RESULT(yes) + else + kde_gcc_supports_pch=no + AC_MSG_RESULT(no) + fi + if test "$kde_gcc_supports_pch" = "yes"; then + AC_MSG_CHECKING(whether gcc supports precompiling c++ header files) + if $CXX -x c++-header conftest.h >/dev/null 2>/dev/null; then + kde_gcc_supports_pch=yes + AC_MSG_RESULT(yes) + else + kde_gcc_supports_pch=no + AC_MSG_RESULT(no) + fi + fi + rm -f conftest.h conftest.h.gch + fi + + KDE_CHECK_FOR_OPT_NOINLINE_MATCH + if test "x$kde_cv_opt_noinline_match" = "xno" ; then + CFLAGS="`echo "$CFLAGS" | sed "s/ -fno-inline//"`" + fi + fi + AM_CONDITIONAL(unsermake_enable_pch, test "$kde_use_pch" = "yes" && test "$kde_gcc_supports_pch" = "yes") + if test "$CXX" = "KCC"; then + dnl unfortunately we currently cannot disable exception support in KCC + dnl because doing so is binary incompatible and Qt by default links with exceptions :-( + dnl KDE_CHECK_COMPILER_FLAG(-no_exceptions,[CXXFLAGS="$CXXFLAGS --no_exceptions"]) + dnl KDE_CHECK_COMPILER_FLAG(-exceptions, [USE_EXCEPTIONS="--exceptions"], USE_EXCEPTIONS= ) + + if test "$kde_use_pch" = "yes"; then + dnl TODO: support --pch-dir! + KDE_CHECK_COMPILER_FLAG(-pch,[CXXFLAGS="$CXXFLAGS --pch"]) + dnl the below works (but the dir must exist), but it's + dnl useless for a whole package. + dnl The are precompiled headers for each source file, so when compiling + dnl from scratch, it doesn't make a difference, and they take up + dnl around ~5Mb _per_ sourcefile. + dnl KDE_CHECK_COMPILER_FLAG(-pch_dir /tmp, + dnl [CXXFLAGS="$CXXFLAGS --pch_dir `pwd`/pcheaders"]) + fi + dnl this flag controls inlining. by default KCC inlines in optimisation mode + dnl all implementations that are defined inside the class {} declaration. + dnl because of templates-compatibility with broken gcc compilers, this + dnl can cause excessive inlining. This flag limits it to a sane level + KDE_CHECK_COMPILER_FLAG(-inline_keyword_space_time=6,[CXXFLAGS="$CXXFLAGS --inline_keyword_space_time=6"]) + KDE_CHECK_COMPILER_FLAG(-inline_auto_space_time=2,[CXXFLAGS="$CXXFLAGS --inline_auto_space_time=2"]) + KDE_CHECK_COMPILER_FLAG(-inline_implicit_space_time=2.0,[CXXFLAGS="$CXXFLAGS --inline_implicit_space_time=2.0"]) + KDE_CHECK_COMPILER_FLAG(-inline_generated_space_time=2.0,[CXXFLAGS="$CXXFLAGS --inline_generated_space_time=2.0"]) + dnl Some source files are shared between multiple executables + dnl (or libraries) and some of those need template instantiations. + dnl In that case KCC needs to compile those sources with + dnl --one_instantiation_per_object. To make it easy for us we compile + dnl _all_ objects with that flag (--one_per is a shorthand). + KDE_CHECK_COMPILER_FLAG(-one_per, [CXXFLAGS="$CXXFLAGS --one_per"]) + fi + AC_SUBST(USE_EXCEPTIONS) + dnl obsolete macro - provided to keep things going + USE_RTTI= + AC_SUBST(USE_RTTI) + + case "$host" in + *-*-irix*) test "$GXX" = yes && CXXFLAGS="-D_LANGUAGE_C_PLUS_PLUS -D__LANGUAGE_C_PLUS_PLUS $CXXFLAGS" ;; + *-*-sysv4.2uw*) CXXFLAGS="-D_UNIXWARE $CXXFLAGS";; + *-*-sysv5uw7*) CXXFLAGS="-D_UNIXWARE7 $CXXFLAGS";; + *-*-solaris*) + if test "$GXX" = yes; then + libstdcpp=`$CXX -print-file-name=libstdc++.so` + if test ! -f $libstdcpp; then + AC_MSG_ERROR([You've compiled gcc without --enable-shared. This doesn't work with KDE. Please recompile gcc with --enable-shared to receive a libstdc++.so]) + fi + fi + ;; + esac + + AC_VALIDIFY_CXXFLAGS + + AC_PROG_CXXCPP + + if test "$GCC" = yes; then + NOOPT_CFLAGS=-O0 + fi + KDE_CHECK_COMPILER_FLAG(O0,[NOOPT_CXXFLAGS=-O0]) + + AC_ARG_ENABLE(coverage, + AC_HELP_STRING([--enable-coverage],[use gcc coverage testing]), [ + if test "$am_cv_CC_dependencies_compiler_type" = "gcc3"; then + ac_coverage_compiler="-fprofile-arcs -ftest-coverage" + ac_coverage_linker="-lgcc" + elif test "$am_cv_CC_dependencies_compiler_type" = "gcc"; then + ac_coverage_compiler="-fprofile-arcs -ftest-coverage" + ac_coverage_linker="" + else + AC_MSG_ERROR([coverage with your compiler is not supported]) + fi + CFLAGS="$CFLAGS $ac_coverage_compiler" + CXXFLAGS="$CXXFLAGS $ac_coverage_compiler" + LDFLAGS="$LDFLAGS $ac_coverage_linker" + ]) + + AC_SUBST(NOOPT_CXXFLAGS) + AC_SUBST(NOOPT_CFLAGS) + AC_SUBST(ENABLE_PERMISSIVE_FLAG) + + KDE_CHECK_NEW_LDFLAGS + KDE_CHECK_FINAL + KDE_CHECK_CLOSURE + KDE_CHECK_NMCHECK + + ifdef([AM_DEPENDENCIES], AC_REQUIRE([KDE_ADD_DEPENDENCIES]), []) +]) + +AC_DEFUN([KDE_CHECK_VISIBILITY_GCC_BUG], + [ + AC_CACHE_CHECK([for gcc -fvisibility-inlines-hidden bug], kde_cv_val_gcc_visibility_bug, + [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + + safe_CXXFLAGS=$CXXFLAGS + safe_LDFLAGS=$LDFLAGS + CXXFLAGS="$CXXFLAGS -fPIC -fvisibility-inlines-hidden -O0" + LDFLAGS="$LDFLAGS -shared -fPIC" + + AC_TRY_LINK( + [ + /* http://gcc.gnu.org/bugzilla/show_bug.cgi?id=19664 */ + #include + int some_function( void ) __attribute__ ((visibility("default"))); + int some_function( void ) + { + std::string s("blafasel"); + return 0; + } + ], [/* elvis is alive */], + kde_cv_val_gcc_visibility_bug=no, kde_cv_val_gcc_visibility_bug=yes) + + CXXFLAGS=$safe_CXXFLAGS + LDFLAGS=$safe_LDFLAGS + AC_LANG_RESTORE + ] + ) + + if test x$kde_cv_val_gcc_visibility_bug = xno; then + CXXFLAGS="$CXXFLAGS -fvisibility-inlines-hidden" + fi + ] +) + +AC_DEFUN([KDE_ENABLE_HIDDEN_VISIBILITY], +[ + AC_BEFORE([AC_PATH_QT_1_3], [KDE_ENABLE_HIDDEN_VISIBILITY]) + + AC_MSG_CHECKING([grepping for visibility push/pop in headers]) + + if test "x$GXX" = "xyes"; then + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + AC_EGREP_CPP( + [GCC visibility push], + [ #include + ], + [ + AC_MSG_RESULT(yes) + kde_stdc_visibility_patched=yes ], + [ + AC_MSG_RESULT(no) + AC_MSG_WARN([Your libstdc++ doesn't appear to be patched for + visibility support. Disabling -fvisibility=hidden]) + + kde_stdc_visibility_patched=no ]) + + AC_LANG_RESTORE + + kde_have_gcc_visibility=no + KDE_CHECK_COMPILER_FLAG(fvisibility=hidden, + [ + kde_have_gcc_visibility=yes + dnl the whole toolchain is just a mess, gcc is just too buggy + dnl to handle STL with visibility enabled. Lets reconsider + dnl when gcc 4.2 is out or when things get fixed in the compiler. + dnl Contact mueller@kde.org for details. + AC_ARG_ENABLE(gcc-hidden-visibility, + AC_HELP_STRING([--enable-gcc-hidden-visibility],[toolchain hidden visibility [default=no]]), + [kde_have_gcc_visibility=$enableval], + [kde_have_gcc_visibility=no]) + + AC_CACHE_CHECK([if Qt is patched for -fvisibility], kde_cv_val_qt_gcc_visibility_patched, + [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + + safe_CXXFLAGS=$CXXFLAGS + CXXFLAGS="$CXXFLAGS $all_includes" + + AC_TRY_COMPILE( + [ +#include +#if Q_EXPORT - 0 != 0 +/* if this compiles, then Q_EXPORT is undefined */ +/* if Q_EXPORT is nonempty, this will break compilation */ +#endif + ], [/* elvis is alive */], + kde_cv_val_qt_gcc_visibility_patched=no, kde_cv_val_qt_gcc_visibility_patched=yes) + + CXXFLAGS=$safe_CXXFLAGS + AC_LANG_RESTORE + ] + ) + + if test x$kde_have_gcc_visibility = "xyes" && test x$kde_stdc_visibility_patched = "xyes" && test x$kde_cv_val_qt_gcc_visibility_patched = "xyes"; then + CXXFLAGS="$CXXFLAGS -fvisibility=hidden" + KDE_CHECK_VISIBILITY_GCC_BUG + HAVE_GCC_VISIBILITY=1 + AC_DEFINE_UNQUOTED(__KDE_HAVE_GCC_VISIBILITY, "$HAVE_GCC_VISIBILITY", [define to 1 if -fvisibility is supported]) + fi + ]) + fi +]) + +AC_DEFUN([KDE_ADD_DEPENDENCIES], +[ + [A]M_DEPENDENCIES(CC) + [A]M_DEPENDENCIES(CXX) +]) + +dnl just a wrapper to clean up configure.in +AC_DEFUN([KDE_PROG_LIBTOOL], +[ +AC_REQUIRE([AC_CHECK_COMPILERS]) +AC_REQUIRE([AC_ENABLE_SHARED]) +AC_REQUIRE([AC_ENABLE_STATIC]) + +AC_REQUIRE([AC_LIBTOOL_DLOPEN]) +AC_REQUIRE([KDE_CHECK_LIB64]) + +AC_OBJEXT +AC_EXEEXT + +AM_PROG_LIBTOOL +AC_LIBTOOL_CXX + +LIBTOOL_SHELL="/bin/sh ./libtool" +# LIBTOOL="$LIBTOOL --silent" +KDE_PLUGIN="-avoid-version -module -no-undefined \$(KDE_NO_UNDEFINED) \$(KDE_RPATH) \$(KDE_MT_LDFLAGS)" +AC_SUBST(KDE_PLUGIN) + +# This hack ensures that libtool creates shared libs for kunittest plugins. By default check_LTLIBRARIES makes static libs. +KDE_CHECK_PLUGIN="\$(KDE_PLUGIN) -rpath \$(libdir)" +AC_SUBST(KDE_CHECK_PLUGIN) + +# we patch configure quite some so we better keep that consistent for incremental runs +AC_SUBST(AUTOCONF,'$(SHELL) $(top_srcdir)/admin/cvs.sh configure || touch configure') +]) + +AC_DEFUN([KDE_CHECK_LIB64], +[ + AC_ARG_ENABLE(libsuffix, + AC_HELP_STRING([--enable-libsuffix], + [/lib directory suffix (64,32,none,auto[=default])]), + kdelibsuff=$enableval, kdelibsuff="auto") + + if test "$kdelibsuff" = "auto"; then + +cat > conftest.c << EOF +#include +int main() { + return 0; +} +EOF + kdelibsuff=`$CC conftest.c -o conftest.out; ldd conftest.out |sed -ne '/libc.so/{ + s,.*/lib\([[^\/]]*\)/.*,\1, + p +}'` + rm -rf conftest.* + fi + + if test "$kdelibsuff" = "no" || test "$kdelibsuff" = "none"; then + kdelibsuff= + fi + if test -z "$kdelibsuff"; then + AC_MSG_RESULT([not using lib directory suffix]) + AC_DEFINE(KDELIBSUFF, [""], Suffix for lib directories) + else + if test "$libdir" = '${exec_prefix}/lib'; then + libdir="$libdir${kdelibsuff}" + AC_SUBST([libdir], ["$libdir"]) dnl ugly hack for lib64 platforms + fi + AC_DEFINE_UNQUOTED(KDELIBSUFF, ["${kdelibsuff}"], Suffix for lib directories) + AC_MSG_RESULT([using lib directory suffix $kdelibsuff]) + fi +]) + +AC_DEFUN([KDE_CHECK_TYPES], +[ AC_CHECK_SIZEOF(int, 4)dnl + AC_CHECK_SIZEOF(short)dnl + AC_CHECK_SIZEOF(long, 4)dnl + AC_CHECK_SIZEOF(char *, 4)dnl +])dnl + +dnl Not used - kept for compat only? +AC_DEFUN([KDE_DO_IT_ALL], +[ +AC_CANONICAL_SYSTEM +AC_ARG_PROGRAM +AM_INIT_AUTOMAKE($1, $2) +AM_DISABLE_LIBRARIES +AC_PREFIX_DEFAULT(${KDEDIR:-/usr/local/kde}) +AC_CHECK_COMPILERS +KDE_PROG_LIBTOOL +AM_KDE_WITH_NLS +AC_PATH_KDE +]) + +AC_DEFUN([AC_CHECK_RPATH], +[ +AC_MSG_CHECKING(for rpath) +AC_ARG_ENABLE(rpath, + AC_HELP_STRING([--disable-rpath],[do not use the rpath feature of ld]), + USE_RPATH=$enableval, USE_RPATH=yes) + +if test -z "$KDE_RPATH" && test "$USE_RPATH" = "yes"; then + + KDE_RPATH="-R \$(libdir)" + + if test "$kde_libraries" != "$libdir"; then + KDE_RPATH="$KDE_RPATH -R \$(kde_libraries)" + fi + + if test -n "$qt_libraries"; then + KDE_RPATH="$KDE_RPATH -R \$(qt_libraries)" + fi + dnl $x_libraries is set to /usr/lib in case + if test -n "$X_LDFLAGS"; then + X_RPATH="-R \$(x_libraries)" + KDE_RPATH="$KDE_RPATH $X_RPATH" + fi + if test -n "$KDE_EXTRA_RPATH"; then + KDE_RPATH="$KDE_RPATH \$(KDE_EXTRA_RPATH)" + fi +fi +AC_SUBST(KDE_EXTRA_RPATH) +AC_SUBST(KDE_RPATH) +AC_SUBST(X_RPATH) +AC_MSG_RESULT($USE_RPATH) +]) + +dnl Check for the type of the third argument of getsockname +AC_DEFUN([AC_CHECK_SOCKLEN_T], +[ + AC_MSG_CHECKING(for socklen_t) + AC_CACHE_VAL(kde_cv_socklen_t, + [ + AC_LANG_PUSH(C++) + kde_cv_socklen_t=no + AC_TRY_COMPILE([ + #include + #include + ], + [ + socklen_t len; + getpeername(0,0,&len); + ], + [ + kde_cv_socklen_t=yes + kde_cv_socklen_t_equiv=socklen_t + ]) + AC_LANG_POP(C++) + ]) + AC_MSG_RESULT($kde_cv_socklen_t) + if test $kde_cv_socklen_t = no; then + AC_MSG_CHECKING([for socklen_t equivalent for socket functions]) + AC_CACHE_VAL(kde_cv_socklen_t_equiv, + [ + kde_cv_socklen_t_equiv=int + AC_LANG_PUSH(C++) + for t in int size_t unsigned long "unsigned long"; do + AC_TRY_COMPILE([ + #include + #include + ], + [ + $t len; + getpeername(0,0,&len); + ], + [ + kde_cv_socklen_t_equiv="$t" + break + ]) + done + AC_LANG_POP(C++) + ]) + AC_MSG_RESULT($kde_cv_socklen_t_equiv) + fi + AC_DEFINE_UNQUOTED(kde_socklen_t, $kde_cv_socklen_t_equiv, + [type to use in place of socklen_t if not defined]) + AC_DEFINE_UNQUOTED(ksize_t, $kde_cv_socklen_t_equiv, + [type to use in place of socklen_t if not defined (deprecated, use kde_socklen_t)]) +]) + +dnl This is a merge of some macros out of the gettext aclocal.m4 +dnl since we don't need anything, I took the things we need +dnl the copyright for them is: +dnl > +dnl Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc. +dnl This Makefile.in is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without +dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A +dnl PARTICULAR PURPOSE. +dnl > +dnl for this file it is relicensed under LGPL + +AC_DEFUN([AM_KDE_WITH_NLS], + [ + dnl If we use NLS figure out what method + + AM_PATH_PROG_WITH_TEST_KDE(MSGFMT, msgfmt, + [test -n "`$ac_dir/$ac_word --version 2>&1 | grep 'GNU gettext'`"], msgfmt) + AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT) + + if test -z "`$GMSGFMT --version 2>&1 | grep 'GNU gettext'`"; then + AC_MSG_RESULT([found msgfmt program is not GNU msgfmt; ignore it]) + GMSGFMT=":" + fi + MSGFMT=$GMSGFMT + AC_SUBST(GMSGFMT) + AC_SUBST(MSGFMT) + + AM_PATH_PROG_WITH_TEST_KDE(XGETTEXT, xgettext, + [test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"], :) + + dnl Test whether we really found GNU xgettext. + if test "$XGETTEXT" != ":"; then + dnl If it is no GNU xgettext we define it as : so that the + dnl Makefiles still can work. + if $XGETTEXT --omit-header /dev/null 2> /dev/null; then + : ; + else + AC_MSG_RESULT( + [found xgettext programs is not GNU xgettext; ignore it]) + XGETTEXT=":" + fi + fi + AC_SUBST(XGETTEXT) + + ]) + +# Search path for a program which passes the given test. +# Ulrich Drepper , 1996. + +# serial 1 +# Stephan Kulow: I appended a _KDE against name conflicts + +dnl AM_PATH_PROG_WITH_TEST_KDE(VARIABLE, PROG-TO-CHECK-FOR, +dnl TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]]) +AC_DEFUN([AM_PATH_PROG_WITH_TEST_KDE], +[# Extract the first word of "$2", so it can be a program name with args. +set dummy $2; ac_word=[$]2 +AC_MSG_CHECKING([for $ac_word]) +AC_CACHE_VAL(ac_cv_path_$1, +[case "[$]$1" in + /*) + ac_cv_path_$1="[$]$1" # Let the user override the test with a path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in ifelse([$5], , $PATH, [$5]); do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if [$3]; then + ac_cv_path_$1="$ac_dir/$ac_word" + break + fi + fi + done + IFS="$ac_save_ifs" +dnl If no 4th arg is given, leave the cache variable unset, +dnl so AC_PATH_PROGS will keep looking. +ifelse([$4], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4" +])dnl + ;; +esac])dnl +$1="$ac_cv_path_$1" +if test -n "[$]$1"; then + AC_MSG_RESULT([$]$1) +else + AC_MSG_RESULT(no) +fi +AC_SUBST($1)dnl +]) + + +# Check whether LC_MESSAGES is available in . +# Ulrich Drepper , 1995. + +# serial 1 + +AC_DEFUN([AM_LC_MESSAGES], + [if test $ac_cv_header_locale_h = yes; then + AC_CACHE_CHECK([for LC_MESSAGES], am_cv_val_LC_MESSAGES, + [AC_TRY_LINK([#include ], [return LC_MESSAGES], + am_cv_val_LC_MESSAGES=yes, am_cv_val_LC_MESSAGES=no)]) + if test $am_cv_val_LC_MESSAGES = yes; then + AC_DEFINE(HAVE_LC_MESSAGES, 1, [Define if your locale.h file contains LC_MESSAGES]) + fi + fi]) + +dnl From Jim Meyering. +dnl FIXME: migrate into libit. + +AC_DEFUN([AM_FUNC_OBSTACK], +[AC_CACHE_CHECK([for obstacks], am_cv_func_obstack, + [AC_TRY_LINK([#include "obstack.h"], + [struct obstack *mem;obstack_free(mem,(char *) 0)], + am_cv_func_obstack=yes, + am_cv_func_obstack=no)]) + if test $am_cv_func_obstack = yes; then + AC_DEFINE(HAVE_OBSTACK) + else + LIBOBJS="$LIBOBJS obstack.o" + fi +]) + +dnl From Jim Meyering. Use this if you use the GNU error.[ch]. +dnl FIXME: Migrate into libit + +AC_DEFUN([AM_FUNC_ERROR_AT_LINE], +[AC_CACHE_CHECK([for error_at_line], am_cv_lib_error_at_line, + [AC_TRY_LINK([],[error_at_line(0, 0, "", 0, "");], + am_cv_lib_error_at_line=yes, + am_cv_lib_error_at_line=no)]) + if test $am_cv_lib_error_at_line = no; then + LIBOBJS="$LIBOBJS error.o" + fi + AC_SUBST(LIBOBJS)dnl +]) + +# Macro to add for using GNU gettext. +# Ulrich Drepper , 1995. + +# serial 1 +# Stephan Kulow: I put a KDE in it to avoid name conflicts + +AC_DEFUN([AM_KDE_GNU_GETTEXT], + [AC_REQUIRE([AC_PROG_MAKE_SET])dnl + AC_REQUIRE([AC_PROG_RANLIB])dnl + AC_REQUIRE([AC_HEADER_STDC])dnl + AC_REQUIRE([AC_TYPE_OFF_T])dnl + AC_REQUIRE([AC_TYPE_SIZE_T])dnl + AC_REQUIRE([AC_FUNC_ALLOCA])dnl + AC_REQUIRE([AC_FUNC_MMAP])dnl + AC_REQUIRE([AM_KDE_WITH_NLS])dnl + AC_CHECK_HEADERS([limits.h locale.h nl_types.h string.h values.h alloca.h]) + AC_CHECK_FUNCS([getcwd munmap putenv setlocale strchr strcasecmp \ +__argz_count __argz_stringify __argz_next]) + + AC_MSG_CHECKING(for stpcpy) + AC_CACHE_VAL(kde_cv_func_stpcpy, + [ + kde_safe_cxxflags=$CXXFLAGS + CXXFLAGS="-Werror" + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + AC_TRY_COMPILE([ + #include + ], + [ + char buffer[200]; + stpcpy(buffer, buffer); + ], + kde_cv_func_stpcpy=yes, + kde_cv_func_stpcpy=no) + AC_LANG_RESTORE + CXXFLAGS=$kde_safe_cxxflags + ]) + AC_MSG_RESULT($kde_cv_func_stpcpy) + if eval "test \"`echo $kde_cv_func_stpcpy`\" = yes"; then + AC_DEFINE(HAVE_STPCPY, 1, [Define if you have stpcpy]) + fi + + AM_LC_MESSAGES + + if test "x$CATOBJEXT" != "x"; then + if test "x$ALL_LINGUAS" = "x"; then + LINGUAS= + else + AC_MSG_CHECKING(for catalogs to be installed) + NEW_LINGUAS= + for lang in ${LINGUAS=$ALL_LINGUAS}; do + case "$ALL_LINGUAS" in + *$lang*) NEW_LINGUAS="$NEW_LINGUAS $lang" ;; + esac + done + LINGUAS=$NEW_LINGUAS + AC_MSG_RESULT($LINGUAS) + fi + + dnl Construct list of names of catalog files to be constructed. + if test -n "$LINGUAS"; then + for lang in $LINGUAS; do CATALOGS="$CATALOGS $lang$CATOBJEXT"; done + fi + fi + + ]) + +AC_DEFUN([AC_HAVE_XPM], + [AC_REQUIRE_CPP()dnl + AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) + + test -z "$XPM_LDFLAGS" && XPM_LDFLAGS= + test -z "$XPM_INCLUDE" && XPM_INCLUDE= + + AC_ARG_WITH(xpm,AC_HELP_STRING([--without-xpm],[disable color pixmap XPM tests]), + xpm_test=$withval, xpm_test="yes") + if test "x$xpm_test" = xno; then + ac_cv_have_xpm=no + else + AC_MSG_CHECKING(for XPM) + AC_CACHE_VAL(ac_cv_have_xpm, + [ + ac_save_ldflags="$LDFLAGS" + ac_save_cflags="$CFLAGS" + if test "x$kde_use_qt_emb" != "xyes" && test "x$kde_use_qt_mac" != "xyes"; then + LDFLAGS="$LDFLAGS $X_LDFLAGS $USER_LDFLAGS $LDFLAGS $XPM_LDFLAGS $all_libraries -lXpm -lX11 -lXext $LIBZ $LIBSOCKET" + else + LDFLAGS="$LDFLAGS $X_LDFLAGS $USER_LDFLAGS $LDFLAGS $XPM_LDFLAGS $all_libraries -lXpm $LIBZ $LIBSOCKET" + fi + CFLAGS="$CFLAGS $X_INCLUDES $USER_INCLUDES" + test -n "$XPM_INCLUDE" && CFLAGS="-I$XPM_INCLUDE $CFLAGS" + AC_TRY_LINK([#include ],[], + ac_cv_have_xpm="yes",ac_cv_have_xpm="no") + LDFLAGS="$ac_save_ldflags" + CFLAGS="$ac_save_cflags" + ])dnl + + if test "$ac_cv_have_xpm" = no; then + AC_MSG_RESULT(no) + XPM_LDFLAGS="" + XPMINC="" + $2 + else + AC_DEFINE(HAVE_XPM, 1, [Define if you have XPM support]) + if test "$XPM_LDFLAGS" = ""; then + XPMLIB='-lXpm $(LIB_X11)' + else + XPMLIB="-L$XPM_LDFLAGS -lXpm "'$(LIB_X11)' + fi + if test "$XPM_INCLUDE" = ""; then + XPMINC="" + else + XPMINC="-I$XPM_INCLUDE" + fi + AC_MSG_RESULT(yes) + $1 + fi + fi + AC_SUBST(XPMINC) + AC_SUBST(XPMLIB) +]) + +AC_DEFUN([AC_HAVE_DPMS], + [AC_REQUIRE_CPP()dnl + AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) + + test -z "$DPMS_LDFLAGS" && DPMS_LDFLAGS= + test -z "$DPMS_INCLUDE" && DPMS_INCLUDE= + DPMS_LIB= + + AC_ARG_WITH(dpms,AC_HELP_STRING([--without-dpms],[disable DPMS power saving]), + dpms_test=$withval, dpms_test="yes") + if test "x$dpms_test" = xno; then + ac_cv_have_dpms=no + else + AC_MSG_CHECKING(for DPMS) + dnl Note: ac_cv_have_dpms can be no, yes, or -lXdpms. + dnl 'yes' means DPMS_LIB="", '-lXdpms' means DPMS_LIB="-lXdpms". + AC_CACHE_VAL(ac_cv_have_dpms, + [ + if test "x$kde_use_qt_emb" = "xyes" || test "x$kde_use_qt_mac" = "xyes" || test "x$kde_use_qt_win" = "xyes"; then + AC_MSG_RESULT(no) + ac_cv_have_dpms="no" + else + ac_save_ldflags="$LDFLAGS" + ac_save_cflags="$CFLAGS" + ac_save_libs="$LIBS" + LDFLAGS="$LDFLAGS $DPMS_LDFLAGS $all_libraries" + LIBS="-lX11 -lXext $LIBSOCKET" + CFLAGS="$CFLAGS $X_INCLUDES" + test -n "$DPMS_INCLUDE" && CFLAGS="-I$DPMS_INCLUDE $CFLAGS" + AC_TRY_LINK([ + #include + #include + #include + #include + int foo_test_dpms() + { return DPMSSetTimeouts( 0, 0, 0, 0 ); }],[], + ac_cv_have_dpms="yes", [ + LIBS="-lXdpms $LIBS" + AC_TRY_LINK([ + #include + #include + #include + #include + int foo_test_dpms() + { return DPMSSetTimeouts( 0, 0, 0, 0 ); }],[], + [ + ac_cv_have_dpms="-lXdpms" + ],ac_cv_have_dpms="no") + ]) + LDFLAGS="$ac_save_ldflags" + CFLAGS="$ac_save_cflags" + LIBS="$ac_save_libs" + fi + ])dnl + + if test "$ac_cv_have_dpms" = no; then + AC_MSG_RESULT(no) + DPMS_LDFLAGS="" + DPMSINC="" + $2 + else + AC_DEFINE(HAVE_DPMS, 1, [Define if you have DPMS support]) + if test "$ac_cv_have_dpms" = "-lXdpms"; then + DPMS_LIB="-lXdpms" + fi + if test "$DPMS_LDFLAGS" = ""; then + DPMSLIB="$DPMS_LIB "'$(LIB_X11)' + else + DPMSLIB="$DPMS_LDFLAGS $DPMS_LIB "'$(LIB_X11)' + fi + if test "$DPMS_INCLUDE" = ""; then + DPMSINC="" + else + DPMSINC="-I$DPMS_INCLUDE" + fi + AC_MSG_RESULT(yes) + $1 + fi + fi + ac_save_cflags="$CFLAGS" + CFLAGS="$CFLAGS $X_INCLUDES" + test -n "$DPMS_INCLUDE" && CFLAGS="-I$DPMS_INCLUDE $CFLAGS" + AH_TEMPLATE(HAVE_DPMSCAPABLE_PROTO, + [Define if you have the DPMSCapable prototype in ]) + AC_CHECK_DECL(DPMSCapable, + AC_DEFINE(HAVE_DPMSCAPABLE_PROTO),, + [#include + #include ]) + AH_TEMPLATE(HAVE_DPMSINFO_PROTO, + [Define if you have the DPMSInfo prototype in ]) + AC_CHECK_DECL(DPMSInfo, + AC_DEFINE(HAVE_DPMSINFO_PROTO),, + [#include + #include ]) + CFLAGS="$ac_save_cflags" + AC_SUBST(DPMSINC) + AC_SUBST(DPMSLIB) +]) + +AC_DEFUN([AC_HAVE_GL], + [AC_REQUIRE_CPP()dnl + AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) + + test -z "$GL_LDFLAGS" && GL_LDFLAGS= + test -z "$GL_INCLUDE" && GL_INCLUDE= + + AC_ARG_WITH(gl,AC_HELP_STRING([--without-gl],[disable 3D GL modes]), + gl_test=$withval, gl_test="yes") + if test "x$kde_use_qt_emb" = "xyes"; then + # GL and Qt Embedded is a no-go for now. + ac_cv_have_gl=no + elif test "x$gl_test" = xno; then + ac_cv_have_gl=no + else + AC_MSG_CHECKING(for GL) + AC_CACHE_VAL(ac_cv_have_gl, + [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + ac_save_ldflags=$LDFLAGS + ac_save_cxxflags=$CXXFLAGS + ac_save_libs=$LIBS + LDFLAGS="$LDFLAGS $GL_LDFLAGS $X_LDFLAGS $all_libraries" + LIBS="$LIBS -lGL -lGLU" + test "x$kde_use_qt_mac" != xyes && test "x$kde_use_qt_emb" != xyes && test "x$kde_use_qt_win" != "xyes" && LIBS="$LIBS -lX11" + LIBS="$LIBS $LIB_XEXT -lm $LIBSOCKET" + CXXFLAGS="$CFLAGS $X_INCLUDES" + test -n "$GL_INCLUDE" && CFLAGS="-I$GL_INCLUDE $CFLAGS" + AC_TRY_LINK([#include +#include +], [], + ac_cv_have_gl="yes", ac_cv_have_gl="no") + AC_LANG_RESTORE + LDFLAGS=$ac_save_ldflags + CXXFLAGS=$ac_save_cxxflags + LIBS=$ac_save_libs + ])dnl + + if test "$ac_cv_have_gl" = "no"; then + AC_MSG_RESULT(no) + GL_LDFLAGS="" + GLINC="" + $2 + else + AC_DEFINE(HAVE_GL, 1, [Defines if you have GL (Mesa, OpenGL, ...)]) + if test "$GL_LDFLAGS" = ""; then + GLLIB='-lGLU -lGL $(LIB_X11)' + else + GLLIB="$GL_LDFLAGS -lGLU -lGL "'$(LIB_X11)' + fi + if test "$GL_INCLUDE" = ""; then + GLINC="" + else + GLINC="-I$GL_INCLUDE" + fi + AC_MSG_RESULT($ac_cv_have_gl) + $1 + fi + fi + AC_SUBST(GLINC) + AC_SUBST(GLLIB) +]) + + + dnl shadow password and PAM magic - maintained by ossi@kde.org + +AC_DEFUN([KDE_PAM], [ + AC_REQUIRE([KDE_CHECK_LIBDL]) + + want_pam= + AC_ARG_WITH(pam, + AC_HELP_STRING([--with-pam[=ARG]],[enable support for PAM: ARG=[yes|no|service name]]), + [ if test "x$withval" = "xyes"; then + want_pam=yes + pam_service=kde + elif test "x$withval" = "xno"; then + want_pam=no + else + want_pam=yes + pam_service=$withval + fi + ], [ pam_service=kde ]) + + use_pam= + PAMLIBS= + if test "x$want_pam" != xno; then + AC_CHECK_LIB(pam, pam_start, [ + AC_CHECK_HEADER(security/pam_appl.h, + [ pam_header=security/pam_appl.h ], + [ AC_CHECK_HEADER(pam/pam_appl.h, + [ pam_header=pam/pam_appl.h ], + [ + AC_MSG_WARN([PAM detected, but no headers found! +Make sure you have the necessary development packages installed.]) + ] + ) + ] + ) + ], , $LIBDL) + if test -z "$pam_header"; then + if test "x$want_pam" = xyes; then + AC_MSG_ERROR([--with-pam was specified, but cannot compile with PAM!]) + fi + else + AC_DEFINE(HAVE_PAM, 1, [Defines if you have PAM (Pluggable Authentication Modules)]) + PAMLIBS="$PAM_MISC_LIB -lpam $LIBDL" + use_pam=yes + + dnl darwin claims to be something special + if test "$pam_header" = "pam/pam_appl.h"; then + AC_DEFINE(HAVE_PAM_PAM_APPL_H, 1, [Define if your PAM headers are in pam/ instead of security/]) + fi + + dnl test whether struct pam_message is const (Linux) or not (Sun) + AC_MSG_CHECKING(for const pam_message) + AC_EGREP_HEADER([struct pam_message], $pam_header, + [ AC_EGREP_HEADER([const struct pam_message], $pam_header, + [AC_MSG_RESULT([const: Linux-type PAM])], + [AC_MSG_RESULT([nonconst: Sun-type PAM]) + AC_DEFINE(PAM_MESSAGE_NONCONST, 1, [Define if your PAM support takes non-const arguments (Solaris)])] + )], + [AC_MSG_RESULT([not found - assume const, Linux-type PAM])]) + fi + fi + + AC_SUBST(PAMLIBS) +]) + +dnl DEF_PAM_SERVICE(arg name, full name, define name) +AC_DEFUN([DEF_PAM_SERVICE], [ + AC_ARG_WITH($1-pam, + AC_HELP_STRING([--with-$1-pam=[val]],[override PAM service from --with-pam for $2]), + [ if test "x$use_pam" = xyes; then + $3_PAM_SERVICE=$withval + else + AC_MSG_ERROR([Cannot use use --with-$1-pam, as no PAM was detected. +You may want to enforce it by using --with-pam.]) + fi + ], + [ if test "x$use_pam" = xyes; then + $3_PAM_SERVICE="$pam_service" + fi + ]) + if test -n "$$3_PAM_SERVICE"; then + AC_MSG_RESULT([The PAM service used by $2 will be $$3_PAM_SERVICE]) + AC_DEFINE_UNQUOTED($3_PAM_SERVICE, "$$3_PAM_SERVICE", [The PAM service to be used by $2]) + fi + AC_SUBST($3_PAM_SERVICE) +]) + +AC_DEFUN([KDE_SHADOWPASSWD], [ + AC_REQUIRE([KDE_PAM]) + + AC_CHECK_LIB(shadow, getspent, + [ LIBSHADOW="-lshadow" + ac_use_shadow=yes + ], + [ dnl for UnixWare + AC_CHECK_LIB(gen, getspent, + [ LIBGEN="-lgen" + ac_use_shadow=yes + ], + [ AC_CHECK_FUNC(getspent, + [ ac_use_shadow=yes ], + [ ac_use_shadow=no ]) + ]) + ]) + AC_SUBST(LIBSHADOW) + AC_SUBST(LIBGEN) + + AC_MSG_CHECKING([for shadow passwords]) + + AC_ARG_WITH(shadow, + AC_HELP_STRING([--with-shadow],[If you want shadow password support]), + [ if test "x$withval" != "xno"; then + use_shadow=yes + else + use_shadow=no + fi + ], [ + use_shadow="$ac_use_shadow" + ]) + + if test "x$use_shadow" = xyes; then + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_SHADOW, 1, [Define if you use shadow passwords]) + else + AC_MSG_RESULT(no) + LIBSHADOW= + LIBGEN= + fi + + dnl finally make the relevant binaries setuid root, if we have shadow passwds. + dnl this still applies, if we could use it indirectly through pam. + if test "x$use_shadow" = xyes || + ( test "x$use_pam" = xyes && test "x$ac_use_shadow" = xyes ); then + case $host in + *-*-freebsd* | *-*-netbsd* | *-*-openbsd*) + SETUIDFLAGS="-m 4755 -o root";; + *) + SETUIDFLAGS="-m 4755";; + esac + fi + AC_SUBST(SETUIDFLAGS) + +]) + +AC_DEFUN([KDE_PASSWDLIBS], [ + AC_REQUIRE([KDE_MISC_TESTS]) dnl for LIBCRYPT + AC_REQUIRE([KDE_PAM]) + AC_REQUIRE([KDE_SHADOWPASSWD]) + + if test "x$use_pam" = "xyes"; then + PASSWDLIBS="$PAMLIBS" + else + PASSWDLIBS="$LIBCRYPT $LIBSHADOW $LIBGEN" + fi + + dnl FreeBSD uses a shadow-like setup, where /etc/passwd holds the users, but + dnl /etc/master.passwd holds the actual passwords. /etc/master.passwd requires + dnl root to read, so kcheckpass needs to be root (even when using pam, since pam + dnl may need to read /etc/master.passwd). + case $host in + *-*-freebsd*) + SETUIDFLAGS="-m 4755 -o root" + ;; + *) + ;; + esac + + AC_SUBST(PASSWDLIBS) +]) + +AC_DEFUN([KDE_CHECK_LIBDL], +[ +AC_CHECK_LIB(dl, dlopen, [ +LIBDL="-ldl" +ac_cv_have_dlfcn=yes +]) + +AC_CHECK_LIB(dld, shl_unload, [ +LIBDL="-ldld" +ac_cv_have_shload=yes +]) + +AC_SUBST(LIBDL) +]) + +AC_DEFUN([KDE_CHECK_DLOPEN], +[ +KDE_CHECK_LIBDL +AC_CHECK_HEADERS(dlfcn.h dl.h) +if test "$ac_cv_header_dlfcn_h" = "no"; then + ac_cv_have_dlfcn=no +fi + +if test "$ac_cv_header_dl_h" = "no"; then + ac_cv_have_shload=no +fi + +dnl XXX why change enable_dlopen? its already set by autoconf's AC_ARG_ENABLE +dnl (MM) +AC_ARG_ENABLE(dlopen, +AC_HELP_STRING([--disable-dlopen],[link statically [default=no]]), +enable_dlopen=$enableval, +enable_dlopen=yes) + +# override the user's opinion, if we know it better ;) +if test "$ac_cv_have_dlfcn" = "no" && test "$ac_cv_have_shload" = "no"; then + enable_dlopen=no +fi + +if test "$ac_cv_have_dlfcn" = "yes"; then + AC_DEFINE_UNQUOTED(HAVE_DLFCN, 1, [Define if you have dlfcn]) +fi + +if test "$ac_cv_have_shload" = "yes"; then + AC_DEFINE_UNQUOTED(HAVE_SHLOAD, 1, [Define if you have shload]) +fi + +if test "$enable_dlopen" = no ; then + test -n "$1" && eval $1 +else + test -n "$2" && eval $2 +fi + +]) + +AC_DEFUN([KDE_CHECK_DYNAMIC_LOADING], +[ +KDE_CHECK_DLOPEN(libtool_enable_shared=yes, libtool_enable_static=no) +KDE_PROG_LIBTOOL +AC_MSG_CHECKING([dynamic loading]) +eval "`egrep '^build_libtool_libs=' libtool`" +if test "$build_libtool_libs" = "yes" && test "$enable_dlopen" = "yes"; then + dynamic_loading=yes + AC_DEFINE_UNQUOTED(HAVE_DYNAMIC_LOADING) +else + dynamic_loading=no +fi +AC_MSG_RESULT($dynamic_loading) +if test "$dynamic_loading" = "yes"; then + $1 +else + $2 +fi +]) + +AC_DEFUN([KDE_ADD_INCLUDES], +[ +if test -z "$1"; then + test_include="Pix.h" +else + test_include="$1" +fi + +AC_MSG_CHECKING([for libg++ ($test_include)]) + +AC_CACHE_VAL(kde_cv_libgpp_includes, +[ +kde_cv_libgpp_includes=no + + for ac_dir in \ + \ + /usr/include/g++ \ + /usr/include \ + /usr/unsupported/include \ + /opt/include \ + $extra_include \ + ; \ + do + if test -r "$ac_dir/$test_include"; then + kde_cv_libgpp_includes=$ac_dir + break + fi + done +]) + +AC_MSG_RESULT($kde_cv_libgpp_includes) +if test "$kde_cv_libgpp_includes" != "no"; then + all_includes="-I$kde_cv_libgpp_includes $all_includes $USER_INCLUDES" +fi +]) +]) + +AC_DEFUN([KDE_CHECK_LIBPTHREAD], +[ + dnl This code is here specifically to handle the + dnl various flavors of threading library on FreeBSD + dnl 4-, 5-, and 6-, and the (weird) rules around it. + dnl There may be an environment PTHREAD_LIBS that + dnl specifies what to use; otherwise, search for it. + dnl -pthread is special cased and unsets LIBPTHREAD + dnl below if found. + LIBPTHREAD="" + + if test -n "$PTHREAD_LIBS"; then + if test "x$PTHREAD_LIBS" = "x-pthread" ; then + LIBPTHREAD="PTHREAD" + else + PTHREAD_LIBS_save="$PTHREAD_LIBS" + PTHREAD_LIBS=`echo "$PTHREAD_LIBS_save" | sed -e 's,^-l,,g'` + AC_MSG_CHECKING([for pthread_create in $PTHREAD_LIBS]) + KDE_CHECK_LIB($PTHREAD_LIBS, pthread_create, [ + LIBPTHREAD="$PTHREAD_LIBS_save"]) + PTHREAD_LIBS="$PTHREAD_LIBS_save" + fi + fi + + dnl Is this test really needed, in the face of the Tru64 test below? + if test -z "$LIBPTHREAD"; then + AC_CHECK_LIB(pthread, pthread_create, [LIBPTHREAD="-lpthread"]) + fi + + dnl This is a special Tru64 check, see BR 76171 issue #18. + if test -z "$LIBPTHREAD" ; then + AC_MSG_CHECKING([for pthread_create in -lpthread]) + kde_safe_libs=$LIBS + LIBS="$LIBS -lpthread" + AC_TRY_LINK([#include ],[(void)pthread_create(0,0,0,0);],[ + AC_MSG_RESULT(yes) + LIBPTHREAD="-lpthread"],[ + AC_MSG_RESULT(no)]) + LIBS=$kde_safe_libs + fi + + dnl Un-special-case for FreeBSD. + if test "x$LIBPTHREAD" = "xPTHREAD" ; then + LIBPTHREAD="" + fi + + AC_SUBST(LIBPTHREAD) +]) + +AC_DEFUN([KDE_CHECK_PTHREAD_OPTION], +[ + USE_THREADS="" + if test -z "$LIBPTHREAD"; then + KDE_CHECK_COMPILER_FLAG(pthread, [USE_THREADS="-D_THREAD_SAFE -pthread"]) + fi + + AH_VERBATIM(__svr_define, [ +#if defined(__SVR4) && !defined(__svr4__) +#define __svr4__ 1 +#endif +]) + case $host_os in + solaris*) + KDE_CHECK_COMPILER_FLAG(mt, [USE_THREADS="-mt"]) + CPPFLAGS="$CPPFLAGS -D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -DUSE_SOLARIS -DSVR4" + ;; + freebsd*) + CPPFLAGS="$CPPFLAGS -D_THREAD_SAFE $PTHREAD_CFLAGS" + ;; + aix*) + CPPFLAGS="$CPPFLAGS -D_THREAD_SAFE" + LIBPTHREAD="$LIBPTHREAD -lc_r" + ;; + linux*) CPPFLAGS="$CPPFLAGS -D_REENTRANT" + if test "$CXX" = "KCC"; then + CXXFLAGS="$CXXFLAGS --thread_safe" + NOOPT_CXXFLAGS="$NOOPT_CXXFLAGS --thread_safe" + fi + ;; + *) + ;; + esac + AC_SUBST(USE_THREADS) + AC_SUBST(LIBPTHREAD) +]) + +AC_DEFUN([KDE_CHECK_THREADING], +[ + AC_REQUIRE([KDE_CHECK_LIBPTHREAD]) + AC_REQUIRE([KDE_CHECK_PTHREAD_OPTION]) + dnl default is yes if libpthread is found and no if no libpthread is available + if test -z "$LIBPTHREAD"; then + if test -z "$USE_THREADS"; then + kde_check_threading_default=no + else + kde_check_threading_default=yes + fi + else + kde_check_threading_default=yes + fi + AC_ARG_ENABLE(threading,AC_HELP_STRING([--disable-threading],[disables threading even if libpthread found]), + kde_use_threading=$enableval, kde_use_threading=$kde_check_threading_default) + if test "x$kde_use_threading" = "xyes"; then + AC_DEFINE(HAVE_LIBPTHREAD, 1, [Define if you have a working libpthread (will enable threaded code)]) + fi +]) + +AC_DEFUN([KDE_TRY_LINK_PYTHON], +[ +if test "$kde_python_link_found" = no; then + +if test "$1" = normal; then + AC_MSG_CHECKING(if a Python application links) +else + AC_MSG_CHECKING(if Python depends on $2) +fi + +AC_CACHE_VAL(kde_cv_try_link_python_$1, +[ +kde_save_cflags="$CFLAGS" +CFLAGS="$CFLAGS $PYTHONINC" +kde_save_libs="$LIBS" +LIBS="$LIBS $LIBPYTHON $2 $LIBDL $LIBSOCKET" +kde_save_ldflags="$LDFLAGS" +LDFLAGS="$LDFLAGS $PYTHONLIB" + +AC_TRY_LINK( +[ +#include +],[ + PySys_SetArgv(1, 0); +], + [kde_cv_try_link_python_$1=yes], + [kde_cv_try_link_python_$1=no] +) +CFLAGS="$kde_save_cflags" +LIBS="$kde_save_libs" +LDFLAGS="$kde_save_ldflags" +]) + +if test "$kde_cv_try_link_python_$1" = "yes"; then + AC_MSG_RESULT(yes) + kde_python_link_found=yes + if test ! "$1" = normal; then + LIBPYTHON="$LIBPYTHON $2" + fi + $3 +else + AC_MSG_RESULT(no) + $4 +fi + +fi + +]) + +AC_DEFUN([KDE_CHECK_PYTHON_DIR], +[ +AC_MSG_CHECKING([for Python directory]) + +AC_CACHE_VAL(kde_cv_pythondir, +[ + if test -z "$PYTHONDIR"; then + kde_cv_pythondir=/usr/local + else + kde_cv_pythondir="$PYTHONDIR" + fi +]) + +AC_ARG_WITH(pythondir, +AC_HELP_STRING([--with-pythondir=pythondir],[use python installed in pythondir]), +[ + ac_python_dir=$withval +], ac_python_dir=$kde_cv_pythondir +) + +AC_MSG_RESULT($ac_python_dir) +]) + +AC_DEFUN([KDE_CHECK_PYTHON_INTERN], +[ +AC_REQUIRE([KDE_CHECK_LIBDL]) +AC_REQUIRE([KDE_CHECK_LIBPTHREAD]) +AC_REQUIRE([KDE_CHECK_PYTHON_DIR]) + +if test -z "$1"; then + version="1.5" +else + version="$1" +fi + +AC_MSG_CHECKING([for Python$version]) + +python_incdirs="$ac_python_dir/include /usr/include /usr/local/include/ $kde_extra_includes" +AC_FIND_FILE(Python.h, $python_incdirs, python_incdir) +if test ! -r $python_incdir/Python.h; then + AC_FIND_FILE(python$version/Python.h, $python_incdirs, python_incdir) + python_incdir=$python_incdir/python$version + if test ! -r $python_incdir/Python.h; then + python_incdir=no + fi +fi + +PYTHONINC=-I$python_incdir + +python_libdirs="$ac_python_dir/lib$kdelibsuff /usr/lib$kdelibsuff /usr/local /usr/lib$kdelibsuff $kde_extra_libs" +AC_FIND_FILE(libpython$version.so, $python_libdirs, python_libdir) +if test ! -r $python_libdir/libpython$version.so; then + AC_FIND_FILE(libpython$version.a, $python_libdirs, python_libdir) + if test ! -r $python_libdir/libpython$version.a; then + AC_FIND_FILE(python$version/config/libpython$version.a, $python_libdirs, python_libdir) + python_libdir=$python_libdir/python$version/config + if test ! -r $python_libdir/libpython$version.a; then + python_libdir=no + fi + fi +fi + +PYTHONLIB=-L$python_libdir +kde_orig_LIBPYTHON=$LIBPYTHON +if test -z "$LIBPYTHON"; then + LIBPYTHON=-lpython$version +fi + +AC_FIND_FILE(python$version/copy.py, $python_libdirs, python_moddir) +python_moddir=$python_moddir/python$version +if test ! -r $python_moddir/copy.py; then + python_moddir=no +fi + +PYTHONMODDIR=$python_moddir + +AC_MSG_RESULT(header $python_incdir library $python_libdir modules $python_moddir) + +if test x$python_incdir = xno || test x$python_libdir = xno || test x$python_moddir = xno; then + LIBPYTHON=$kde_orig_LIBPYTHON + test "x$PYTHONLIB" = "x-Lno" && PYTHONLIB="" + test "x$PYTHONINC" = "x-Ino" && PYTHONINC="" + $2 +else + dnl Note: this test is very weak + kde_python_link_found=no + KDE_TRY_LINK_PYTHON(normal) + KDE_TRY_LINK_PYTHON(m, -lm) + KDE_TRY_LINK_PYTHON(pthread, $LIBPTHREAD) + KDE_TRY_LINK_PYTHON(tcl, -ltcl) + KDE_TRY_LINK_PYTHON(db2, -ldb2) + KDE_TRY_LINK_PYTHON(m_and_thread, [$LIBPTHREAD -lm]) + KDE_TRY_LINK_PYTHON(m_and_thread_and_util, [$LIBPTHREAD -lm -lutil]) + KDE_TRY_LINK_PYTHON(m_and_thread_and_db3, [$LIBPTHREAD -lm -ldb-3 -lutil]) + KDE_TRY_LINK_PYTHON(pthread_and_db3, [$LIBPTHREAD -ldb-3]) + KDE_TRY_LINK_PYTHON(m_and_thread_and_db, [$LIBPTHREAD -lm -ldb -ltermcap -lutil]) + KDE_TRY_LINK_PYTHON(pthread_and_dl, [$LIBPTHREAD $LIBDL -lutil -lreadline -lncurses -lm]) + KDE_TRY_LINK_PYTHON(pthread_and_panel_curses, [$LIBPTHREAD $LIBDL -lm -lpanel -lcurses]) + KDE_TRY_LINK_PYTHON(m_and_thread_and_db_special, [$LIBPTHREAD -lm -ldb -lutil], [], + [AC_MSG_WARN([it seems, Python depends on another library. + Please set LIBPYTHON to '-lpython$version -lotherlib' before calling configure to fix this + and contact the authors to let them know about this problem]) + ]) + + LIBPYTHON="$LIBPYTHON $LIBDL $LIBSOCKET" + AC_SUBST(PYTHONINC) + AC_SUBST(PYTHONLIB) + AC_SUBST(LIBPYTHON) + AC_SUBST(PYTHONMODDIR) + AC_DEFINE(HAVE_PYTHON, 1, [Define if you have the development files for python]) +fi + +]) + + +AC_DEFUN([KDE_CHECK_PYTHON], +[ + KDE_CHECK_PYTHON_INTERN("2.5", + [KDE_CHECK_PYTHON_INTERN("2.4", + [KDE_CHECK_PYTHON_INTERN("2.3", + [KDE_CHECK_PYTHON_INTERN("2.2", + [KDE_CHECK_PYTHON_INTERN("2.1", + [KDE_CHECK_PYTHON_INTERN("2.0", + [KDE_CHECK_PYTHON_INTERN($1, $2) ]) + ]) + ]) + ]) + ]) + ]) +]) + +AC_DEFUN([KDE_CHECK_STL], +[ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="`echo $CXXFLAGS | sed s/-fno-exceptions//`" + + AC_MSG_CHECKING([if C++ programs can be compiled]) + AC_CACHE_VAL(kde_cv_stl_works, + [ + AC_TRY_COMPILE([ +#include +using namespace std; +],[ + string astring="Hallo Welt."; + astring.erase(0, 6); // now astring is "Welt" + return 0; +], kde_cv_stl_works=yes, + kde_cv_stl_works=no) +]) + + AC_MSG_RESULT($kde_cv_stl_works) + + if test "$kde_cv_stl_works" = "yes"; then + # back compatible + AC_DEFINE_UNQUOTED(HAVE_SGI_STL, 1, [Define if you have a STL implementation by SGI]) + else + AC_MSG_ERROR([Your Installation isn't able to compile simple C++ programs. +Check config.log for details - if you're using a Linux distribution you might miss +a package named similar to libstdc++-dev.]) + fi + + CXXFLAGS="$ac_save_CXXFLAGS" + AC_LANG_RESTORE +]) + +AC_DEFUN([AC_FIND_QIMGIO], + [AC_REQUIRE([AC_FIND_JPEG]) +AC_REQUIRE([KDE_CHECK_EXTRA_LIBS]) +AC_MSG_CHECKING([for qimgio]) +AC_CACHE_VAL(ac_cv_lib_qimgio, +[ +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +ac_save_LIBS="$LIBS" +ac_save_CXXFLAGS="$CXXFLAGS" +LIBS="$all_libraries -lqimgio -lpng -lz $LIBJPEG $LIBQT" +CXXFLAGS="$CXXFLAGS -I$qt_incdir $all_includes" +AC_TRY_RUN(dnl +[ +#include +#include +int main() { + QString t = "hallo"; + t.fill('t'); + qInitImageIO(); +} +], + ac_cv_lib_qimgio=yes, + ac_cv_lib_qimgio=no, + ac_cv_lib_qimgio=no) +LIBS="$ac_save_LIBS" +CXXFLAGS="$ac_save_CXXFLAGS" +AC_LANG_RESTORE +])dnl +if eval "test \"`echo $ac_cv_lib_qimgio`\" = yes"; then + LIBQIMGIO="-lqimgio -lpng -lz $LIBJPEG" + AC_MSG_RESULT(yes) + AC_DEFINE_UNQUOTED(HAVE_QIMGIO, 1, [Define if you have the Qt extension qimgio available]) + AC_SUBST(LIBQIMGIO) +else + AC_MSG_RESULT(not found) +fi +]) + +AC_DEFUN([AM_DISABLE_LIBRARIES], +[ + AC_PROVIDE([AM_ENABLE_STATIC]) + AC_PROVIDE([AM_ENABLE_SHARED]) + enable_static=no + enable_shared=yes +]) + + +AC_DEFUN([AC_CHECK_UTMP_FILE], +[ + AC_MSG_CHECKING([for utmp file]) + + AC_CACHE_VAL(kde_cv_utmp_file, + [ + kde_cv_utmp_file=no + + for ac_file in \ + \ + /var/run/utmp \ + /var/adm/utmp \ + /etc/utmp \ + ; \ + do + if test -r "$ac_file"; then + kde_cv_utmp_file=$ac_file + break + fi + done + ]) + + if test "$kde_cv_utmp_file" != "no"; then + AC_DEFINE_UNQUOTED(UTMP, "$kde_cv_utmp_file", [Define the file for utmp entries]) + $1 + AC_MSG_RESULT($kde_cv_utmp_file) + else + $2 + AC_MSG_RESULT([non found]) + fi +]) + + +AC_DEFUN([KDE_CREATE_SUBDIRSLIST], +[ + +DO_NOT_COMPILE="$DO_NOT_COMPILE CVS debian bsd-port admin" +TOPSUBDIRS="" + +if test ! -s $srcdir/subdirs; then + dnl Note: Makefile.common creates subdirs, so this is just a fallback + files=`cd $srcdir && ls -1` + dirs=`for i in $files; do if test -d $i; then echo $i; fi; done` + for i in $dirs; do + echo $i >> $srcdir/subdirs + done +fi + +ac_topsubdirs= +if test -s $srcdir/inst-apps; then + ac_topsubdirs="`cat $srcdir/inst-apps`" +elif test -s $srcdir/subdirs; then + ac_topsubdirs="`cat $srcdir/subdirs`" +fi + +for i in $ac_topsubdirs; do + AC_MSG_CHECKING([if $i should be compiled]) + if test -d $srcdir/$i; then + install_it="yes" + for j in $DO_NOT_COMPILE; do + if test $i = $j; then + install_it="no" + fi + done + else + install_it="no" + fi + AC_MSG_RESULT($install_it) + vari=`echo $i | sed -e 's,[[-+.@\/]],_,g'` + if test $install_it = "yes"; then + TOPSUBDIRS="$TOPSUBDIRS $i" + eval "$vari""_SUBDIR_included=yes" + else + eval "$vari""_SUBDIR_included=no" + fi +done + +AC_SUBST(TOPSUBDIRS) +]) + +AC_DEFUN([KDE_CHECK_NAMESPACES], +[ +AC_MSG_CHECKING(whether C++ compiler supports namespaces) +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +AC_TRY_COMPILE([ +], +[ +namespace Foo { + extern int i; + namespace Bar { + extern int i; + } +} + +int Foo::i = 0; +int Foo::Bar::i = 1; +],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_NAMESPACES) +], [ +AC_MSG_RESULT(no) +]) +AC_LANG_RESTORE +]) + +dnl ------------------------------------------------------------------------ +dnl Check for S_ISSOCK macro. Doesn't exist on Unix SCO. faure@kde.org +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([AC_CHECK_S_ISSOCK], +[ +AC_MSG_CHECKING(for S_ISSOCK) +AC_CACHE_VAL(ac_cv_have_s_issock, +[ +AC_TRY_LINK( +[ +#include +], +[ +struct stat buff; +int b = S_ISSOCK( buff.st_mode ); +], +ac_cv_have_s_issock=yes, +ac_cv_have_s_issock=no) +]) +AC_MSG_RESULT($ac_cv_have_s_issock) +if test "$ac_cv_have_s_issock" = "yes"; then + AC_DEFINE_UNQUOTED(HAVE_S_ISSOCK, 1, [Define if sys/stat.h declares S_ISSOCK.]) +fi + +AH_VERBATIM(_ISSOCK, +[ +#ifndef HAVE_S_ISSOCK +#define HAVE_S_ISSOCK +#define S_ISSOCK(mode) (1==0) +#endif +]) + +]) + +dnl ------------------------------------------------------------------------ +dnl Check for MAXPATHLEN macro, defines KDEMAXPATHLEN. faure@kde.org +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([AC_CHECK_KDEMAXPATHLEN], +[ +AC_MSG_CHECKING(for MAXPATHLEN) +AC_CACHE_VAL(ac_cv_maxpathlen, +[ +cat > conftest.$ac_ext < +#endif +#include +#include +#ifndef MAXPATHLEN +#define MAXPATHLEN 1024 +#endif + +KDE_HELLO MAXPATHLEN + +EOF + +ac_try="$ac_cpp conftest.$ac_ext 2>/dev/null | grep '^KDE_HELLO' >conftest.out" + +if AC_TRY_EVAL(ac_try) && test -s conftest.out; then + ac_cv_maxpathlen=`sed 's#KDE_HELLO ##' conftest.out` +else + ac_cv_maxpathlen=1024 +fi + +rm conftest.* + +]) +AC_MSG_RESULT($ac_cv_maxpathlen) +AC_DEFINE_UNQUOTED(KDEMAXPATHLEN,$ac_cv_maxpathlen, [Define a safe value for MAXPATHLEN] ) +]) + +AC_DEFUN([KDE_CHECK_HEADER], +[ + kde_safe_cppflags=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $all_includes" + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + AC_CHECK_HEADER([$1], [$2], [$3], [$4]) + AC_LANG_RESTORE + CPPFLAGS=$kde_safe_cppflags +]) + +AC_DEFUN([KDE_CHECK_HEADERS], +[ + AH_CHECK_HEADERS([$1]) + AC_LANG_SAVE + kde_safe_cppflags=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $all_includes" + AC_LANG_CPLUSPLUS + AC_CHECK_HEADERS([$1], [$2], [$3], [$4]) + CPPFLAGS=$kde_safe_cppflags + AC_LANG_RESTORE +]) + +AC_DEFUN([KDE_FAST_CONFIGURE], +[ + dnl makes configure fast (needs perl) + AC_ARG_ENABLE(fast-perl, AC_HELP_STRING([--disable-fast-perl],[disable fast Makefile generation (needs perl)]), + with_fast_perl=$enableval, with_fast_perl=yes) +]) + +AC_DEFUN([KDE_CONF_FILES], +[ + val= + if test -f $srcdir/configure.files ; then + val=`sed -e 's%^%\$(top_srcdir)/%' $srcdir/configure.files` + fi + CONF_FILES= + if test -n "$val" ; then + for i in $val ; do + CONF_FILES="$CONF_FILES $i" + done + fi + AC_SUBST(CONF_FILES) +])dnl + +dnl This sets the prefix, for arts and kdelibs +dnl Do NOT use in any other module. +dnl It only looks at --prefix, KDEDIR and falls back to /usr/local/kde +AC_DEFUN([KDE_SET_PREFIX_CORE], +[ + unset CDPATH + dnl make $KDEDIR the default for the installation + AC_PREFIX_DEFAULT(${KDEDIR:-/usr/local/kde}) + + if test "x$prefix" = "xNONE"; then + prefix=$ac_default_prefix + ac_configure_args="$ac_configure_args --prefix=$prefix" + fi + # And delete superfluous '/' to make compares easier + prefix=`echo "$prefix" | sed 's,//*,/,g' | sed -e 's,/$,,'` + exec_prefix=`echo "$exec_prefix" | sed 's,//*,/,g' | sed -e 's,/$,,'` + + kde_libs_prefix='$(prefix)' + kde_libs_htmldir='$(kde_htmldir)' + AC_SUBST(kde_libs_prefix) + AC_SUBST(kde_libs_htmldir) + KDE_FAST_CONFIGURE + KDE_CONF_FILES +]) + + +AC_DEFUN([SIM_SET_PREFIX], +[ + AC_MSG_CHECKING([where to install]) + if test "x$prefix" = "xNONE"; then + prefix=/usr/local + AC_MSG_RESULT([$prefix (default value)]) + else + dnl --prefix was given. Compare prefixes and warn (in configure.in.bot.end) if different + given_prefix=$prefix + AC_MSG_RESULT([$prefix (as requested)]) + fi + KDE_SET_DEFAULT_PATHS(default) +]) + +AC_DEFUN([KDE_SET_PREFIX], +[ + unset CDPATH + dnl We can't give real code to that macro, only a value. + dnl It only matters for --help, since we set the prefix in this function anyway. + AC_PREFIX_DEFAULT(${KDEDIR:-the kde prefix}) + + KDE_SET_DEFAULT_BINDIRS + if test "x$prefix" = "xNONE"; then + dnl no prefix given: look for kde-config in the PATH and deduce the prefix from it + KDE_FIND_PATH(kde-config, KDECONFIG, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(kde-config)], [], prepend) + else + dnl prefix given: look for kde-config, preferrably in prefix, otherwise in PATH + kde_save_PATH="$PATH" + PATH="$exec_prefix/bin:$prefix/bin:$PATH" + KDE_FIND_PATH(kde-config, KDECONFIG, [$kde_default_bindirs], [KDE_MISSING_PROG_ERROR(kde-config)], [], prepend) + PATH="$kde_save_PATH" + fi + + kde_libs_prefix=`$KDECONFIG --prefix` + if test -z "$kde_libs_prefix" || test ! -x "$kde_libs_prefix"; then + AC_MSG_ERROR([$KDECONFIG --prefix outputed the non existant prefix '$kde_libs_prefix' for kdelibs. + This means it has been moved since you installed it. + This won't work. Please recompile kdelibs for the new prefix. + ]) + fi + kde_libs_htmldir=`$KDECONFIG --install html --expandvars` + + AC_MSG_CHECKING([where to install]) + if test "x$prefix" = "xNONE"; then + prefix=$kde_libs_prefix + AC_MSG_RESULT([$prefix (as returned by kde-config)]) + else + dnl --prefix was given. Compare prefixes and warn (in configure.in.bot.end) if different + given_prefix=$prefix + AC_MSG_RESULT([$prefix (as requested)]) + fi + + # And delete superfluous '/' to make compares easier + prefix=`echo "$prefix" | sed 's,//*,/,g' | sed -e 's,/$,,'` + exec_prefix=`echo "$exec_prefix" | sed 's,//*,/,g' | sed -e 's,/$,,'` + given_prefix=`echo "$given_prefix" | sed 's,//*,/,g' | sed -e 's,/$,,'` + + AC_SUBST(KDECONFIG) + AC_SUBST(kde_libs_prefix) + AC_SUBST(kde_libs_htmldir) + + KDE_FAST_CONFIGURE + KDE_CONF_FILES +]) + +pushdef([AC_PROG_INSTALL], +[ + dnl our own version, testing for a -p flag + popdef([AC_PROG_INSTALL]) + dnl as AC_PROG_INSTALL works as it works we first have + dnl to save if the user didn't specify INSTALL, as the + dnl autoconf one overwrites INSTALL and we have no chance to find + dnl out afterwards + test -n "$INSTALL" && kde_save_INSTALL_given=$INSTALL + test -n "$INSTALL_PROGRAM" && kde_save_INSTALL_PROGRAM_given=$INSTALL_PROGRAM + test -n "$INSTALL_SCRIPT" && kde_save_INSTALL_SCRIPT_given=$INSTALL_SCRIPT + AC_PROG_INSTALL + + if test -z "$kde_save_INSTALL_given" ; then + # OK, user hasn't given any INSTALL, autoconf found one for us + # now we test, if it supports the -p flag + AC_MSG_CHECKING(for -p flag to install) + rm -f confinst.$$.* > /dev/null 2>&1 + echo "Testtest" > confinst.$$.orig + ac_res=no + if ${INSTALL} -p confinst.$$.orig confinst.$$.new > /dev/null 2>&1 ; then + if test -f confinst.$$.new ; then + # OK, -p seems to do no harm to install + INSTALL="${INSTALL} -p" + ac_res=yes + fi + fi + rm -f confinst.$$.* + AC_MSG_RESULT($ac_res) + fi + dnl the following tries to resolve some signs and wonders coming up + dnl with different autoconf/automake versions + dnl e.g.: + dnl *automake 1.4 install-strip sets A_M_INSTALL_PROGRAM_FLAGS to -s + dnl and has INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(A_M_INSTALL_PROGRAM_FLAGS) + dnl it header-vars.am, so there the actual INSTALL_PROGRAM gets the -s + dnl *automake 1.4a (and above) use INSTALL_STRIP_FLAG and only has + dnl INSTALL_PROGRAM = @INSTALL_PROGRAM@ there, but changes the + dnl install-@DIR@PROGRAMS targets to explicitly use that flag + dnl *autoconf 2.13 is dumb, and thinks it can use INSTALL_PROGRAM as + dnl INSTALL_SCRIPT, which breaks with automake <= 1.4 + dnl *autoconf >2.13 (since 10.Apr 1999) has not that failure + dnl *sometimes KDE does not use the install-@DIR@PROGRAM targets from + dnl automake (due to broken Makefile.am or whatever) to install programs, + dnl and so does not see the -s flag in automake > 1.4 + dnl to clean up that mess we: + dnl +set INSTALL_PROGRAM to use INSTALL_STRIP_FLAG + dnl which cleans KDE's program with automake > 1.4; + dnl +set INSTALL_SCRIPT to only use INSTALL, to clean up autoconf's problems + dnl with automake<=1.4 + dnl note that dues to this sometimes two '-s' flags are used (if KDE + dnl properly uses install-@DIR@PROGRAMS, but I don't care + dnl + dnl And to all this comes, that I even can't write in comments variable + dnl names used by automake, because it is so stupid to think I wanted to + dnl _use_ them, therefor I have written A_M_... instead of AM_ + dnl hmm, I wanted to say something ... ahh yes: Arghhh. + + if test -z "$kde_save_INSTALL_PROGRAM_given" ; then + INSTALL_PROGRAM='${INSTALL} $(INSTALL_STRIP_FLAG)' + fi + if test -z "$kde_save_INSTALL_SCRIPT_given" ; then + INSTALL_SCRIPT='${INSTALL}' + fi +])dnl + +AC_DEFUN([KDE_LANG_CPLUSPLUS], +[AC_LANG_CPLUSPLUS +ac_link='rm -rf SunWS_cache; ${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&AC_FD_CC' +pushdef([AC_LANG_CPLUSPLUS], [popdef([AC_LANG_CPLUSPLUS]) KDE_LANG_CPLUSPLUS]) +]) + +pushdef([AC_LANG_CPLUSPLUS], +[popdef([AC_LANG_CPLUSPLUS]) +KDE_LANG_CPLUSPLUS +]) + +AC_DEFUN([KDE_CHECK_LONG_LONG], +[ +AC_MSG_CHECKING(for long long) +AC_CACHE_VAL(kde_cv_c_long_long, +[ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + AC_TRY_LINK([], [ + long long foo = 0; + foo = foo+1; + ], + kde_cv_c_long_long=yes, kde_cv_c_long_long=no) + AC_LANG_RESTORE +]) +AC_MSG_RESULT($kde_cv_c_long_long) +if test "$kde_cv_c_long_long" = yes; then + AC_DEFINE(HAVE_LONG_LONG, 1, [Define if you have long long as datatype]) +fi +]) + +AC_DEFUN([KDE_CHECK_LIB], +[ + kde_save_LDFLAGS="$LDFLAGS" + dnl AC_CHECK_LIB modifies LIBS, so save it here + kde_save_LIBS="$LIBS" + LDFLAGS="$LDFLAGS $all_libraries" + case $host_os in + aix*) LDFLAGS="-brtl $LDFLAGS" + test "$GCC" = yes && LDFLAGS="-Wl,$LDFLAGS" + ;; + esac + AC_CHECK_LIB($1, $2, $3, $4, $5) + LDFLAGS="$kde_save_LDFLAGS" + LIBS="$kde_save_LIBS" +]) + +AC_DEFUN([KDE_JAVA_PREFIX], +[ + dir=`dirname "$1"` + base=`basename "$1"` + list=`ls -1 $dir 2> /dev/null` + for entry in $list; do + if test -d $dir/$entry/bin; then + case $entry in + $base) + javadirs="$javadirs $dir/$entry/bin" + ;; + esac + elif test -d $dir/$entry/jre/bin; then + case $entry in + $base) + javadirs="$javadirs $dir/$entry/jre/bin" + ;; + esac + fi + done +]) + +dnl KDE_CHEC_JAVA_DIR(onlyjre) +AC_DEFUN([KDE_CHECK_JAVA_DIR], +[ + +AC_ARG_WITH(java, +AC_HELP_STRING([--with-java=javadir],[use java installed in javadir, --without-java disables]), +[ ac_java_dir=$withval +], ac_java_dir="" +) + +AC_MSG_CHECKING([for Java]) + +dnl at this point ac_java_dir is either a dir, 'no' to disable, or '' to say look in $PATH +if test "x$ac_java_dir" = "xno"; then + kde_java_bindir=no + kde_java_includedir=no + kde_java_libjvmdir=no + kde_java_libgcjdir=no + kde_java_libhpidir=no +else + if test "x$ac_java_dir" = "x"; then + + + dnl No option set -> collect list of candidate paths + if test -n "$JAVA_HOME"; then + KDE_JAVA_PREFIX($JAVA_HOME) + fi + KDE_JAVA_PREFIX(/usr/j2se) + KDE_JAVA_PREFIX(/usr/lib/j2se) + KDE_JAVA_PREFIX(/usr/j*dk*) + KDE_JAVA_PREFIX(/usr/lib/j*dk*) + KDE_JAVA_PREFIX(/opt/j*sdk*) + KDE_JAVA_PREFIX(/usr/lib/java*) + KDE_JAVA_PREFIX(/usr/java*) + KDE_JAVA_PREFIX(/usr/java/j*dk*) + KDE_JAVA_PREFIX(/usr/java/j*re*) + KDE_JAVA_PREFIX(/usr/lib/SunJava2*) + KDE_JAVA_PREFIX(/usr/lib/SunJava*) + KDE_JAVA_PREFIX(/usr/lib/IBMJava2*) + KDE_JAVA_PREFIX(/usr/lib/IBMJava*) + KDE_JAVA_PREFIX(/opt/java*) + + kde_cv_path="NONE" + kde_save_IFS=$IFS + IFS=':' + for dir in $PATH; do + if test -d "$dir"; then + javadirs="$javadirs $dir" + fi + done + IFS=$kde_save_IFS + jredirs= + + dnl Now javadirs contains a list of paths that exist, all ending with bin/ + for dir in $javadirs; do + dnl Check for the java executable + if test -x "$dir/java"; then + dnl And also check for a libjvm.so somewhere under there + dnl Since we have to go to the parent dir, /usr/bin is excluded, /usr is too big. + if test "$dir" != "/usr/bin"; then + libjvmdir=`find $dir/.. -name libjvm.so | sed 's,libjvm.so,,'|head -n 1` + if test ! -f $libjvmdir/libjvm.so; then continue; fi + jredirs="$jredirs $dir" + fi + fi + done + + dnl Now jredirs contains a reduced list, of paths where both java and ../**/libjvm.so was found + JAVAC= + JAVA= + kde_java_bindir=no + for dir in $jredirs; do + JAVA="$dir/java" + kde_java_bindir=$dir + if test -x "$dir/javac"; then + JAVAC="$dir/javac" + break + fi + done + + if test -n "$JAVAC"; then + dnl this substitution might not work - well, we test for jni.h below + kde_java_includedir=`echo $JAVAC | sed -e 's,bin/javac$,include/,'` + else + kde_java_includedir=no + fi + else + dnl config option set + kde_java_bindir=$ac_java_dir/bin + if test -x $ac_java_dir/bin/java && test ! -x $ac_java_dir/bin/javac; then + kde_java_includedir=no + else + kde_java_includedir=$ac_java_dir/include + fi + fi +fi + +dnl At this point kde_java_bindir and kde_java_includedir are either set or "no" +if test "x$kde_java_bindir" != "xno"; then + + dnl Look for libjvm.so + kde_java_libjvmdir=`find $kde_java_bindir/.. -name libjvm.so | sed 's,libjvm.so,,'|head -n 1` + dnl Look for libgcj.so + kde_java_libgcjdir=`find $kde_java_bindir/.. -name libgcj.so | sed 's,libgcj.so,,'|head -n 1` + dnl Look for libhpi.so and avoid green threads + kde_java_libhpidir=`find $kde_java_bindir/.. -name libhpi.so | grep -v green | sed 's,libhpi.so,,' | head -n 1` + + dnl Now check everything's fine under there + dnl the include dir is our flag for having the JDK + if test -d "$kde_java_includedir"; then + if test ! -x "$kde_java_bindir/javac"; then + AC_MSG_ERROR([javac not found under $kde_java_bindir - it seems you passed a wrong --with-java.]) + fi + if test ! -x "$kde_java_bindir/javah"; then + AC_MSG_ERROR([javah not found under $kde_java_bindir. javac was found though! Use --with-java or --without-java.]) + fi + if test ! -x "$kde_java_bindir/jar"; then + AC_MSG_ERROR([jar not found under $kde_java_bindir. javac was found though! Use --with-java or --without-java.]) + fi + if test ! -r "$kde_java_includedir/jni.h"; then + AC_MSG_ERROR([jni.h not found under $kde_java_includedir. Use --with-java or --without-java.]) + fi + + jni_includes="-I$kde_java_includedir" + dnl Strange thing, jni.h requires jni_md.h which is under genunix here.. + dnl and under linux here.. + + dnl not needed for gcj + + if test "x$kde_java_libgcjdir" = "x"; then + test -d "$kde_java_includedir/linux" && jni_includes="$jni_includes -I$kde_java_includedir/linux" + test -d "$kde_java_includedir/solaris" && jni_includes="$jni_includes -I$kde_java_includedir/solaris" + test -d "$kde_java_includedir/genunix" && jni_includes="$jni_includes -I$kde_java_includedir/genunix" + fi + + else + JAVAC= + jni_includes= + fi + + if test "x$kde_java_libgcjdir" = "x"; then + if test ! -r "$kde_java_libjvmdir/libjvm.so"; then + AC_MSG_ERROR([libjvm.so not found under $kde_java_libjvmdir. Use --without-java.]) + fi + else + if test ! -r "$kde_java_libgcjdir/libgcj.so"; then + AC_MSG_ERROR([libgcj.so not found under $kde_java_libgcjdir. Use --without-java.]) + fi + fi + + if test ! -x "$kde_java_bindir/java"; then + AC_MSG_ERROR([java not found under $kde_java_bindir. javac was found though! Use --with-java or --without-java.]) + fi + + dnl not needed for gcj compile + + if test "x$kde_java_libgcjdir" = "x"; then + if test ! -r "$kde_java_libhpidir/libhpi.so"; then + AC_MSG_ERROR([libhpi.so not found under $kde_java_libhpidir. Use --without-java.]) + fi + fi + + if test -n "$jni_includes"; then + dnl Check for JNI version + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + ac_cxxflags_safe="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS $all_includes $jni_includes" + + AC_TRY_COMPILE([ + #include + ], + [ + #ifndef JNI_VERSION_1_2 + Syntax Error + #endif + ],[ kde_jni_works=yes ], + [ kde_jni_works=no ]) + + if test $kde_jni_works = no; then + AC_MSG_ERROR([Incorrect version of $kde_java_includedir/jni.h. + You need to have Java Development Kit (JDK) version 1.2. + + Use --with-java to specify another location. + Use --without-java to configure without java support. + Or download a newer JDK and try again. + See e.g. http://java.sun.com/products/jdk/1.2 ]) + fi + + CXXFLAGS="$ac_cxxflags_safe" + AC_LANG_RESTORE + + dnl All tests ok, inform and subst the variables + + JAVAC=$kde_java_bindir/javac + JAVAH=$kde_java_bindir/javah + JAR=$kde_java_bindir/jar + AC_DEFINE_UNQUOTED(PATH_JAVA, "$kde_java_bindir/java", [Define where your java executable is]) + if test "x$kde_java_libgcjdir" = "x"; then + JVMLIBS="-L$kde_java_libjvmdir -ljvm -L$kde_java_libhpidir -lhpi" + else + JVMLIBS="-L$kde_java_libgcjdir -lgcj" + fi + AC_MSG_RESULT([java JDK in $kde_java_bindir]) + + else + AC_DEFINE_UNQUOTED(PATH_JAVA, "$kde_java_bindir/java", [Define where your java executable is]) + AC_MSG_RESULT([java JRE in $kde_java_bindir]) + fi +elif test -d "/Library/Java/Home"; then + kde_java_bindir="/Library/Java/Home/bin" + jni_includes="-I/Library/Java/Home/include" + + JAVAC=$kde_java_bindir/javac + JAVAH=$kde_java_bindir/javah + JAR=$kde_java_bindir/jar + JVMLIBS="-Wl,-framework,JavaVM" + + AC_DEFINE_UNQUOTED(PATH_JAVA, "$kde_java_bindir/java", [Define where your java executable is]) + AC_MSG_RESULT([Apple Java Framework]) +else + AC_MSG_RESULT([none found]) +fi + +AC_SUBST(JAVAC) +AC_SUBST(JAVAH) +AC_SUBST(JAR) +AC_SUBST(JVMLIBS) +AC_SUBST(jni_includes) + +# for backward compat +kde_cv_java_includedir=$kde_java_includedir +kde_cv_java_bindir=$kde_java_bindir +]) + +dnl this is a redefinition of autoconf 2.5x's AC_FOREACH. +dnl When the argument list becomes big, as in KDE for AC_OUTPUT in +dnl big packages, m4_foreach is dog-slow. So use our own version of +dnl it. (matz@kde.org) +m4_define([mm_foreach], +[m4_pushdef([$1])_mm_foreach($@)m4_popdef([$1])]) +m4_define([mm_car], [[$1]]) +m4_define([mm_car2], [[$@]]) +m4_define([_mm_foreach], +[m4_if(m4_quote($2), [], [], + [m4_define([$1], mm_car($2))$3[]_mm_foreach([$1], + mm_car2(m4_shift($2)), + [$3])])]) +m4_define([AC_FOREACH], +[mm_foreach([$1], m4_split(m4_normalize([$2])), [$3])]) + +AC_DEFUN([KDE_NEED_FLEX], +[ +kde_libs_safe=$LIBS +LIBS="$LIBS $USER_LDFLAGS" +AM_PROG_LEX +LIBS=$kde_libs_safe +if test -z "$LEXLIB"; then + AC_MSG_ERROR([You need to have flex installed.]) +fi +AC_SUBST(LEXLIB) +]) + +AC_DEFUN([AC_PATH_QTOPIA], +[ + dnl TODO: use AC_CACHE_VAL + + if test -z "$1"; then + qtopia_minver_maj=1 + qtopia_minver_min=5 + qtopia_minver_pat=0 + else + qtopia_minver_maj=`echo "$1" | sed -e "s/^\(.*\)\..*\..*$/\1/"` + qtopia_minver_min=`echo "$1" | sed -e "s/^.*\.\(.*\)\..*$/\1/"` + qtopia_minver_pat=`echo "$1" | sed -e "s/^.*\..*\.\(.*\)$/\1/"` + fi + + qtopia_minver="$qtopia_minver_maj$qtopia_minver_min$qtopia_minver_pat" + qtopia_minverstr="$qtopia_minver_maj.$qtopia_minver_min.$qtopia_minver_pat" + + AC_REQUIRE([AC_PATH_QT]) + + AC_MSG_CHECKING([for Qtopia]) + + LIB_QTOPIA="-lqpe" + AC_SUBST(LIB_QTOPIA) + + kde_qtopia_dirs="$QPEDIR /opt/Qtopia" + + ac_qtopia_incdir=NO + + AC_ARG_WITH(qtopia-dir, + AC_HELP_STRING([--with-qtopia-dir=DIR],[where the root of Qtopia is installed]), + [ ac_qtopia_incdir="$withval"/include] ) + + qtopia_incdirs="" + for dir in $kde_qtopia_dirs; do + qtopia_incdirs="$qtopia_incdirs $dir/include" + done + + if test ! "$ac_qtopia_incdir" = "NO"; then + qtopia_incdirs="$ac_qtopia_incdir $qtopia_incdirs" + fi + + qtopia_incdir="" + AC_FIND_FILE(qpe/qpeapplication.h, $qtopia_incdirs, qtopia_incdir) + ac_qtopia_incdir="$qtopia_incdir" + + if test -z "$qtopia_incdir"; then + AC_MSG_ERROR([Cannot find Qtopia headers. Please check your installation.]) + fi + + qtopia_ver_maj=`cat $qtopia_incdir/qpe/version.h | sed -n -e 's,.*QPE_VERSION "\(.*\)\..*\..*".*,\1,p'`; + qtopia_ver_min=`cat $qtopia_incdir/qpe/version.h | sed -n -e 's,.*QPE_VERSION ".*\.\(.*\)\..*".*,\1,p'`; + qtopia_ver_pat=`cat $qtopia_incdir/qpe/version.h | sed -n -e 's,.*QPE_VERSION ".*\..*\.\(.*\)".*,\1,p'`; + + qtopia_ver="$qtopia_ver_maj$qtopia_ver_min$qtopia_ver_pat" + qtopia_verstr="$qtopia_ver_maj.$qtopia_ver_min.$qtopia_ver_pat" + if test "$qtopia_ver" -lt "$qtopia_minver"; then + AC_MSG_ERROR([found Qtopia version $qtopia_verstr but version $qtopia_minverstr +is required.]) + fi + + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + + ac_cxxflags_safe="$CXXFLAGS" + ac_ldflags_safe="$LDFLAGS" + ac_libs_safe="$LIBS" + + CXXFLAGS="$CXXFLAGS -I$qtopia_incdir $all_includes" + LDFLAGS="$LDFLAGS $QT_LDFLAGS $all_libraries $USER_LDFLAGS $KDE_MT_LDFLAGS" + LIBS="$LIBS $LIB_QTOPIA $LIBQT" + + cat > conftest.$ac_ext < +#include + +int main( int argc, char **argv ) +{ + QPEApplication app( argc, argv ); + return 0; +} +EOF + + if AC_TRY_EVAL(ac_link) && test -s conftest; then + rm -f conftest* + else + rm -f conftest* + AC_MSG_ERROR([Cannot link small Qtopia Application. For more details look at +the end of config.log]) + fi + + CXXFLAGS="$ac_cxxflags_safe" + LDFLAGS="$ac_ldflags_safe" + LIBS="$ac_libs_safe" + + AC_LANG_RESTORE + + QTOPIA_INCLUDES="-I$qtopia_incdir" + AC_SUBST(QTOPIA_INCLUDES) + + AC_MSG_RESULT([found version $qtopia_verstr with headers at $qtopia_incdir]) +]) + + +AC_DEFUN([KDE_INIT_DOXYGEN], +[ +AC_MSG_CHECKING([for Qt docs]) +kde_qtdir= +if test "${with_qt_dir+set}" = set; then + kde_qtdir="$with_qt_dir" +fi + +AC_FIND_FILE(qsql.html, [ $kde_qtdir/doc/html $QTDIR/doc/html /usr/share/doc/packages/qt3/html /usr/lib/qt/doc /usr/lib/qt3/doc /usr/lib/qt3/doc/html /usr/doc/qt3/html /usr/doc/qt3 /usr/share/doc/qt3-doc /usr/share/qt3/doc/html /usr/X11R6/share/doc/qt/html ], QTDOCDIR) +AC_MSG_RESULT($QTDOCDIR) + +AC_SUBST(QTDOCDIR) + +KDE_FIND_PATH(dot, DOT, [], []) +if test -n "$DOT"; then + KDE_HAVE_DOT="YES" +else + KDE_HAVE_DOT="NO" +fi +AC_SUBST(KDE_HAVE_DOT) +KDE_FIND_PATH(doxygen, DOXYGEN, [], []) +AC_SUBST(DOXYGEN) + +DOXYGEN_PROJECT_NAME="$1" +DOXYGEN_PROJECT_NUMBER="$2" +AC_SUBST(DOXYGEN_PROJECT_NAME) +AC_SUBST(DOXYGEN_PROJECT_NUMBER) + +KDE_HAS_DOXYGEN=no +if test -n "$DOXYGEN" && test -x "$DOXYGEN" && test -f $QTDOCDIR/qsql.html; then + KDE_HAS_DOXYGEN=yes +fi +AC_SUBST(KDE_HAS_DOXYGEN) + +]) + + +AC_DEFUN([AC_FIND_BZIP2], +[ +AC_MSG_CHECKING([for bzDecompress in libbz2]) +AC_CACHE_VAL(ac_cv_lib_bzip2, +[ +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +kde_save_LIBS="$LIBS" +LIBS="$all_libraries $USER_LDFLAGS -lbz2 $LIBSOCKET" +kde_save_CXXFLAGS="$CXXFLAGS" +CXXFLAGS="$CXXFLAGS $all_includes $USER_INCLUDES" +AC_TRY_LINK(dnl +[ +#define BZ_NO_STDIO +#include +], + [ bz_stream s; (void) bzDecompress(&s); ], + eval "ac_cv_lib_bzip2='-lbz2'", + eval "ac_cv_lib_bzip2=no") +LIBS="$kde_save_LIBS" +CXXFLAGS="$kde_save_CXXFLAGS" +AC_LANG_RESTORE +])dnl +AC_MSG_RESULT($ac_cv_lib_bzip2) + +if test ! "$ac_cv_lib_bzip2" = no; then + BZIP2DIR=bzip2 + + LIBBZ2="$ac_cv_lib_bzip2" + AC_SUBST(LIBBZ2) + +else + + cxx_shared_flag= + ld_shared_flag= + KDE_CHECK_COMPILER_FLAG(shared, [ + ld_shared_flag="-shared" + ]) + KDE_CHECK_COMPILER_FLAG(fPIC, [ + cxx_shared_flag="-fPIC" + ]) + + AC_MSG_CHECKING([for BZ2_bzDecompress in (shared) libbz2]) + AC_CACHE_VAL(ac_cv_lib_bzip2_prefix, + [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + kde_save_LIBS="$LIBS" + LIBS="$all_libraries $USER_LDFLAGS $ld_shared_flag -lbz2 $LIBSOCKET" + kde_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CFLAGS $cxx_shared_flag $all_includes $USER_INCLUDES" + + AC_TRY_LINK(dnl + [ + #define BZ_NO_STDIO + #include + ], + [ bz_stream s; (void) BZ2_bzDecompress(&s); ], + eval "ac_cv_lib_bzip2_prefix='-lbz2'", + eval "ac_cv_lib_bzip2_prefix=no") + LIBS="$kde_save_LIBS" + CXXFLAGS="$kde_save_CXXFLAGS" + AC_LANG_RESTORE + ])dnl + + AC_MSG_RESULT($ac_cv_lib_bzip2_prefix) + + if test ! "$ac_cv_lib_bzip2_prefix" = no; then + BZIP2DIR=bzip2 + + LIBBZ2="$ac_cv_lib_bzip2_prefix" + AC_SUBST(LIBBZ2) + + AC_DEFINE(NEED_BZ2_PREFIX, 1, [Define if the libbz2 functions need the BZ2_ prefix]) + dnl else, we just ignore this + fi + +fi +AM_CONDITIONAL(include_BZIP2, test -n "$BZIP2DIR") +]) + +dnl ------------------------------------------------------------------------ +dnl Try to find the SSL headers and libraries. +dnl $(SSL_LDFLAGS) will be -Lsslliblocation (if needed) +dnl and $(SSL_INCLUDES) will be -Isslhdrlocation (if needed) +dnl ------------------------------------------------------------------------ +dnl +AC_DEFUN([KDE_CHECK_SSL], +[ +LIBSSL="-lssl -lcrypto" +AC_REQUIRE([KDE_CHECK_LIB64]) + +ac_ssl_includes=NO ac_ssl_libraries=NO +ssl_libraries="" +ssl_includes="" +AC_ARG_WITH(ssl-dir, + AC_HELP_STRING([--with-ssl-dir=DIR],[where the root of OpenSSL is installed]), + [ ac_ssl_includes="$withval"/include + ac_ssl_libraries="$withval"/lib$kdelibsuff + ]) + +want_ssl=yes +AC_ARG_WITH(ssl, + AC_HELP_STRING([--without-ssl],[disable SSL checks]), + [want_ssl=$withval]) + +if test $want_ssl = yes; then + +AC_MSG_CHECKING(for OpenSSL) + +AC_CACHE_VAL(ac_cv_have_ssl, +[#try to guess OpenSSL locations + + ssl_incdirs="/usr/include /usr/local/include /usr/ssl/include /usr/local/ssl/include $prefix/include $kde_extra_includes" + ssl_incdirs="$ac_ssl_includes $ssl_incdirs" + AC_FIND_FILE(openssl/ssl.h, $ssl_incdirs, ssl_incdir) + ac_ssl_includes="$ssl_incdir" + + ssl_libdirs="/usr/lib$kdelibsuff /usr/local/lib$kdelibsuff /usr/ssl/lib$kdelibsuff /usr/local/ssl/lib$kdelibsuff $libdir $prefix/lib$kdelibsuff $exec_prefix/lib$kdelibsuff $kde_extra_libs" + if test ! "$ac_ssl_libraries" = "NO"; then + ssl_libdirs="$ac_ssl_libraries $ssl_libdirs" + fi + + test=NONE + ssl_libdir=NONE + for dir in $ssl_libdirs; do + try="ls -1 $dir/libssl*" + if test=`eval $try 2> /dev/null`; then ssl_libdir=$dir; break; else echo "tried $dir" >&AC_FD_CC ; fi + done + + ac_ssl_libraries="$ssl_libdir" + + ac_ldflags_safe="$LDFLAGS" + ac_libs_safe="$LIBS" + + LDFLAGS="$LDFLAGS -L$ssl_libdir $all_libraries" + LIBS="$LIBS $LIBSSL -lRSAglue -lrsaref" + + AC_TRY_LINK(,void RSAPrivateEncrypt(void);RSAPrivateEncrypt();, + ac_ssl_rsaref="yes" + , + ac_ssl_rsaref="no" + ) + + LDFLAGS="$ac_ldflags_safe" + LIBS="$ac_libs_safe" + + if test "$ac_ssl_includes" = NO || test "$ac_ssl_libraries" = NO; then + have_ssl=no + else + have_ssl=yes; + fi + + ]) + + eval "$ac_cv_have_ssl" + + AC_MSG_RESULT([libraries $ac_ssl_libraries, headers $ac_ssl_includes]) + + AC_MSG_CHECKING([whether OpenSSL uses rsaref]) + AC_MSG_RESULT($ac_ssl_rsaref) + + AC_MSG_CHECKING([for easter eggs]) + AC_MSG_RESULT([none found]) + +else + have_ssl=no +fi + +if test "$have_ssl" = yes; then + AC_MSG_CHECKING(for OpenSSL version) + dnl Check for SSL version + AC_CACHE_VAL(ac_cv_ssl_version, + [ + + cat >conftest.$ac_ext < +#include + int main() { + +#ifndef OPENSSL_VERSION_NUMBER + printf("ssl_version=\\"error\\"\n"); +#else + if (OPENSSL_VERSION_NUMBER < 0x00906000) + printf("ssl_version=\\"old\\"\n"); + else + printf("ssl_version=\\"ok\\"\n"); +#endif + return (0); + } +EOF + + ac_save_CPPFLAGS=$CPPFLAGS + if test "$ac_ssl_includes" != "/usr/include"; then + CPPFLAGS="$CPPFLAGS -I$ac_ssl_includes" + fi + + if AC_TRY_EVAL(ac_link); then + + if eval `./conftest 2>&5`; then + if test $ssl_version = error; then + AC_MSG_ERROR([$ssl_incdir/openssl/opensslv.h doesn't define OPENSSL_VERSION_NUMBER !]) + else + if test $ssl_version = old; then + AC_MSG_WARN([OpenSSL version too old. Upgrade to 0.9.6 at least, see http://www.openssl.org. SSL support disabled.]) + have_ssl=no + fi + fi + ac_cv_ssl_version="ssl_version=$ssl_version" + else + AC_MSG_ERROR([Your system couldn't run a small SSL test program. + Check config.log, and if you can't figure it out, send a mail to + David Faure , attaching your config.log]) + fi + + else + AC_MSG_ERROR([Your system couldn't link a small SSL test program. + Check config.log, and if you can't figure it out, send a mail to + David Faure , attaching your config.log]) + fi + CPPFLAGS=$ac_save_CPPFLAGS + + ]) + + eval "$ac_cv_ssl_version" + AC_MSG_RESULT($ssl_version) +fi + +if test "$have_ssl" != yes; then + LIBSSL=""; +else + AC_DEFINE(HAVE_SSL, 1, [If we are going to use OpenSSL]) + ac_cv_have_ssl="have_ssl=yes \ + ac_ssl_includes=$ac_ssl_includes ac_ssl_libraries=$ac_ssl_libraries ac_ssl_rsaref=$ac_ssl_rsaref" + + if test "$have_ssl" = "yes"; then + AC_DEFINE(ENABLE_OPENSSL, 1, [Use OpenSSL]) + fi + + ssl_libraries="$ac_ssl_libraries" + ssl_includes="$ac_ssl_includes" + + if test "$ac_ssl_rsaref" = yes; then + LIBSSL="-lssl -lcrypto -lRSAglue -lrsaref" + fi + + if test $ssl_version = "old"; then + AC_DEFINE(HAVE_OLD_SSL_API, 1, [Define if you have OpenSSL < 0.9.6]) + fi +fi + +SSL_INCLUDES= + +if test "$ssl_includes" = "/usr/include"; then + if test -f /usr/kerberos/include/krb5.h; then + SSL_INCLUDES="-I/usr/kerberos/include" + fi +elif test "$ssl_includes" != "/usr/local/include" && test -n "$ssl_includes"; then + SSL_INCLUDES="-I$ssl_includes" +fi + +if test "$ssl_libraries" = "/usr/lib" || test "$ssl_libraries" = "/usr/local/lib" || test -z "$ssl_libraries" || test "$ssl_libraries" = "NONE"; then + SSL_LDFLAGS="" +else + SSL_LDFLAGS="-L$ssl_libraries -R$ssl_libraries" +fi + +AC_SUBST(SSL_INCLUDES) +AC_SUBST(SSL_LDFLAGS) +AC_SUBST(LIBSSL) +]) + +AC_DEFUN([KDE_CHECK_STRLCPY], +[ + AC_REQUIRE([AC_CHECK_STRLCAT]) + AC_REQUIRE([AC_CHECK_STRLCPY]) + AC_CHECK_SIZEOF(size_t) + AC_CHECK_SIZEOF(unsigned long) + + AC_MSG_CHECKING([sizeof size_t == sizeof unsigned long]) + AC_TRY_COMPILE(,[ + #if SIZEOF_SIZE_T != SIZEOF_UNSIGNED_LONG + choke me + #endif + ],AC_MSG_RESULT([yes]),[ + AC_MSG_RESULT(no) + AC_MSG_ERROR([ + Apparently on your system our assumption sizeof size_t == sizeof unsigned long + does not apply. Please mail kde-devel@kde.org with a description of your system! + ]) + ]) +]) + +AC_DEFUN([KDE_CHECK_BINUTILS], +[ + AC_MSG_CHECKING([if ld supports unversioned version maps]) + + kde_save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -Wl,--version-script=conftest.map" + echo "{ local: extern \"C++\" { foo }; };" > conftest.map + AC_TRY_LINK([int foo;], +[ +#ifdef __INTEL_COMPILER +icc apparently does not support libtools version-info and version-script +at the same time. Dunno where the bug is, but until somebody figured out, +better disable the optional version scripts. +#endif + + foo = 42; +], kde_supports_versionmaps=yes, kde_supports_versionmaps=no) + LDFLAGS="$kde_save_LDFLAGS" + rm -f conftest.map + AM_CONDITIONAL(include_VERSION_SCRIPT, + [test "$kde_supports_versionmaps" = "yes" && test "$kde_use_debug_code" = "no"]) + + AC_MSG_RESULT($kde_supports_versionmaps) +]) + +AC_DEFUN([AM_PROG_OBJC],[ +AC_CHECK_PROGS(OBJC, gcc, gcc) +test -z "$OBJC" && AC_MSG_ERROR([no acceptable objective-c gcc found in \$PATH]) +if test "x${OBJCFLAGS-unset}" = xunset; then + OBJCFLAGS="-g -O2" +fi +AC_SUBST(OBJCFLAGS) +_AM_IF_OPTION([no-dependencies],, [_AM_DEPENDENCIES(OBJC)]) +]) + +AC_DEFUN([KDE_CHECK_PERL], +[ + KDE_FIND_PATH(perl, PERL, [$bindir $exec_prefix/bin $prefix/bin], [ + AC_MSG_ERROR([No Perl found in your $PATH. +We need perl to generate some code.]) + ]) + AC_SUBST(PERL) +]) + +AC_DEFUN([KDE_CHECK_LARGEFILE], +[ +AC_SYS_LARGEFILE +if test "$ac_cv_sys_file_offset_bits" != no; then + CPPFLAGS="$CPPFLAGS -D_FILE_OFFSET_BITS=$ac_cv_sys_file_offset_bits" +fi + +if test "x$ac_cv_sys_large_files" != "xno"; then + CPPFLAGS="$CPPFLAGS -D_LARGE_FILES=1" +fi + +]) + +dnl A small extension to PKG_CHECK_MODULES (defined in pkg.m4.in) +dnl which allows to search for libs that get installed into the KDE prefix. +dnl +dnl Syntax: KDE_PKG_CHECK_MODULES(KSTUFF, libkexif >= 0.2 glib = 1.3.4, action-if, action-not) +dnl defines KSTUFF_LIBS, KSTUFF_CFLAGS, see pkg-config man page +dnl also defines KSTUFF_PKG_ERRORS on error +AC_DEFUN([KDE_PKG_CHECK_MODULES], [ + + PKG_CONFIG_PATH="$prefix/lib${kdelibsuff}/pkgconfig:$PKG_CONFIG_PATH" + if test "$prefix" != "$kde_libs_prefix"; then + PKG_CONFIG_PATH="$kde_libs_prefix/lib${kdelibsuff}/pkgconfig:$PKG_CONFIG_PATH" + fi + export PKG_CONFIG_PATH + PKG_CHECK_MODULES([$1],[$2],[$3],[$4]) +]) + + +dnl Check for PIE support in the compiler and linker +AC_DEFUN([KDE_CHECK_PIE_SUPPORT], +[ + AC_CACHE_CHECK([for PIE support], kde_cv_val_pie_support, + [ + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + safe_CXXFLAGS=$CXXFLAGS + safe_LDFLAGS=$LDFLAGS + CXXFLAGS="$CXXFLAGS -fPIE" + LDFLAGS="$LDFLAGS -pie" + + AC_TRY_LINK([int foo;], [], [kde_cv_val_pie_support=yes], [kde_cv_val_pie_support=no]) + + CXXFLAGS=$safe_CXXFLAGS + LDFLAGS=$safe_LDFLAGS + AC_LANG_RESTORE + ]) + + AC_MSG_CHECKING(if enabling -pie/fPIE support) + + AC_ARG_ENABLE(pie, + AC_HELP_STRING([--enable-pie],[platform supports PIE linking [default=detect]]), + [kde_has_pie_support=$enableval], + [kde_has_pie_support=detect]) + + if test "$kde_has_pie_support" = "detect"; then + kde_has_pie_support=$kde_cv_val_pie_support + fi + + AC_MSG_RESULT([$kde_has_pie_support]) + + KDE_USE_FPIE="" + KDE_USE_PIE="" + + AC_SUBST([KDE_USE_FPIE]) + AC_SUBST([KDE_USE_PIE]) + + if test "$kde_has_pie_support" = "yes"; then + KDE_USE_FPIE="-fPIE" + KDE_USE_PIE="-pie" + fi +]) diff --git a/admin/am_edit b/admin/am_edit new file mode 100644 index 0000000..a1a9e35 --- /dev/null +++ b/admin/am_edit @@ -0,0 +1,2441 @@ +#!/usr/bin/perl -w + +# Expands the specialised KDE tags in Makefile.in to (hopefully) valid +# make syntax. +# When called without file parameters, we work recursively on all Makefile.in +# in and below the current subdirectory. When called with file parameters, +# only those Makefile.in are changed. +# The currently supported tags are +# +# {program}_METASOURCES +# where you have a choice of two styles +# {program}_METASOURCES = name1.moc name2.moc ... [\] +# {program}_METASOURCES = AUTO +# The second style requires other tags as well. +# +# To install icons : +# KDE_ICON = iconname iconname2 ... +# KDE_ICON = AUTO +# +# For documentation : +# http://developer.kde.org/documentation/other/developer-faq.html +# +# and more new tags TBD! +# +# The concept (and base code) for this program came from automoc, +# supplied by the following +# +# Matthias Ettrich (The originator) +# Kalle Dalheimer (The original implementator) +# Harri Porten +# Alex Zepeda +# David Faure +# Stephan Kulow +# Dirk Mueller + +use Cwd; +use File::Find; +use File::Basename; + +# Prototype the functions +sub initialise (); +sub processMakefile ($); +sub updateMakefile (); +sub restoreMakefile (); + +sub removeLine ($$); +sub appendLines ($); +sub substituteLine ($$); + +sub findMocCandidates (); +sub pruneMocCandidates ($); +sub checkMocCandidates (); +sub addMocRules (); +sub findKcfgFile($); + +sub tag_AUTOMAKE (); +sub tag_META_INCLUDES (); +sub tag_METASOURCES (); +sub tag_POFILES (); +sub tag_DOCFILES (); +sub tag_LOCALINSTALL(); +sub tag_IDLFILES(); +sub tag_UIFILES(); +sub tag_KCFGFILES(); +sub tag_SUBDIRS(); +sub tag_ICON(); +sub tag_CLOSURE(); +sub tag_NO_UNDEFINED(); +sub tag_NMCHECK(); +sub tag_DIST(); +sub tag_KDEINIT(); + +# Some global globals... +$verbose = 0; # a debug flag +$thisProg = "$0"; # This programs name +$topdir = cwd(); # The current directory +@makefiles = (); # Contains all the files we'll process +@foreignfiles = (); +$start = (times)[0]; # some stats for testing - comment out for release +$version = "v0.2"; +$errorflag = 0; +$cppExt = "(cpp|cc|cxx|C|c\\+\\+)"; +$hExt = "(h|H|hh|hxx|hpp|h\\+\\+)"; +$progId = "KDE tags expanded automatically by " . basename($thisProg); +$automkCall = "\n"; +$printname = ""; # used to display the directory the Makefile is in +$use_final = 1; # create code for --enable-final +$cleantarget = "clean"; +$dryrun = 0; +$pathoption = 0; +$foreign_libtool = 0; + +while (defined ($ARGV[0])) +{ + $_ = shift; + if (/^--version$/) + { + print STDOUT "\n"; + print STDOUT basename($thisProg), " $version\n", + "This is really free software, unencumbered by the GPL.\n", + "You can do anything you like with it except sueing me.\n", + "Copyright 1998 Kalle Dalheimer \n", + "Concept, design and unnecessary questions about perl\n", + " by Matthias Ettrich \n\n", + "Making it useful by Stephan Kulow and\n", + "Harri Porten \n", + "Updated (Feb-1999), John Birch \n", + "Fixes and Improvements by Dirk Mueller \n", + "Current Maintainer Stephan Kulow\n\n"; + exit 0; + } + elsif (/^--verbose$|^-v$/) + { + $verbose = 1; # Oh is there a problem...? + } + elsif (/^(?:-p|--path=)(.+)$/) + { + my $p = $1; + $thisProg = $p . "/". basename($thisProg); + warn ("$thisProg doesn't exist\n") if (!(-f $thisProg)); + $thisProg .= " -p".$p; + $pathoption=1; + } + elsif (/^--help$|^-h$/) + { + print STDOUT "Usage $thisProg [OPTION] ... [dir/Makefile.in]...\n", + "\n", + "Patches dir/Makefile.in generated by automake\n", + "(where dir can be an absolute or relative directory name)\n", + "\n", + " -v, --verbose verbosely list files processed\n", + " -h, --help print this help, then exit\n", + " --version print version number, then exit\n", + " -p, --path= use the path to am_edit if the path\n", + " called from is not the one to be used\n", + " --no-final don't patch for --enable-final\n"; + + exit 0; + } + elsif (/^--no-final$/) + { + $use_final = 0; + $thisProg .= " --no-final"; + } + elsif (/^--foreign-libtool$/) + { + $foreign_libtool = 1; + $thisProg .= " --foreign-libtool"; + } + elsif (/^-n$/) + { + $dryrun = 1; + } + else + { + # user selects what input files to check + # add full path if relative path is given + $_ = cwd()."/".$_ if (! /^\//); + print "User wants $_\n" if ($verbose); + push (@makefiles, $_); + } +} + +if ($thisProg =~ /^\// && !$pathoption ) +{ + print STDERR "Illegal full pathname call performed...\n", + "The call to \"$thisProg\"\nwould be inserted in some Makefile.in.\n", + "Please use option --path.\n"; + exit 1; +} + +# Only scan for files when the user hasn't entered data +if (!@makefiles) +{ + print STDOUT "Scanning for Makefile.in\n" if ($verbose); + find (\&add_makefile, cwd()); + #chdir('$topdir'); +} else { + print STDOUT "Using input files specified by user\n" if ($verbose); +} + +foreach $makefile (sort(@makefiles)) +{ + processMakefile ($makefile); + last if ($errorflag); +} + +# Just some debug statistics - comment out for release as it uses printf. +printf STDOUT "Time %.2f CPU sec\n", (times)[0] - $start if ($verbose); + +exit $errorflag; # causes make to fail if erroflag is set + +#----------------------------------------------------------------------------- + +# In conjunction with the "find" call, this builds the list of input files +sub add_makefile () +{ + push (@makefiles, $File::Find::name) if (/Makefile.in$/); +} + +#----------------------------------------------------------------------------- + +# Processes a single make file +# The parameter contains the full path name of the Makefile.in to use +sub processMakefile ($) +{ + # some useful globals for the subroutines called here + local ($makefile) = @_; + local @headerdirs = ('.'); + local $haveAutomocTag = 0; + local $MakefileData = ""; + + local $cxxsuffix = "KKK"; + + local @programs = (); # lists the names of programs and libraries + local $program = ""; + + local @kdeinits = (); # lists the kdeinit targets + + local %realObjs = (); # lists the objects compiled into $program + local %sources = (); # lists the sources used for $program + local %finalObjs = (); # lists the objects compiled when final + local %realname = (); # the binary name of program variable + local %idlfiles = (); # lists the idl files used for $program + local %globalmocs = ();# list of all mocfiles (in %mocFiles format) + local %important = (); # list of files to be generated asap + local %uiFiles = (); + local %kcfgFiles = (); + + local $allidls = ""; + local $idl_output = "";# lists all idl generated files for cleantarget + local $ui_output = "";# lists all uic generated files for cleantarget + local $kcfg_output = "";# lists all kcfg generated files for cleantarget + + local %dependmocs = (); + + local $metasourceTags = 0; + local $dep_files = ""; + local $dep_finals = ""; + local %target_adds = (); # the targets to add + local %rule_adds = (); + local $kdelang = ""; + local @cleanfiles = (); + local $cleanMoc = ""; + local $closure_output = ""; + + local %varcontent = (); + + $makefileDir = dirname($makefile); + chdir ($makefileDir); + $printname = $makefile; + $printname =~ s/^\Q$topdir\E\///; + $makefile = basename($makefile); + + print STDOUT "Processing makefile $printname\n" if ($verbose); + + # Setup and see if we need to do this. + return if (!initialise()); + + tag_AUTOMAKE (); # Allows a "make" to redo the Makefile.in + tag_META_INCLUDES (); # Supplies directories for src locations + + foreach $program (@programs) { + $sources_changed{$program} = 0; + $dependmocs{$program} = ""; + $important{$program} = ""; + tag_IDLFILES(); # Sorts out idl rules + tag_NO_UNDEFINED(); + tag_CLOSURE(); + tag_NMCHECK(); + tag_UIFILES(); # Sorts out ui rules + tag_KCFGFILES(); # Sorts out kcfg rules + tag_METASOURCES (); # Sorts out the moc rules + if ($sources_changed{$program}) { + my $lookup = $program . '_SOURCES\s*=[ \t]*(.*)'; + + if($program =~ /libkdeinit_(.*)/) { + my $prog = $1; + substituteLine($prog . '_SOURCES\s*=[ \t]*(.*)', + "${prog}_SOURCES = ${prog}_dummy.$cxxsuffix\n" . + "libkdeinit_${prog}_SOURCES = " . $sources{$program}); + $sources{$prog} = "${prog}_dummy.$cxxsuffix"; + } + else { + substituteLine($lookup, "$program\_SOURCES=" . $sources{$program}); + } + } + if ($important{$program}) { + local %source_dict = (); + for $source (split(/[\034\s]+/, $sources{$program})) { + $source_dict{$source} = 1; + } + for $source (@cleanfiles) { + $source_dict{$source} = 0; + } + for $source (keys %source_dict) { + next if (!$source); + if ($source_dict{$source}) { + # sanity check + if (! -f $source) { + print STDERR "Error: $source is listed in a _SOURCE line in $printname, but doesn't exist yet. Put it in DISTCLEANFILES!\n"; + } else { + $target_adds{"\$(srcdir)/$source"} .= $important{$program}; + } + } + } + } + } + if ($cleanMoc) { + # Always add dist clean tag + # Add extra *.moc.cpp files created for USE_AUTOMOC because they + # aren't included in the normal *.moc clean rules. + appendLines ("$cleantarget-metasources:\n\t-rm -f $cleanMoc\n"); + $target_adds{"$cleantarget-am"} .= "$cleantarget-metasources "; + } + + tag_DIST() unless ($kdeopts{"noautodist"}); + + if ($idl_output) { + appendLines ("$cleantarget-idl:\n\t-rm -f $idl_output\n"); + $target_adds{"$cleantarget-am"} .= "$cleantarget-idl "; + } + + if ($ui_output) { + appendLines ("$cleantarget-ui:\n\t-rm -f $ui_output\n"); + $target_adds{"$cleantarget-am"} .= "$cleantarget-ui "; + } + + if ($kcfg_output) { + appendLines ("$cleantarget-kcfg:\n\t-rm -f $kcfg_output\n"); + $target_adds{"$cleantarget-am"} .= "$cleantarget-kcfg "; + } + + if ($closure_output) { + appendLines ("$cleantarget-closures:\n\t-rm -f $closure_output\n"); + $target_adds{"$cleantarget-am"} .= "$cleantarget-closures "; + } + + if ($MakefileData =~ /\nKDE_LANG\s*=\s*(\S*)\s*\n/) { + $kdelang = '$(KDE_LANG)' + } else { + $kdelang = ''; + } + + tag_POFILES (); # language rules for po directory + tag_DOCFILES (); # language rules for doc directories + tag_LOCALINSTALL(); # add $(DESTDIR) before all kde_ dirs + tag_ICON(); + tag_SUBDIRS(); + + my $tmp = "force-reedit:\n"; + $tmp .= "\t$automkCall\n\tcd \$(top_srcdir) && perl $thisProg $printname\n\n"; + appendLines($tmp); + + make_bcheck_target(); + make_meta_classes(); + tag_COMPILE_FIRST(); + tag_FINAL() if (!$kdeopts{"nofinal"}); + + my $final_lines = "final:\n\t\$(MAKE) "; + my $final_install_lines = "final-install:\n\t\$(MAKE) "; + my $nofinal_lines = "no-final:\n\t\$(MAKE) "; + my $nofinal_install_lines = "no-final-install:\n\t\$(MAKE) "; + + foreach $program (@programs) { + my $lookup = $program . '_OBJECTS\s*=[ \t]*.*'; + my $new = ""; + my @list = split(/[\034\s]+/, $realObjs{$program}); + if (!$kdeopts{"nofinal"} && @list > 1 && $finalObjs{$program}) { + $new .= "$program\_final\_OBJECTS = " . $finalObjs{$program}; + $new .= "\n$program\_nofinal\_OBJECTS = " . $realObjs{$program}; + $new .= "\n\@KDE_USE_FINAL_FALSE\@$program\_OBJECTS = \$($program\_nofinal\_OBJECTS)"; + $new .= "\n\@KDE_USE_FINAL_TRUE\@$program\_OBJECTS = \$($program\_final\_OBJECTS)"; + + $final_lines .= "$program\_OBJECTS=\"\$($program\_final_OBJECTS)\" "; + $final_install_lines .= "$program\_OBJECTS=\"\$($program\_final_OBJECTS)\" "; + $nofinal_lines .= "$program\_OBJECTS=\"\$($program\_nofinal\_OBJECTS)\" "; + $nofinal_install_lines .= "$program\_OBJECTS=\"\$($program\_nofinal_OBJECTS)\" "; + } else { + $new = "$program\_OBJECTS = " . $realObjs{$program}; + } + if($MakefileData =~ m/\n$lookup/) { + substituteLine ($lookup, $new); + } + else { + appendLines("$new\n"); + } + } + appendLines($final_lines . "all-am\n"); + appendLines($final_install_lines . "install-am\n"); + appendLines($nofinal_lines . "all-am\n"); + appendLines($nofinal_install_lines . "install-am\n"); + + my $lookup = '(\@\S+\@)?DEP_FILES\s*=[ \t]*(.*)'; + if ($MakefileData =~ /\n$lookup/) { + my $condition = $1; + my $depfiles = $2; + my $workfiles; + + if ($dep_finals) { + # Add the conditions on every line, since + # there may be line continuations in the list. + $workfiles = "$dep_files $dep_finals $depfiles"; + $workfiles =~ s/\034/\034$condition\@KDE_USE_FINAL_TRUE\@\t/g; + $lines = "$condition\@KDE_USE_FINAL_TRUE\@DEP_FILES = $workfiles\n"; + $workfiles = "$dep_files $depfiles"; + $workfiles =~ s/\034/\034$condition\@KDE_USE_FINAL_FALSE\@\t/g; + $lines .= "$condition\@KDE_USE_FINAL_FALSE\@DEP_FILES = $workfiles"; + } else { + $workfiles = "$dep_files $depfiles"; + $workfiles =~ s/\034/\034$condition\t/g; + $lines = $condition . "DEP_FILES = $workfiles"; + } + substituteLine($lookup, $lines); + } + + # new recursive targets + $target_adds{ "nmcheck" } .= ""; # always create nmcheck target + $target_adds{ "nmcheck-am" } .= "nmcheck"; + $lookup = 'RECURSIVE_TARGETS\s*=[ \t]*(.*)'; + if ($MakefileData =~ /\n$lookup/) { + substituteLine($lookup, "RECURSIVE_TARGETS = $1 nmcheck-recursive bcheck-recursive"); + } + + $cvs_lines = "kde-rpo-clean:\n"; + $cvs_lines .= "\t-rm -f *.rpo\n"; + appendLines($cvs_lines); + $target_adds{"clean"} .= "kde-rpo-clean "; + + my %target_dels = ("install-data-am" => ""); + + # some strange people like to do a install-exec, and expect that also + # all modules are installed. automake doesn't know this, so we need to move + # this here from install-data to install-exec. + if ($MakefileData =~ m/\nkde_module_LTLIBRARIES\s*=/) { +# $target_adds{"install-exec-am"} .= "install-kde_moduleLTLIBRARIES "; +# don't use $target_adds here because we need to append the dependency, not +# prepend it. Fixes #44342 , when a module depends on a lib in the same dir +# and libtool needs it during relinking upon install (Simon) + my $lookup = "install-exec-am:([^\n]*)"; + if($MakefileData =~ /\n$lookup\n/) { + substituteLine("$lookup", "install-exec-am: $1 install-kde_moduleLTLIBRARIES"); + } + $target_dels{"install-data-am"} .= "install-kde_moduleLTLIBRARIES "; + $target_adds{"install-data-am"} .= " "; + } + + my $lines = ""; + + foreach $add (keys %target_adds) { + my $lookup = quotemeta($add) . ':([^\n]*)'; + if ($MakefileData =~ /\n$lookup\n/) { + my $newlines = $1; + my $oldlines = $lookup; + if (defined $target_dels{$add}) { + foreach $del (split(' ', $target_dels{$add})) { + $newlines =~ s/\s*$del\s*/ /g; + } + } + substituteLine($oldlines, "$add: " . $target_adds{$add} . $newlines); + } else { + $lines .= "$add: " . $target_adds{$add} . "\n"; + } + } + + appendLines($lines) if ($lines); + + $lines = join("\n", values %rule_adds); + appendLines($lines) if ($lines); + + my $found = 1; + + while ($found) { + if ($MakefileData =~ m/\n(.*)\$\(CXXFLAGS\)(.*)\n/) { + my $stuff_before = $1; + my $stuff_after = $2; + my $lookup = quotemeta("$1\$(CXXFLAGS)$2"); + my $replacement = "$1\$(KCXXFLAGS)$2"; + $MakefileData =~ s/$lookup/$replacement/; + $lookup =~ s/\\\$\\\(CXXFLAGS\\\)/\\\$\\\(KCXXFLAGS\\\)/; + $replacement = "$stuff_before\$(KCXXFLAGS) \$(KDE_CXXFLAGS)$stuff_after"; + next if ($stuff_before =~ /\$\(KDE_CXXFLAGS\)/ or $stuff_after =~ /\$\(KDE_CXXFLAGS\)/); + substituteLine($lookup, $replacement); + } else { + $found = 0; + } + } + + if($foreign_libtool == 0) { + $lookup = '(\n[^#].*\$\(LIBTOOL\) --mode=link) (\$\(CXXLD\).*\$\(KCXXFLAGS\))'; + + if ($MakefileData =~ m/$lookup/ ) { + $MakefileData =~ s/$lookup/$1 --tag=CXX $2/; + } + + $lookup = '(\n[^#].*\$\(LIBTOOL\) --mode=compile)\s+(\$\(CXX\)\s+)'; + if ($MakefileData =~ m/$lookup/ ) { + $MakefileData =~ s/$lookup/$1 --tag=CXX $2/; + } + } + + $MakefileData =~ s/\$\(KCXXFLAGS\)/\$\(CXXFLAGS\)/g; + + $lookup = '(.*)cp -pr \$\$/\$\$file \$\(distdir\)/\$\$file(.*)'; + if ($MakefileData =~ m/\n$lookup\n/) { + substituteLine($lookup, "$1cp -pr \$\$d/\$\$file \$(distdir)/\$\$file$2"); + } + + # Always update the Makefile.in + updateMakefile (); + return; +} + +#----------------------------------------------------------------------------- + +# Beware: This procedure is not complete. E.g. it also parses lines +# containing a '=' in rules (for instance setting shell vars). For our +# usage this us enough, though. +sub read_variables () +{ + while ($MakefileData =~ /\n\s*(\S+)\s*=([^\n]*)/g) { + $varcontent{$1} = $2; + } +} + +# Check to see whether we should process this make file. +# This is where we look for tags that we need to process. +# A small amount of initialising on the tags is also done here. +# And of course we open and/or create the needed make files. +sub initialise () +{ + if (! -r "Makefile.am") { + print STDOUT "found Makefile.in without Makefile.am\n" if ($verbose); + return 0; + } + + # Checking for files to process... + + open (FILEIN, $makefile) || die "Can't open $makefileDir/$makefile: $!\n"; + # perl bug in 5.8.0: in utf8 mode it badly screws up + binmode(FILEIN, ":bytes") if ($] >= 5.008); + # Read the file + # stat(FILEIN)[7] might look more elegant, but is slower as it + # requires stat'ing the file + seek(FILEIN, 0, 2); + my $fsize = tell(FILEIN); + seek(FILEIN, 0, 0); + read FILEIN, $MakefileData, $fsize; + close FILEIN; + print "DOS CRLF within $makefileDir/$makefile!\n" if($MakefileData =~ y/\r//d); + + # Remove the line continuations, but keep them marked + # Note: we lose the trailing spaces but that's ok. + # Don't mangle line-leading spaces (usually tabs) + # since they're important. + $MakefileData =~ s/\\\s*\n/\034/g; + + # If we've processed the file before... + restoreMakefile () if ($MakefileData =~ /$progId/); + + foreach $dir (@foreignfiles) { + if (substr($makefileDir,0,length($dir)) eq $dir) { + return 0; + } + } + + %kdeopts = (); + $kdeopts{"foreign"} = 0; + $kdeopts{"qtonly"} = 0; + $kdeopts{"noautodist"} = 0; + $kdeopts{"foreign-libtool"} = $foreign_libtool; + $kdeopts{"nofinal"} = !$use_final; # default + + read_variables(); + + if ($MakefileData =~ /\nKDE_OPTIONS\s*=[ \t]*([^\n]*)\n/) { + my $kde_options_str = $1; + local @kde_options = split(/[\034\s]+/, $kde_options_str); + if (grep(/^foreign$/, @kde_options)) { + push(@foreignfiles, $makefileDir . "/"); + return 0; # don't touch me + } + for $opt (@kde_options) { + if (!defined $kdeopts{$opt}) { + print STDERR "Warning: unknown option $opt in $printname\n"; + } else { + $kdeopts{$opt} = 1; + } + } + } + + # Look for the tags that mean we should process this file. + $metasourceTags = 0; + $metasourceTags++ while ($MakefileData =~ /\n[^=\#]*METASOURCES\s*=/g); + + my $pofileTag = 0; + $pofileTag++ while ($MakefileData =~ /\nPOFILES\s*=/g); + if ($pofileTag > 1) + { + print STDERR "Error: Only one POFILES tag allowed\n"; + $errorflag = 1; + } + + while ($MakefileData =~ /\n\.SUFFIXES:([^\n]+)\n/g) { + my $suffixes_str = $1; + my @list=split(' ', $suffixes_str); + foreach $ext (@list) { + if ($ext =~ /^\.$cppExt$/) { + $cxxsuffix = $ext; + $cxxsuffix =~ s/\.//g; + print STDOUT "will use suffix $cxxsuffix\n" if ($verbose); + last; + } + } + } + + tag_KDEINIT(); + + while ($MakefileData =~ /\n(\S*)_OBJECTS\s*=[\034 \t]*([^\n]*)\n/g) { + + my $program = $1; + my $objs = $2; # safe them + + my $ocv = 0; + + my @objlist = split(/[\034\s]+/, $objs); + foreach $obj (@objlist) { + if ($obj =~ /(\S*)\$\((\S+)\)/ ) { + my $pre = $1; + my $variable = $2; + if ($pre eq '' && exists($varcontent{$variable})) { + my @addlist = split(/[\034\s]+/, $varcontent{$variable}); + push(@objlist, @addlist); + } elsif ($variable !~ 'OBJEXT' && $variable !~ /am__objects_\d+/ ) { + $ocv = 1; + } + } + } + + next if ($ocv); + next if ($program =~ /^am_libkdeinit_/); + + $program =~ s/^am_// if ($program =~ /^am_/); + + my $sourceprogram = $program; + $sourceprogram =~ s/\@am_/\@/ if($sourceprogram =~ /^.*\@am_.+/); + + print STDOUT "found program $program\n" if ($verbose); + push(@programs, $program); + + $realObjs{$program} = $objs; + + if ($MakefileData =~ /\n$sourceprogram\_SOURCES\s*=[ \t]*(.*)\n/) { + $sources{$program} = $1; + } + else { + $sources{$program} = ""; + print STDERR "found program with no _SOURCES: $program\n"; + } + + my $realprogram = $program; + $realprogram =~ s/_/./g; # unmask to regexp + if ($MakefileData =~ /\n($realprogram)(\$\(EXEEXT\)?)?:.*\$\($program\_OBJECTS\)/) { + $realname{$program} = $1; + } else { + # not standard Makefile - nothing to worry about + $realname{$program} = ""; + } + } + + my $lookup = 'DEPDIR\s*=.*'; + if ($MakefileData !~ /\n$lookup/) { + $lookup = 'bindir\s*=[ \t]*.*'; + substituteLine($lookup, "DEPDIR = .deps\n$1") if ($MakefileData =~ /\n($lookup)/); + } + + my @marks = ('MAINTAINERCLEANFILES', 'CLEANFILES', 'DISTCLEANFILES'); + foreach $mark (@marks) { + while ($MakefileData =~ /\n($mark)\s*=[ \t]*([^\n]*)/g) { + my $clean_str = $2; + foreach $file (split('[\034\s]+', $clean_str)) { + $file =~ s/\.\///; + push(@cleanfiles, $file); + } + } + } + + my $localTag = 0; + $localTag++ if ($MakefileData =~ /\ninstall-\S+-local:/); + + return (!$errorflag); +} + +#----------------------------------------------------------------------------- + +# Gets the list of user defined directories - relative to $srcdir - where +# header files could be located. +sub tag_META_INCLUDES () +{ + my $lookup = '[^=\n]*META_INCLUDES\s*=[ \t]*(.*)'; + return 1 if ($MakefileData !~ /($lookup)\n/); + print STDOUT "META_INCLUDE processing <$1>\n" if ($verbose); + + my $headerStr = $2; + removeLine ($lookup, $1); + + my @headerlist = split(/[\034\s]+/, $headerStr); + + foreach $dir (@headerlist) + { + $dir =~ s#\$\(srcdir\)#.#; + if (! -d $dir) + { + print STDERR "Warning: $dir can't be found. ", + "Must be a relative path to \$(srcdir)\n"; + } + else + { + push (@headerdirs, $dir); + } + } + + return 0; +} + +#----------------------------------------------------------------------------- + +sub tag_FINAL() +{ + my @final_names = (); + + foreach $program (@programs) { + + if ($sources{$program} =~ /\(/) { + print STDOUT "found ( in $program\_SOURCES. skipping\n" if ($verbose); + next; + } + + my $mocs = ""; # Moc files (in this program) + my $moc_cpp_added = 0; # If we added some .moc.cpp files, due to + # no other .cpp file including the .moc one. + + my @progsources = split(/[\034\s]+/, $sources{$program}); + my %shash = (); + @shash{@progsources} = 1; # we are only interested in the existence + my %sourcelist = (); + my %extradeps = (); + + foreach $source (@progsources) { + my $suffix = $source; + $suffix =~ s/^.*\.([^\.]+)$/$1/; + + $sourcelist{$suffix} .= "$source "; + } + foreach my $mocFile (keys (%globalmocs)) + { + my ($dir, $hFile, $cppFile) = split ("\035", $globalmocs{$mocFile}, 3); + if (defined ($cppFile)) { + $mocs .= " $mocFile.moc" if exists $shash{$cppFile}; + } else { + $sourcelist{$cxxsuffix} .= "$mocFile.moc.$cxxsuffix "; + $moc_cpp_added = 1; + } + } + + # scan for extra given dependencies and add them to our target + while ($MakefileData =~ /\n\s*(\S+)\.(?:lo|o)\s*:([^\n]*)/g) { + $extradeps{$1} = $2; + } + + foreach $suffix (keys %sourcelist) { + # See if this file contains c++ code. (i.e., just check the file's suffix against c++ extensions) + my $suffix_is_cxx = 0; + if($suffix =~ /($cppExt)$/) { + $cxxsuffix = $1; + $suffix_is_cxx = 1; + } + + my $mocfiles_in = ($suffix eq $cxxsuffix) && $moc_cpp_added; + + my @sourcelist = split(/[\034\s]+/, $sourcelist{$suffix}); + + if ((@sourcelist == 1 && !$mocfiles_in) || $suffix_is_cxx != 1 ) { + + # we support IDL on our own + if ($suffix eq "skel" || $suffix =~ /^stub/ + || $suffix =~ /^signals/ # obsolete, remove in KDE-4 + || $suffix eq "h" || $suffix eq "ui" + || $suffix eq "kcfgc" ) { + next; + } + + foreach $file (@sourcelist) { + $file =~ s/\Q$suffix\E$//; + + $finalObjs{$program} .= $file; + if ($program =~ /_la$/) { + $finalObjs{$program} .= "lo "; + } else { + $finalObjs{$program} .= "o "; + } + } + next; # suffix + } + + my $source_deps = ""; + foreach $source (@sourcelist) { + if (-f $source) { + $source_deps .= " \$(srcdir)/$source"; + } else { + $source_deps .= " $source"; + } + my $plainsource = $source; + $plainsource =~ s/\.$cppExt$//; + $source_deps .= " " . $extradeps{$plainsource} if (exists($extradeps{$plainsource})); + } + + $handling = "$program.all_$suffix.$suffix: \$(srcdir)/Makefile.in" . $source_deps . " " . join(' ', $mocs) . "\n"; + $handling .= "\t\@echo 'creating $program.all_$suffix.$suffix ...'; \\\n"; + $handling .= "\trm -f $program.all_$suffix.files $program.all_$suffix.final; \\\n"; + $handling .= "\techo \"#define KDE_USE_FINAL 1\" >> $program.all_$suffix.final; \\\n"; + $handling .= "\tfor file in " . $sourcelist{$suffix} . "; do \\\n"; + $handling .= "\t echo \"#include \\\"\$\$file\\\"\" >> $program.all_$suffix.files; \\\n"; + $handling .= "\t test ! -f \$\(srcdir\)/\$\$file || egrep '^#pragma +implementation' \$\(srcdir\)/\$\$file >> $program.all_$suffix.final; \\\n"; + $handling .= "\tdone; \\\n"; + $handling .= "\tcat $program.all_$suffix.final $program.all_$suffix.files > $program.all_$suffix.$suffix; \\\n"; + $handling .= "\trm -f $program.all_$suffix.final $program.all_$suffix.files\n"; + + appendLines($handling); + + push(@final_names, "$program.all_$suffix.$suffix"); + my $finalObj = "$program.all_$suffix."; + if ($program =~ /_la$/) { + $finalObj .= "lo"; + } else { + $finalObj .= "o"; + } + $finalObjs{$program} .= $finalObj . " "; + } + } + + if (!$kdeopts{"nofinal"} && @final_names >= 1) { + # add clean-final target + my $lines = "$cleantarget-final:\n"; + $lines .= "\t-rm -f " . join(' ', @final_names) . "\n" if (@final_names); + appendLines($lines); + $target_adds{"$cleantarget-am"} .= "$cleantarget-final "; + + foreach $finalfile (@final_names) { + $finalfile =~ s/\.[^.]*$/.P/; + $dep_finals .= " \$(DEPDIR)/$finalfile"; + } + } +} + +sub tag_KDEINIT() +{ + my @progs = (); + my $ltlibs = ""; + my $lookup = 'kdeinit_LTLIBRARIES\s*=[ \t]*(.*)'; + + if ($MakefileData =~ m/\n$lookup/) { + @kdeinits = split(/[\034\s]+/, $1); + my $lines = ""; + foreach my $kdeinit (@kdeinits) { + if ($kdeinit =~ m/\.la$/) { + $kdeinit =~ s/\.la$//; + push(@progs, $kdeinit); + + $lines .= "\n${kdeinit}.la.$cxxsuffix:\n"; + $lines .= "\techo 'extern \"C\" int kdemain(int argc, char* argv[]);' > ${kdeinit}.la.$cxxsuffix; \\\n"; + $lines .= "\techo 'int main(int argc, char* argv[]) { return kdemain(argc,argv); }' >> ${kdeinit}.la.$cxxsuffix\n"; + + $lines .= "\n${kdeinit}_dummy.$cxxsuffix:\n"; + $lines .= "\techo '#include ' > ${kdeinit}_dummy.$cxxsuffix; \\\n"; + $lines .= "\techo 'extern \"C\" int kdemain(int argc, char* argv[]);' >> ${kdeinit}_dummy.$cxxsuffix; \\\n"; + $lines .= "\techo 'extern \"C\" KDE_EXPORT int kdeinitmain(int argc, char* argv[]) { return kdemain(argc,argv); }' >> ${kdeinit}_dummy.$cxxsuffix\n"; + + push(@cleanfiles, "${kdeinit}.la.$cxxsuffix"); + push(@cleanfiles, "${kdeinit}_dummy.$cxxsuffix"); + + # add dependency + $dep_files .= " \$(DEPDIR)/${kdeinit}.la.Po" if($dep_files !~/${kdeinit}.la.Po/ ); + $dep_files .= " \$(DEPDIR)/${kdeinit}_dummy.Plo" if($dep_files !~/${kdeinit}_dummy.Plo/ ); + + # make library + $lookup = $kdeinit . '_la_LIBADD\s*=[ \t]*(.*)'; + if($MakefileData =~ m/\n$lookup/) { + my $libadd = $1; + substituteLine($lookup, "${kdeinit}_la_LIBADD = libkdeinit_${kdeinit}.la"); + appendLines("libkdeinit_${kdeinit}_la_LIBADD = $libadd\n"); + } + appendLines("libkdeinit_${kdeinit}_la_LDFLAGS = -no-undefined -avoid-version \$(all_libraries)\n"); + + # add library dependencies + $lookup = $kdeinit . '_la_DEPENDENCIES\s*=[ \t]*(.*)'; + if($MakefileData =~ m/\n$lookup/) { + my $libdeps = $1; + substituteLine($lookup, "${kdeinit}_la_DEPENDENCIES = libkdeinit_${kdeinit}.la"); + appendLines("libkdeinit_${kdeinit}_la_DEPENDENCIES = $libdeps\n"); + } + + # make library objects + $lookup = "am_${kdeinit}_la_OBJECTS" . '\s*=[ \t]*(.*)'; + if($MakefileData =~ m/\n$lookup/) { + my $libobjects = $1; + substituteLine($lookup, "am_${kdeinit}_la_OBJECTS = ${kdeinit}_dummy.lo"); + appendLines("am_libkdeinit_${kdeinit}_la_OBJECTS = $libobjects\n"); + my $prog = "libkdeinit_${kdeinit}_la"; + push(@programs, $prog); + $realObjs{$prog} = $libobjects; + $realname{$prog} = "libkdeinit_${kdeinit}.la"; + } + $target_adds{"libkdeinit_${kdeinit}.la"} = "\$(libkdeinit_${kdeinit}_la_OBJECTS) \$(libkdeinit_${kdeinit}_la_DEPENDENCIES)\n" . + "\t\$(CXXLINK) -rpath \$(libdir) \$(libkdeinit_${kdeinit}_la_LDFLAGS) ". + "\$(libkdeinit_${kdeinit}_la_OBJECTS) " . + "\$(libkdeinit_${kdeinit}_la_LIBADD) " . + "\$(LIBS)\n"; + + # make libkdeinit sources + $lookup = $kdeinit . '_la_SOURCES\s*=[ \t]*(.*)'; + if($MakefileData =~ m/\n$lookup/) { + my $srces = $1; + $sources_changed{"libkdeinit_${kdeinit}_la"} = 1; + $sources{"libkdeinit_${kdeinit}_la"} = $srces; + } + + # make libkdeinit metasources + $lookup = $kdeinit . '_la_METASOURCES\s*=[ \t]*(.*)'; + substituteLine($lookup, "libkdeinit_${kdeinit}_la_METASOURCES = $1") + if($MakefileData =~ m/\n$lookup/); + +=cut + # make binary sources + $lookup = $kdeinit. '_SOURCES\s*=[ \t]*(.*)'; + if($MakefileData =~ m/\n$lookup/) { + substituteLine($lookup, "${kdeinit}_SOURCES = ${kdeinit}.la.$cxxsuffix"); + $lookup = 'SOURCES\s*=[ \t]*(.*)'; + if($MakefileData =~ m/\n$lookup/) { + my $srces = $1; + $srces =~ s/\b$kdeinit\.c\b/\$(${kdeinit}_SOURCES)/; + $srces =~ s/\$\(${kdeinit}_la_SOURCES\)/\$(libkdeinit_${kdeinit}_la_SOURCES)/; + substituteLine($lookup, "SOURCES = $srces"); + } + $lookup = 'DIST_SOURCES\s*=[ \t](.*)'; + if($MakefileData =~ m/\n$lookup/) { + my $srces = $1; + $srces =~ s/\b$kdeinit\.c\b/\$(${kdeinit}_SOURCES)/; + $srces =~ s/\$\(${kdeinit}_la_SOURCES\)/\$(libkdeinit_${kdeinit}_la_SOURCES)/; + substituteLine($lookup, "DIST_SOURCES = $srces"); + } + } + + # make binary objects / libs + $lookup = $kdeinit . '_OBJECTS\s*=[ \t]*.*'; + if($MakefileData =~ m/\n$lookup/) { + $realObjs{$kdeinit} = "${kdeinit}.la.\$(OBJEXT)"; + substituteLine("${kdeinit}_LDFLAGS\\s*=.*", "${kdeinit}_LDFLAGS = \$(all_libraries)"); + substituteLine("${kdeinit}_LDADD\\s*=.*", "${kdeinit}_LDADD = libkdeinit_${kdeinit}.la"); + substituteLine("${kdeinit}_DEPENDENCIES\\s*=.*", "${kdeinit}_DEPENDENCIES = libkdeinit_${kdeinit}.la"); + } +=cut + # add binary + push(@programs, $kdeinit); + $realObjs{$kdeinit} = "${kdeinit}.la.\$(OBJEXT)"; + $realname{$kdeinit} = $kdeinit; + $sources{$kdeinit} = "${kdeinit}.la.$cxxsuffix"; + + $lines .= "${kdeinit}_LDFLAGS = \$(KDE_RPATH) -no-undefined \$(all_libraries)\n"; + $lines .= "${kdeinit}_LDADD = libkdeinit_${kdeinit}.la\n"; + $lines .= "${kdeinit}_DEPENDENCIES = libkdeinit_${kdeinit}.la\n"; + + $target_adds{"${kdeinit}\$(EXEEXT)"} = + "\$(${kdeinit}_OBJECTS) \$(${kdeinit}_DEPENDENCIES)\n" . + "\t\@rm -f ${kdeinit}\$(EXEEXT)\n" . + "\t\$(CXXLINK) \$(${kdeinit}_LDFLAGS) \$(${kdeinit}_OBJECTS) \$(${kdeinit}_LDADD) \$(LIBS)\n"; + + $ltlibs .= " libkdeinit_${kdeinit}.la"; + } + } + appendLines($lines); + + # add libkdeinit target + $lookup = 'lib_LTLIBRARIES\s*=[ \t]*(.*)'; + if($MakefileData =~ m/\n$lookup/) { + substituteLine($lookup, "lib_LTLIBRARIES = $1 $ltlibs"); + } + else { + print STDERR + "Error: lib_LTLIBRARIES missing in $printname (required for kdeinit_LTLIBRARIES).\n"; + $errorflag = 1; + } + } + + if($#progs >= 0) { + if($MakefileData !~ m/\nbin_PROGRAMS\s*=/) { + print STDERR "Error: bin_PROGRAMS missing in $printname (required for kdeinit_LTLIBRARIES).\n"; + $errorflag = 1; + } + else { + # add our new progs to SOURCES, DIST_SOURCES and bin_PROGRAMS + my $progsources = ""; + my $progexes = ""; + foreach my $p (@progs) { + $progsources .= "\$(${p}_SOURCES) "; + $progexes .= "${p}\$(EXEEXT) "; + } + $lookup = 'SOURCES\s*=[ \t]*(.*)'; + if($MakefileData =~ /\n$lookup/) { + substituteLine($lookup, "SOURCES = $1 $progsources"); + } + $lookup = 'DIST_SOURCES\s*=[ \t]*(.*)'; + if($MakefileData =~ /\n$lookup/) { + substituteLine($lookup, "DIST_SOURCES = $1 $progsources"); + } + # bin_PROGRAMS is complicated, as it exists twice, so we do a little + # magic trick here + $lookup = 'PROGRAMS\s*=[ \t]*(.*)'; + if ($MakefileData =~ /\n$lookup/) { + substituteLine($lookup, "bin_PROGRAMS += $progexes\nPROGRAMS = $1"); + } + } + } +} + +#----------------------------------------------------------------------------- + +sub tag_COMPILE_FIRST() +{ + foreach $program (@programs) { + my $lookup = "$program" . '_COMPILE_FIRST\s*=[ \t]*(.*)'; + if ($MakefileData =~ m/\n$lookup\n/) { + my $compilefirst_str = $1; + my @compilefirst = split(/[\034\s]+/, $compilefirst_str); + my @progsources = split(/[\034\s]+/, $sources{$program}); + my %donesources = (); + foreach $source (@progsources) { + my @deps = (); + my $sdeps = ""; + if (-f $source) { + $sdeps = "\$(srcdir)/$source"; + } else { + $sdeps = "$source"; + } + foreach $depend (@compilefirst) { + next if ($source eq $depend); + # avoid cyclic dependencies + next if defined($donesources{$depend}); + push @deps, $depend; + } + $target_adds{$sdeps} .= join(' ', @deps) . ' ' if (@deps); + $donesources{$source} = 1; + } + } + } +} + +#----------------------------------------------------------------------------- + + +# Organises the list of headers that we'll use to produce moc files +# from. +sub tag_METASOURCES () +{ + local @newObs = (); # here we add to create object files + local @depend = (); # here we add to create moc files + local $mocExt = ".moc"; + local %mocFiles = (); + + my $line = ""; + my $postEqual = ""; + + my $lookup; + my $found = ""; + if ($metasourceTags > 1) { + $lookup = $program . '_METASOURCES\s*=\s*(.*)'; + return 1 if ($MakefileData !~ /\n($lookup)\n/); + $found = $1; + } else { + $lookup = $program . '_METASOURCES\s*=\s*(.*)'; + if ($MakefileData !~ /\n($lookup)\n/) { + $lookup = 'METASOURCES\s*=\s*(.*)'; + return 1 if ($MakefileData !~ /\n($lookup)\n/); + $found = $1; + $metasourceTags = 0; # we can use the general target only once + } else { + $found = $1; + } + } + print STDOUT "METASOURCE processing <$found>)\n" if ($verbose); + + $postEqual = $found; + $postEqual =~ s/[^=]*=//; + + removeLine ($lookup, $found); + + # Always find the header files that could be used to "moc" + return 1 if (findMocCandidates ()); + + if ($postEqual =~ /AUTO\s*(\S*)|USE_AUTOMOC\s*(\S*)/) + { + print STDERR "$printname: the argument for AUTO|USE_AUTOMOC is obsolete" if ($+); + $mocExt = ".moc.$cxxsuffix"; + $haveAutomocTag = 1; + } + else + { + # Not automoc so read the list of files supplied which + # should be .moc files. + + $postEqual =~ tr/\034/ /; + + # prune out extra headers - This also checks to make sure that + # the list is valid. + pruneMocCandidates ($postEqual); + } + + checkMocCandidates (); + + if (@newObs) { + my $ext = ($program =~ /_la$/) ? ".moc.lo " : ".moc.o "; + $realObjs{$program} .= "\034" . join ($ext, @newObs) . $ext; + $dependmocs{$program} = join (".moc.$cxxsuffix " , @newObs) . ".moc.$cxxsuffix"; + foreach $file (@newObs) { + $dep_files .= " \$(DEPDIR)/$file.moc.P" if($dep_files !~/$file.moc.P/); + } + } + if (@depend) { + $dependmocs{$program} .= " "; + $dependmocs{$program} .= join('.moc ', @depend) . ".moc"; + $dependmocs{$program} .= " "; + } + addMocRules (); + @globalmocs{keys %mocFiles}=values %mocFiles; +} + +#----------------------------------------------------------------------------- + +# Returns 0 if the line was processed - 1 otherwise. +# Errors are logged in the global $errorflags +sub tag_AUTOMAKE () +{ + my $lookup = '.*cd \$\(top_srcdir\)\s+&&[\034\s]+\$\(AUTOMAKE\)(.*)'; + return 1 if ($MakefileData !~ /\n($lookup)\n/); + print STDOUT "AUTOMAKE processing <$1>\n" if ($verbose); + + my $newLine = $1."\n\tcd \$(top_srcdir) && perl $thisProg $printname"; + + # automake 1.8.x adds another automake call. *sigh* + $newLine =~ s/;([\034\s]+cd\s+\$\(srcdir\)\s+&&[\034\s]+\$\(AUTOMAKE\).*)[\034\s]+\&\&[\034\s]+exit[\034\s]+0;([\034\s]+exit\s+1)/; \034 ( $1 ) || exit 1; echo \' cd \$(top_srcdir) && perl $thisProg \'; cd \$(top_srcdir) && perl $thisProg && exit 0; $2/; + substituteLine ($lookup, $newLine); + $automkCall = $1; + + $lookup = '.*cd \$\(srcdir\)\s+&&[\034\s]+\$\(AUTOCONF\)(.*)'; + if ($MakefileData =~ /\n($lookup)\n/) { + $newLine = "\tcd \$(srcdir) && rm -f configure\n"; + $newLine .= "\tcd \$(top_srcdir) && \$(MAKE) -f admin/Makefile.common configure"; + substituteLine ($lookup, $newLine); + } + + return 0; +} + +#----------------------------------------------------------------------------- + +sub handle_TOPLEVEL() +{ + my $pofiles = ""; + my @restfiles = (); + opendir (THISDIR, "."); + foreach $entry (readdir(THISDIR)) { + next if (-d $entry); + + next if ($entry eq "CVS" || $entry =~ /^\./ || $entry =~ /^Makefile/ || $entry =~ /~$/ || $entry =~ /^\#.*\#$/ || $entry =~ /.gmo$/); + + if ($entry =~ /\.po$/) { + next; + } + push(@restfiles, $entry); + } + closedir (THISDIR); + + if (@restfiles) { + $target_adds{"install-data-am"} .= "install-nls-files "; + $lines = "install-nls-files:\n"; + $lines .= "\t\$(mkinstalldirs) \$(DESTDIR)\$(kde_locale)/$kdelang\n"; + for $file (@restfiles) { + $lines .= "\t\$(INSTALL_DATA) \$\(srcdir\)/$file \$(DESTDIR)\$(kde_locale)/$kdelang/$file\n"; + } + $target_adds{"uninstall"} .= "uninstall-nls-files "; + $lines .= "uninstall-nls-files:\n"; + for $file (@restfiles) { + $lines .= "\t-rm -f \$(DESTDIR)\$(kde_locale)/$kdelang/$file\n"; + } + appendLines($lines); + } + + return 0; +} + +#----------------------------------------------------------------------------- + +sub tag_SUBDIRS () +{ + if ($MakefileData !~ /\nSUBDIRS\s*=\s*\$\(AUTODIRS\)\s*\n/) { + return 1; + } + + my $subdirs = "."; + + opendir (THISDIR, "."); + foreach $entry (readdir(THISDIR)) { + next if ($entry eq "CVS" || $entry =~ /^\./); + if (-d $entry && -f $entry . "/Makefile.am") { + $subdirs .= " $entry"; + next; + } + } + closedir (THISDIR); + + substituteLine('SUBDIRS\s*=.*', "SUBDIRS =$subdirs"); + return 0; +} + +sub tag_IDLFILES () +{ + my @psources = split(/[\034\s]+/, $sources{$program}); + my $dep_lines = ""; + my @cppFiles = (); + + foreach $source (@psources) { + my $skel = ($source =~ m/\.skel$/); + my $stub = ($source =~ m/\.stub$/); + my $signals = ($source =~ m/\.signals$/); # obsolete, remove in KDE-4 + + if ($stub || $skel || $signals) { + + my $qs = quotemeta($source); + $sources{$program} =~ s/$qs//; + $sources_changed{$program} = 1; + + $source =~ s/\.(stub|skel|signals)$//; + my $sourcename; + + if ($skel) { + $sourcename = "$source\_skel"; + } elsif ($stub) { + $sourcename = "$source\_stub"; + } else { + $sourcename = "$source\_signals"; + } + + my $sourcedir = ''; + if (-f "$makefileDir/$source.h") { + $sourcedir = '$(srcdir)/'; + } else { + if ($MakefileData =~ /\n$source\_DIR\s*=\s*(\S+)\n/) { + $sourcedir = $1; + $sourcedir .= "/" if ($sourcedir !~ /\/$/); + } + } + + if ($allidls !~ /$source\_kidl/) { + + $use_ng = ($MakefileData =~ /\n$source\_DCOPIDLNG\s*=\s*(\S+)\n/); + $dcopidl = $use_ng ? "KDECONFIG=\"\$(KDECONFIG)\" \$(DCOPIDLNG)" : "\$(DCOPIDL)"; + + $dep_lines .= "$source.kidl: $sourcedir$source.h \$(DCOP_DEPENDENCIES)\n"; + $dep_lines .= "\t$dcopidl $sourcedir$source.h > $source.kidl || ( rm -f $source.kidl ; false )\n"; + + $allidls .= $source . "_kidl "; + } + + if ($allidls !~ /$sourcename/) { + + $dep_lines_tmp = ""; + + if ($skel) { + $dep_lines .= "$sourcename.$cxxsuffix: $source.kidl\n"; + $dep_lines .= "\t\$(DCOPIDL2CPP) --c++-suffix $cxxsuffix --no-signals --no-stub $source.kidl\n"; + } elsif ($stub) { + $dep_lines_tmp = "\t\$(DCOPIDL2CPP) --c++-suffix $cxxsuffix --no-signals --no-skel $source.kidl\n"; + } else { # signals - obsolete, remove in KDE 4 + $dep_lines_tmp = "\t\$(DCOPIDL2CPP) --c++-suffix $cxxsuffix --no-stub --no-skel $source.kidl\n"; + } + + if ($stub || $signals) { + $target_adds{"$sourcename.$cxxsuffix"} .= "$sourcename.h "; + $dep_lines .= "$sourcename.h: $source.kidl\n"; + $dep_lines .= $dep_lines_tmp; + } + + $allidls .= $sourcename . " "; + } + + $idlfiles{$program} .= $sourcename . " "; + + if ($program =~ /_la$/) { + $realObjs{$program} .= " $sourcename.lo"; + } else { + $realObjs{$program} .= " $sourcename.\$(OBJEXT)"; + } + $sources{$program} .= " $sourcename.$cxxsuffix"; + $sources_changed{$program} = 1; + $important{$program} .= "$sourcename.h " if (!$skel); + $idl_output .= "\\\n\t$sourcename.$cxxsuffix $sourcename.h $source.kidl "; + push(@cleanfiles, "$sourcename.$cxxsuffix"); + push(@cleanfiles, "$sourcename.h"); + push(@cleanfiles, "$sourcename.kidl"); + $dep_files .= " \$(DEPDIR)/$sourcename.P" if ($dep_files !~/$sourcename.P/); + } + } + if ($dep_lines) { + appendLines($dep_lines); + } + + if (0) { + my $lookup = "($program)"; + $lookup .= '(|\$\(EXEEXT\))'; + $lookup =~ s/\_/./g; + $lookup .= ":(.*..$program\_OBJECTS..*)"; + # $lookup = quotemeta($lookup); + if ($MakefileData =~ /\n$lookup\n/) { + + my $line = "$1$2: "; + foreach $file (split(' ', $idlfiles{$program})) { + $line .= "$file.$cxxsuffix "; + } + $line .= $3; + substituteLine($lookup, $line); + } else { + print STDERR "no built dependency found $lookup\n"; + } + } +} + +sub tag_UIFILES () +{ + my @psources = split(/[\034\s]+/, $sources{$program}); + my @depFiles = (); + + foreach $source (@psources) { + + if ($source =~ m/\.ui$/) { + + print STDERR "adding UI file $source\n" if ($verbose); + + my $qs = quotemeta($source); + $sources{$program} =~ s/$qs//; + $sources_changed{$program} = 1; + + $source =~ s/\.ui$//; + + my $sourcedir = ''; + if (-f "$makefileDir/$source.ui") { + $sourcedir = '$(srcdir)/'; + } + + if (!$uiFiles{$source}) { + + my $dep_lines = "$source.$cxxsuffix: $sourcedir$source.ui $source.h $source.moc\n"; + $dep_lines .= "\trm -f $source.$cxxsuffix\n"; + if (!$kdeopts{"qtonly"}) { +# $dep_lines .= "\techo '#include ' > $source.$cxxsuffix\n"; +# $dep_lines .= "\techo '#include ' >> $source.$cxxsuffix\n"; + $dep_lines .= "\techo '#include \"misc.h\"' > $source.$cxxsuffix\n"; + my ($mangled_source) = $source; + $mangled_source =~ s/[^A-Za-z0-9]/_/g; # get rid of garbage + $dep_lines .= "\t\$(UIC) -tr \${UIC_TR} -i $source.h $sourcedir$source.ui > $source.$cxxsuffix.temp ; ret=\$\$?; \\\n"; + $dep_lines .= "\t\$(PERL) -pe \"s,\${UIC_TR}( \\\"\\\" ),QString::null,g\" $source.$cxxsuffix.temp | \$(PERL) -pe \"s,\${UIC_TR}( \\\"\\\"\\, \\\"\\\" ),QString::null,g\" | \$(PERL) -pe \"s,image([0-9][0-9]*)_data,img\\\$\$1_" . $mangled_source . ",g\" >> $source.$cxxsuffix ;\\\n"; + $dep_lines .= "\trm -f $source.$cxxsuffix.temp ;\\\n"; + } else { + $dep_lines .= "\t\$(UIC) -i $source.h $sourcedir$source.ui > $source.$cxxsuffix; ret=\$\$?; \\\n"; + } + $dep_lines .= "\tif test \"\$\$ret\" = 0; then echo '#include \"$source.moc\"' >> $source.$cxxsuffix; else rm -f $source.$cxxsuffix ; exit \$\$ret ; fi\n\n"; + $dep_lines .= "$source.h: $sourcedir$source.ui\n"; + $dep_lines .= "\t\$(UIC) -o $source.h $sourcedir$source.ui\n\n"; + $dep_lines .= "$source.moc: $source.h\n"; + $dep_lines .= "\t\$(MOC) $source.h -o $source.moc\n"; + + $rule_adds{"$source.$cxxsuffix"} = $dep_lines; + + $uiFiles{$source} = 1; + $dependmocs{$program} .= " $source.moc"; + $globalmocs{$source} = "\035$source.h\035$source.cpp"; + } + + if ($program =~ /_la$/) { + $realObjs{$program} .= " $source.lo"; + } else { + $realObjs{$program} .= " $source.\$(OBJEXT)"; + } + $sources{$program} .= " $source.$cxxsuffix"; + $sources_changed{$program} = 1; + $important{$program} .= "$source.h "; + $ui_output .= "\\\n\t$source.$cxxsuffix $source.h $source.moc "; + push(@cleanfiles, "$source.$cxxsuffix"); + push(@cleanfiles, "$source.h"); + push(@cleanfiles, "$source.moc"); + $dep_files .= " \$(DEPDIR)/$source.P" if($dep_files !~/$source.P/ ); + } + } +} + +sub tag_KCFGFILES () +{ + my @psources = split(/[\034\s]+/, $sources{$program}); + my @depFiles = (); + + foreach $source (@psources) { + + if ($source =~ m/\.kcfgc$/) { + + print STDERR "adding KCFG file $source\n" if ($verbose); + + my $qs = quotemeta($source); + $sources{$program} =~ s/$qs//; + $sources_changed{$program} = 1; + + $source =~ s/\.kcfgc$//; + + my $sourcedir = ''; + if (-f "$makefileDir/$source.kcfgc") { + $sourcedir = '$(srcdir)/'; + } + + if (!$kcfgFiles{$source}) { + $kcfg = "$program.kcfg"; + findKcfgFile("$source.kcfgc"); + + my $fixsuffix = ""; + $fixsuffix = "else mv $source.cpp $source.$cxxsuffix ; " + unless "cpp" eq $cxxsuffix; + + my $dep_lines = "$source.$cxxsuffix: $source.h\n"; + $dep_lines .= "$source.h: $sourcedir$kcfg $sourcedir$source.kcfgc \$(KCFG_DEPENDENCIES)\n"; + $dep_lines .= "\t\$(KCONFIG_COMPILER) $sourcedir$kcfg $sourcedir$source.kcfgc; ret=\$\$?; \\\n"; + $dep_lines .= "\tif test \"\$\$ret\" != 0; then rm -f $source.h ; exit \$\$ret ; $fixsuffix fi\n\n"; + + $rule_adds{"$source.$cxxsuffix"} = $dep_lines; + + $kcfgFiles{$source} = 1; + } + + if ($program =~ /_la$/) { + $realObjs{$program} .= " $source.lo"; + } else { + $realObjs{$program} .= " $source.\$(OBJEXT)"; + } + $sources{$program} .= " $source.$cxxsuffix"; + $sources_changed{$program} = 1; + $important{$program} .= "$source.h "; + $kcfg_output .= "\\\n\t$source.$cxxsuffix $source.h "; + push(@cleanfiles, "$source.$cxxsuffix"); + push(@cleanfiles, "$source.h"); + $dep_files .= " \$(DEPDIR)/$source.P" if($dep_files !~/$source.P/ ); + } + } +} + +sub tag_ICON() +{ + my $lookup = '([^\s]*)_ICON\s*=[ \t]*(.*)'; + my $install = ""; + my $uninstall = ""; + + while ($MakefileData =~ /\n$lookup/g) { + my $destdir; + if ($1 eq "KDE") { + $destdir = "kde_icondir"; + } else { + $destdir = $1 . "dir"; + } + my $iconauto = ($2 =~ /AUTO\s*$/); + my @appnames = (); + if ( ! $iconauto ) { + my $appicon_str = $2; + my @_appnames = split(" ", $appicon_str); + print STDOUT "KDE_ICON processing <@_appnames>\n" if ($verbose); + foreach $appname (@_appnames) { + push(@appnames, quotemeta($appname)); + } + } else { + print STDOUT "KDE_ICON processing \n" if ($verbose); + } + + my @files = (); + opendir (THISDIR, "."); + foreach $entry (readdir(THISDIR)) { + next if ($entry eq "CVS" || $entry =~ /^\./ || $entry =~ /^Makefile/ || $entry =~ /~$/ || $entry =~ /^\#.*\#$/); + next if (! -f $entry); + if ( $iconauto ) + { + push(@files, $entry) + if ($entry =~ /\.xpm/ || $entry =~ /\.png/ || $entry =~ /\.mng/ || $entry =~ /\.svg/); + } else { + foreach $appname (@appnames) { + push(@files, $entry) + if ($entry =~ /-$appname\.xpm/ || $entry =~ /-$appname\.png/ || $entry =~ /-$appname\.mng/ || $entry =~ /-$appname\.svg/); + } + } + } + closedir (THISDIR); + + my %directories = (); + + foreach $file (@files) { + my $newfile = $file; + my $prefix = $file; + $prefix =~ s/\.(png|xpm|mng|svg|svgz)$//; + my $appname = $prefix; + $appname =~ s/^[^-]+-// if ($appname =~ /-/) ; + $appname =~ s/^[^-]+-// if ($appname =~ /-/) ; + $appname = quotemeta($appname); + $prefix =~ s/$appname$//; + $prefix =~ s/-$//; + + $prefix = 'lo16-app' if ($prefix eq 'mini'); + $prefix = 'lo32-app' if ($prefix eq 'lo'); + $prefix = 'hi48-app' if ($prefix eq 'large'); + $prefix .= '-app' if ($prefix =~ m/^...$/); + + my $type = $prefix; + $type =~ s/^.*-([^-]+)$/$1/; + $prefix =~ s/^(.*)-[^-]+$/$1/; + + my %type_hash = + ( + 'action' => 'actions', + 'app' => 'apps', + 'device' => 'devices', + 'filesys' => 'filesystems', + 'mime' => 'mimetypes' + ); + + if (! defined $type_hash{$type} ) { + print STDERR "unknown icon type $type in $printname ($file)\n"; + next; + } + + my %dir_hash = + ( + 'los' => 'locolor/16x16', + 'lom' => 'locolor/32x32', + 'him' => 'hicolor/32x32', + 'hil' => 'hicolor/48x48', + 'lo16' => 'locolor/16x16', + 'lo22' => 'locolor/22x22', + 'lo32' => 'locolor/32x32', + 'hi16' => 'hicolor/16x16', + 'hi22' => 'hicolor/22x22', + 'hi32' => 'hicolor/32x32', + 'hi48' => 'hicolor/48x48', + 'hi64' => 'hicolor/64x64', + 'hi128' => 'hicolor/128x128', + 'hisc' => 'hicolor/scalable', + 'cr16' => 'crystalsvg/16x16', + 'cr22' => 'crystalsvg/22x22', + 'cr32' => 'crystalsvg/32x32', + 'cr48' => 'crystalsvg/48x48', + 'cr64' => 'crystalsvg/64x64', + 'cr128' => 'crystalsvg/128x128', + 'crsc' => 'crystalsvg/scalable' + ); + + $newfile =~ s@.*-($appname\.(png|xpm|mng|svgz|svg?))@$1@; + + if (! defined $dir_hash{$prefix}) { + print STDERR "unknown icon prefix $prefix in $printname\n"; + next; + } + + my $dir = $dir_hash{$prefix} . "/" . $type_hash{$type}; + if ($newfile =~ /-[^\.]/) { + my $tmp = $newfile; + $tmp =~ s/^([^-]+)-.*$/$1/; + $dir = $dir . "/" . $tmp; + $newfile =~ s/^[^-]+-//; + } + + if (!defined $directories{$dir}) { + $install .= "\t\$(mkinstalldirs) \$(DESTDIR)\$($destdir)/$dir\n"; + $directories{$dir} = 1; + } + + $install .= "\t\$(INSTALL_DATA) \$(srcdir)/$file \$(DESTDIR)\$($destdir)/$dir/$newfile\n"; + $uninstall .= "\t-rm -f \$(DESTDIR)\$($destdir)/$dir/$newfile\n"; + + } + } + + if (length($install)) { + $target_adds{"install-data-am"} .= "install-kde-icons "; + $target_adds{"uninstall-am"} .= "uninstall-kde-icons "; + appendLines("install-kde-icons:\n" . $install . "\nuninstall-kde-icons:\n" . $uninstall); + } +} + +sub handle_POFILES($$) +{ + my @pofiles = split(" ", $_[0]); + my $lang = $_[1]; + + # Build rules for creating the gmo files + my $tmp = ""; + my $allgmofiles = ""; + my $pofileLine = "POFILES ="; + foreach $pofile (@pofiles) + { + $pofile =~ /(.*)\.[^\.]*$/; # Find name minus extension + $tmp .= "$1.gmo: $pofile\n"; + $tmp .= "\trm -f $1.gmo; \$(GMSGFMT) -o $1.gmo \$(srcdir)/$pofile\n"; + $tmp .= "\ttest ! -f $1.gmo || touch $1.gmo\n"; + $allgmofiles .= " $1.gmo"; + $pofileLine .= " $1.po"; + } + appendLines ($tmp); + my $lookup = 'POFILES\s*=([^\n]*)'; + if ($MakefileData !~ /\n$lookup/) { + appendLines("$pofileLine\nGMOFILES =$allgmofiles"); + } else { + substituteLine ($lookup, "$pofileLine\nGMOFILES =$allgmofiles"); + } + + if ($allgmofiles) { + + # Add the "clean" rule so that the maintainer-clean does something + appendLines ("clean-nls:\n\t-rm -f $allgmofiles\n"); + + $target_adds{"maintainer-clean"} .= "clean-nls "; + + $lookup = 'DISTFILES\s*=[ \t]*(.*)'; + if ($MakefileData =~ /\n$lookup/) { + $tmp = "DISTFILES = \$(GMOFILES) \$(POFILES) $1"; + substituteLine ($lookup, $tmp); + } + } + + $target_adds{"install-data-am"} .= "install-nls "; + + $tmp = "install-nls:\n"; + if ($lang) { + $tmp .= "\t\$(mkinstalldirs) \$(DESTDIR)\$(kde_locale)/$lang/LC_MESSAGES\n"; + } + $tmp .= "\t\@for base in "; + foreach $pofile (@pofiles) + { + $pofile =~ /(.*)\.[^\.]*$/; # Find name minus extension + $tmp .= "$1 "; + } + + $tmp .= "; do \\\n"; + if ($lang) { + $tmp .= "\t echo \$(INSTALL_DATA) \$\$base.gmo \$(DESTDIR)\$(kde_locale)/$lang/LC_MESSAGES/\$\$base.mo ;\\\n"; + $tmp .= "\t if test -f \$\$base.gmo; then \$(INSTALL_DATA) \$\$base.gmo \$(DESTDIR)\$(kde_locale)/$lang/LC_MESSAGES/\$\$base.mo ;\\\n"; + $tmp .= "\t elif test -f \$(srcdir)/\$\$base.gmo; then \$(INSTALL_DATA) \$(srcdir)/\$\$base.gmo \$(DESTDIR)\$(kde_locale)/$lang/LC_MESSAGES/\$\$base.mo ;\\\n"; + $tmp .= "\t fi ;\\\n"; + } else { + $tmp .= "\t echo \$(INSTALL_DATA) \$\$base.gmo \$(DESTDIR)\$(kde_locale)/\$\$base/LC_MESSAGES/\$(PACKAGE).mo ;\\\n"; + $tmp .= "\t \$(mkinstalldirs) \$(DESTDIR)\$(kde_locale)/\$\$base/LC_MESSAGES ; \\\n"; + $tmp .= "\t if test -f \$\$base.gmo; then \$(INSTALL_DATA) \$\$base.gmo \$(DESTDIR)\$(kde_locale)/\$\$base/LC_MESSAGES/\$(PACKAGE).mo ;\\\n"; + $tmp .= "\t elif test -f \$(srcdir)/\$\$base.gmo; then \$(INSTALL_DATA) \$(srcdir)/\$\$base.gmo \$(DESTDIR)\$(kde_locale)/\$\$base/LC_MESSAGES/\$(PACKAGE).mo ;\\\n"; + $tmp .= "\t fi ;\\\n"; + } + $tmp .= "\tdone\n\n"; + appendLines ($tmp); + + $target_adds{"uninstall"} .= "uninstall-nls "; + + $tmp = "uninstall-nls:\n"; + foreach $pofile (@pofiles) + { + $pofile =~ /(.*)\.[^\.]*$/; # Find name minus extension + if ($lang) { + $tmp .= "\trm -f \$(DESTDIR)\$(kde_locale)/$lang/LC_MESSAGES/$1.mo\n"; + } else { + $tmp .= "\trm -f \$(DESTDIR)\$(kde_locale)/$1/LC_MESSAGES/\$(PACKAGE).mo\n"; + } + } + appendLines($tmp); + + $target_adds{"all"} .= "all-nls "; + + $tmp = "all-nls: \$(GMOFILES)\n"; + + appendLines($tmp); + + $target_adds{"distdir"} .= "distdir-nls "; + + $tmp = "distdir-nls:\$(GMOFILES)\n"; + $tmp .= "\tfor file in \$(POFILES); do \\\n"; + $tmp .= "\t cp \$(srcdir)/\$\$file \$(distdir); \\\n"; + $tmp .= "\tdone\n"; + $tmp .= "\tfor file in \$(GMOFILES); do \\\n"; + $tmp .= "\t cp \$(srcdir)/\$\$file \$(distdir); \\\n"; + $tmp .= "\tdone\n"; + + appendLines ($tmp); + + if (!$lang) { + appendLines("merge:\n\t\$(MAKE) -f \$(top_srcdir)/admin/Makefile.common package-merge POFILES=\"\${POFILES}\" PACKAGE=\${PACKAGE}\n\n"); + } + +} + +#----------------------------------------------------------------------------- + +# Returns 0 if the line was processed - 1 otherwise. +# Errors are logged in the global $errorflags +sub tag_POFILES () +{ + my $lookup = 'POFILES\s*=([^\n]*)'; + return 1 if ($MakefileData !~ /\n$lookup/); + print STDOUT "POFILES processing <$1>\n" if ($verbose); + + my $tmp = $1; + + # make sure these are all gone. + if ($MakefileData =~ /\n\.po\.gmo:\n/) + { + print STDERR "Warning: Found old .po.gmo rules in $printname. New po rules not added\n"; + return 1; + } + + # Either find the pofiles in the directory (AUTO) or use + # only the specified po files. + my $pofiles = ""; + if ($tmp =~ /^\s*AUTO\s*$/) + { + opendir (THISDIR, "."); + $pofiles = join(" ", grep(/\.po$/, readdir(THISDIR))); + closedir (THISDIR); + print STDOUT "pofiles found = $pofiles\n" if ($verbose); + if (-f "charset" && -f "kdelibs/kdelibs.po") { + handle_TOPLEVEL(); + } + } + else + { + $tmp =~ s/\034/ /g; + $pofiles = $tmp; + } + return 1 if (!$pofiles); # Nothing to do + + handle_POFILES($pofiles, $kdelang); + + return 0; +} + +sub helper_LOCALINSTALL($) +{ + my $lookup = "\035" . $_[0] . " *:[^\035]*\035\t"; + my $copy = $MakefileData; + $copy =~ s/\n/\035/g; + if ($copy =~ /($lookup.*)$/) { + + $install = $1; + $install =~ s/\035$_[0] *:[^\035]*\035//; + my $emptyline = 0; + while (! $emptyline ) { + if ($install =~ /([^\035]*)\035(.*)/) { + local $line = $1; + $install = $2; + if ($line !~ /^\s*$/ && $line !~ /^(\@.*\@)*\t/) { + $emptyline = 1; + } else { + replaceDestDir($line); + } + } else { + $emptyline = 1; + } + } + } + +} + +sub tag_LOCALINSTALL () +{ + helper_LOCALINSTALL('install-exec-local'); + helper_LOCALINSTALL('install-data-local'); + helper_LOCALINSTALL('uninstall-local'); + + return 0; +} + +sub replaceDestDir($) { + local $line = $_[0]; + + if ( $line =~ /^\s*(\@.*\@)*\s*\$\(mkinstalldirs\)/ + || $line =~ /^\s*(\@.*\@)*\s*\$\(INSTALL\S*\)/ + || $line =~ /^\s*(\@.*\@)*\s*(-?rm.*) \S*$/) + { + $line =~ s/^(.*) ([^\s]+)\s*$/$1 \$(DESTDIR)$2/ if ($line !~ /\$\(DESTDIR\)/); + } + + if ($line ne $_[0]) { + $_[0] = quotemeta $_[0]; + substituteLine($_[0], $line); + } +} + +#--------------------------------------------------------------------------- +# libtool is very hard to persuade it could use -Wl,--no-undefined for making +# -no-undefined actually work +# append $(KDE_NO_UNFINED) after every -no-undefined in LDFLAGS +# this may go away if libtool ever does this on its own +sub tag_NO_UNDEFINED () { + return if ($program !~ /_la$/); + + my $lookup = quotemeta($realname{$program}) . ":.*?\n\t.*?\\((.*?)\\) .*\n"; + $MakefileData =~ m/$lookup/; + return if (!defined($1)); + return if ($1 !~ /CXXLINK/); + + if ($MakefileData !~ /\n$program\_LDFLAGS\s*=.*-no-undefined/ ) { + return; + } + + $lookup = $program . '\_LDFLAGS(\s*)=(.*)-no-undefined(.*)'; + if ($MakefileData =~ /\n$lookup\n/) { + my $replace = $program . "\_LDFLAGS$1=$2-no-undefined \$(KDE_NO_UNDEFINED)$3"; + substituteLine($lookup, $replace); + } +} + +sub tag_CLOSURE () { + return if ($program !~ /_la$/); + + my $lookup = quotemeta($realname{$program}) . ":.*?\n\t.*?\\((.*?)\\) .*\n"; + $MakefileData =~ m/$lookup/; + return if (!defined($1)); + return if ($1 !~ /CXXLINK/); + + if ($MakefileData !~ /\n$program\_LDFLAGS\s*=.*-no-undefined/ && + $MakefileData !~ /\n$program\_LDFLAGS\s*=.*KDE_PLUGIN/ ) { + print STDERR "Report: $program contains undefined in $printname\n" if ($program =~ /^lib/ && $dryrun); + return; + } + + my $closure = $realname{$program} . ".closure"; + my $lines = "$closure: \$($program\_OBJECTS) \$($program\_DEPENDENCIES)\n"; + $lines .= "\t\@echo \"int main() {return 0;}\" > $program\_closure.$cxxsuffix\n"; + $lines .= "\t\@\$\(LTCXXCOMPILE\) -c $program\_closure.$cxxsuffix\n"; + $lines .= "\t\$\(CXXLINK\) $program\_closure.lo \$($program\_LDFLAGS) \$($program\_OBJECTS) \$($program\_LIBADD) \$(LIBS)\n"; + $lines .= "\t\@rm -f $program\_closure.* $closure\n"; + $lines .= "\t\@echo \"timestamp\" > $closure\n"; + $lines .= "\n"; + appendLines($lines); + $lookup = $realname{$program} . ": (.*)"; + if ($MakefileData =~ /\n$lookup\n/) { + $lines = "\@KDE_USE_CLOSURE_TRUE@". $realname{$program} . ": $closure $1"; + $lines .= "\n\@KDE_USE_CLOSURE_FALSE@" . $realname{$program} . ": $1"; + substituteLine($lookup, $lines); + } + $closure_output .= " $closure"; +} + +sub tag_NMCHECK () { + return if ($program !~ /_la$/); + my $lookup = quotemeta($realname{$program}) . ":.*?\n\t.*?\\((.*?)\\) .*\n"; + $MakefileData =~ m/$lookup/; + my $linkcmd = $1; + return if (!defined($1)); + return if ($linkcmd !~ /CXXLINK/ && $linkcmd !~ /LINK/); + + $lookup = $program . '_NMCHECK\s*=([^\n]*)'; + if( $MakefileData !~ m/\n$lookup\n/ ) { + return; + } + my $allowed = $1; + $allowed =~ s/^ *//; + $lookup = $program . '_NMCHECKWEAK\s*=([^\n]*)'; + my $weak = ""; + my $is_weak = 0; + if( $MakefileData =~ m/\n$lookup\n/ ) { + $weak = $1; + $is_weak = 1; + } + $weak =~ s/^ *//; + + if( $is_weak ) + { + $weak = '--allowweak=\'' . $weak . '\' '; + } + my $nmline = "\@KDE_USE_NMCHECK_TRUE@\t\@\$(MAKE) \$(AM_MAKEFLAGS) nmcheck_$realname{$program} || ( rm -f $realname{$program}; exit 1 )"; + $lookup = '(\t\$\(CXXLINK\)[^\n]*' . $program . '_OBJECTS[^\n]*)'; + if( $MakefileData =~ /\n$lookup\n/ ) { + my $oldstuff = $1; + substituteLine( $lookup, $oldstuff . "\n" . $nmline ); + } + $lookup = '(\t\$\(LINK\)[^\n]*' . $program . '_OBJECTS[^\n]*)'; + if( $MakefileData =~ /\n$lookup\n/ ) { + my $oldstuff = $1; + substituteLine( $lookup, $oldstuff . "\n" . $nmline ); + } + $nmline = "\@\$(top_srcdir)/admin/nmcheck $realname{$program} \'$allowed\' $weak"; + appendLines( "\nnmcheck_$realname{$program}: $realname{$program} \n\t$nmline\n" ); + $target_adds{ "nmcheck" } .= "nmcheck_$realname{$program} "; +} + +sub tag_DIST () { + my %foundfiles = (); + opendir (THISDIR, "."); + foreach $entry (readdir(THISDIR)) { + next if ($entry eq "CVS" || $entry =~ /^\./ || $entry eq "Makefile" || $entry =~ /~$/ || $entry =~ /^\#.*\#$/); + next if (! -f $entry); + next if ($entry =~ /\.moc/ || $entry =~ /\.moc.$cppExt$/ || $entry =~ /\.lo$/ || $entry =~ /\.la$/ || $entry =~ /\.o/); + next if ($entry =~ /\.all_$cppExt\.$cppExt$/); + $foundfiles{$entry} = 1; + } + closedir (THISDIR); + + # doing this for MAINTAINERCLEANFILES would be wrong + my @marks = ("EXTRA_DIST", "DIST_COMMON", '\S*_SOURCES', '\S*_HEADERS', 'CLEANFILES', 'DISTCLEANFILES', '\S*_OBJECTS'); + foreach $mark (@marks) { + while ($MakefileData =~ /\n($mark)\s*=[ \t]*([^\n]*)/g) { + my $cleanfiles_str = $2; + foreach $file (split('[\034\s]+', $cleanfiles_str)) { + $file =~ s/\.\///; + $foundfiles{$file} = 0 if (defined $foundfiles{$file}); + } + } + } + my @files = ("Makefile", "config.cache", "config.log", "stamp-h", + "stamp-h1", "stamp-h1", "config.h", "Makefile", + "config.status", "config.h", "libtool", "core" ); + foreach $file (@files) { + $foundfiles{$file} = 0 if (defined $foundfiles{$file}); + } + + my $KDE_DIST = ""; + foreach $file (keys %foundfiles) { + if ($foundfiles{$file} == 1) { + $KDE_DIST .= "$file "; + } + } + if ($KDE_DIST) { + print "KDE_DIST $printname $KDE_DIST\n" if ($verbose); + + my $lookup = 'DISTFILES\s*=[ \t]*(.*)'; + if ($MakefileData =~ /\n$lookup/) { + substituteLine($lookup, "DISTFILES = $1 \$(KDE_DIST)"); + appendLines("KDE_DIST=$KDE_DIST\n"); + } + } +} + +#----------------------------------------------------------------------------- +# Returns 0 if the line was processed - 1 otherwise. +# Errors are logged in the global $errorflags +sub tag_DOCFILES () +{ + $target_adds{"all"} .= "docs-am "; + + my $lookup = 'KDE_DOCS\s*=[ \t]*([^\n]*)'; + goto nodocs if ($MakefileData !~ /\n$lookup/); + print STDOUT "KDE_DOCS processing <$1>\n" if ($verbose); + + my $tmp = $1; + + # Either find the files in the directory (AUTO) or use + # only the specified po files. + my $files = ""; + my $appname = $tmp; + $appname =~ s/^(\S*)\s*.*$/$1/; + if ($appname =~ /AUTO/) { + $appname = basename($makefileDir); + if ("$appname" eq "en") { + print STDERR "Error: KDE_DOCS = AUTO relies on the directory name. Yours is 'en' - you most likely want something else, e.g. KDE_DOCS = myapp\n"; + exit(1); + } + } + + if ($tmp !~ / - /) + { + opendir (THISDIR, "."); + foreach $entry (readdir(THISDIR)) { + next if ($entry eq "CVS" || $entry =~ /^\./ || $entry =~ /^Makefile/ || $entry =~ /~$/ || $entry =~ /^\#.*\#$/ || $entry eq "core" || $entry eq "index.cache.bz2"); + next if (! -f $entry); + $files .= "$entry "; + } + closedir (THISDIR); + print STDOUT "docfiles found = $files\n" if ($verbose); + } + else + { + $tmp =~ s/\034/ /g; + $tmp =~ s/^\S*\s*-\s*//; + $files = $tmp; + } + goto nodocs if (!$files); # Nothing to do + + if ($files =~ /(^| )index\.docbook($| )/) { + + my $lines = ""; + my $lookup = 'MEINPROC\s*='; + if ($MakefileData !~ /\n($lookup)/) { + $lines = "MEINPROC=/\$(kde_bindir)/meinproc\n"; + } + $lookup = 'KDE_XSL_STYLESHEET\s*='; + if ($MakefileData !~ /\n($lookup)/) { + $lines .= "KDE_XSL_STYLESHEET=/\$(kde_datadir)/ksgmltools2/customization/kde-chunk.xsl\n"; + } + $lookup = '\nindex.cache.bz2:'; + if ($MakefileData !~ /\n($lookup)/) { + $lines .= "index.cache.bz2: \$(srcdir)/index.docbook \$(KDE_XSL_STYLESHEET) $files\n"; + $lines .= "\t\@if test -n \"\$(MEINPROC)\"; then echo \$(MEINPROC) --check --cache index.cache.bz2 \$(srcdir)/index.docbook; \$(MEINPROC) --check --cache index.cache.bz2 \$(srcdir)/index.docbook; fi\n"; + $lines .= "\n"; + } + + $lines .= "docs-am: index.cache.bz2\n"; + $lines .= "\n"; + $lines .= "install-docs: docs-am install-nls\n"; + $lines .= "\t\$(mkinstalldirs) \$(DESTDIR)\$(kde_htmldir)/$kdelang/$appname\n"; + $lines .= "\t\@if test -f index.cache.bz2; then \\\n"; + $lines .= "\techo \$(INSTALL_DATA) index.cache.bz2 \$(DESTDIR)\$(kde_htmldir)/$kdelang/$appname/; \\\n"; + $lines .= "\t\$(INSTALL_DATA) index.cache.bz2 \$(DESTDIR)\$(kde_htmldir)/$kdelang/$appname/; \\\n"; + $lines .= "\telif test -f \$(srcdir)/index.cache.bz2; then \\\n"; + $lines .= "\techo \$(INSTALL_DATA) \$(srcdir)/index.cache.bz2 \$(DESTDIR)\$(kde_htmldir)/$kdelang/$appname/; \\\n"; + $lines .= "\t\$(INSTALL_DATA) \$(srcdir)/index.cache.bz2 \$(DESTDIR)\$(kde_htmldir)/$kdelang/$appname/; \\\n"; + $lines .= "\tfi\n"; + $lines .= "\t-rm -f \$(DESTDIR)\$(kde_htmldir)/$kdelang/$appname/common\n"; + $lines .= "\t\$(LN_S) \$(kde_libs_htmldir)/$kdelang/common \$(DESTDIR)\$(kde_htmldir)/$kdelang/$appname/common\n"; + + $lines .= "\n"; + $lines .= "uninstall-docs:\n"; + $lines .= "\t-rm -rf \$(DESTDIR)\$(kde_htmldir)/$kdelang/$appname\n"; + $lines .= "\n"; + $lines .= "clean-docs:\n"; + $lines .= "\t-rm -f index.cache.bz2\n"; + $lines .= "\n"; + $target_adds{"install-data-am"} .= "install-docs "; + $target_adds{"uninstall"} .= "uninstall-docs "; + $target_adds{"clean-am"} .= "clean-docs "; + appendLines ($lines); + } else { + appendLines("docs-am: $files\n"); + } + + $target_adds{"install-data-am"} .= "install-nls "; + $target_adds{"uninstall"} .= "uninstall-nls "; + + $tmp = "install-nls:\n"; + $tmp .= "\t\$(mkinstalldirs) \$(DESTDIR)\$(kde_htmldir)/$kdelang/$appname\n"; + $tmp .= "\t\@for base in $files; do \\\n"; + $tmp .= "\t echo \$(INSTALL_DATA) \$\$base \$(DESTDIR)\$(kde_htmldir)/$kdelang/$appname/\$\$base ;\\\n"; + $tmp .= "\t \$(INSTALL_DATA) \$(srcdir)/\$\$base \$(DESTDIR)\$(kde_htmldir)/$kdelang/$appname/\$\$base ;\\\n"; + $tmp .= "\tdone\n"; + if ($appname eq 'common') { + $tmp .= "\t\@echo \"merging common and language specific dir\" ;\\\n"; + $tmp .= "\tif test ! -f \$(kde_htmldir)/en/common/kde-common.css; then echo 'no english docs found in \$(kde_htmldir)/en/common/'; exit 1; fi \n"; + $tmp .= "\t\@com_files=`cd \$(kde_htmldir)/en/common && echo *` ;\\\n"; + $tmp .= "\tcd \$(DESTDIR)\$(kde_htmldir)/$kdelang/common ;\\\n"; + $tmp .= "\tif test -n \"\$\$com_files\"; then for p in \$\$com_files ; do \\\n"; + $tmp .= "\t case \" $files \" in \\\n"; + $tmp .= "\t *\" \$\$p \"*) ;; \\\n"; + $tmp .= "\t *) test ! -f \$\$p && echo \$(LN_S) ../../en/common/\$\$p \$(DESTDIR)\$(kde_htmldir)/$kdelang/common/\$\$p && \$(LN_S) ../../en/common/\$\$p \$\$p ;; \\\n"; + $tmp .= "\t esac ; \\\n"; + $tmp .= "\tdone ; fi ; true\n"; + } + $tmp .= "\n"; + $tmp .= "uninstall-nls:\n"; + $tmp .= "\tfor base in $files; do \\\n"; + $tmp .= "\t rm -f \$(DESTDIR)\$(kde_htmldir)/$kdelang/$appname/\$\$base ;\\\n"; + $tmp .= "\tdone\n\n"; + appendLines ($tmp); + + $target_adds{"distdir"} .= "distdir-nls "; + + $tmp = "distdir-nls:\n"; + $tmp .= "\tfor file in $files; do \\\n"; + $tmp .= "\t cp \$(srcdir)/\$\$file \$(distdir); \\\n"; + $tmp .= "\tdone\n"; + + appendLines ($tmp); + + return 0; + + nodocs: + appendLines("docs-am:\n"); + return 1; +} + +#----------------------------------------------------------------------------- +# Find headers in any of the source directories specified previously, that +# are candidates for "moc-ing". +sub findMocCandidates () +{ + foreach $dir (@headerdirs) + { + my @list = (); + opendir (SRCDIR, "$dir"); + @hFiles = grep { /.+\.$hExt$/o && !/^\./ } readdir(SRCDIR); + closedir SRCDIR; + foreach $hf (@hFiles) + { + next if ($hf =~ /^\.\#/); + $hf =~ /(.*)\.[^\.]*$/; # Find name minus extension + next if ($uiFiles{$1}); + open (HFIN, "$dir/$hf") || die "Could not open $dir/$hf: $!\n"; + my $hfsize = 0; + seek(HFIN, 0, 2); + $hfsize = tell(HFIN); + seek(HFIN, 0, 0); + read HFIN, $hfData, $hfsize; + close HFIN; + # push (@list, $hf) if(index($hfData, "Q_OBJECT") >= 0); ### fast but doesn't handle //Q_OBJECT + # handle " { friend class blah; Q_OBJECT ", but don't match antlarr_Q_OBJECT (\b). + if ( $hfData =~ /{([^}]*)\bQ_OBJECT/s ) { + push (@list, $hf) unless $1 =~ m://[^\n]*Q_OBJECT[^\n]*$:s; ## reject "// Q_OBJECT" + } + } + # The assoc array of root of headerfile and header filename + foreach $hFile (@list) + { + $hFile =~ /(.*)\.[^\.]*$/; # Find name minus extension + if ($mocFiles{$1}) + { + print STDERR "Warning: Multiple header files found for $1\n"; + next; # Use the first one + } + $mocFiles{$1} = "$dir\035$hFile"; # Add relative dir + } + } + + return 0; +} + +#----------------------------------------------------------------------------- + +# The programmer has specified a moc list. Prune out the moc candidates +# list that we found based on looking at the header files. This generates +# a warning if the programmer gets the list wrong, but this doesn't have +# to be fatal here. +sub pruneMocCandidates ($) +{ + my %prunedMoc = (); + local @mocList = split(' ', $_[0]); + + foreach $mocname (@mocList) + { + $mocname =~ s/\.moc$//; + if ($mocFiles{$mocname}) + { + $prunedMoc{$mocname} = $mocFiles{$mocname}; + } + else + { + my $print = $makefileDir; + $print =~ s/^\Q$topdir\E\\//; + # They specified a moc file but we can't find a header that + # will generate this moc file. That's possible fatal! + print STDERR "Warning: No moc-able header file for $print/$mocname\n"; + } + } + + undef %mocFiles; + %mocFiles = %prunedMoc; +} + +#----------------------------------------------------------------------------- + +# Finds the cpp files (If they exist). +# The cpp files get appended to the header file separated by \035 +sub checkMocCandidates () +{ + my @cppFiles; + my $cpp2moc; # which c++ file includes which .moc files + my $moc2cpp; # which moc file is included by which c++ files + + return unless (keys %mocFiles); + opendir(THISDIR, ".") || return; + @cppFiles = grep { /.+\.$cppExt$/o && !/.+\.moc\.$cppExt$/o + && !/.+\.all_$cppExt\.$cppExt$/o + && !/^\./ } readdir(THISDIR); + closedir THISDIR; + return unless (@cppFiles); + my $files = join (" ", @cppFiles); + $cpp2moc = {}; + $moc2cpp = {}; + foreach $cxxf (@cppFiles) + { + open (CXXFIN, $cxxf) || die "Could not open $cxxf: $!\n"; + seek(CXXFIN, 0, 2); + my $cxxfsize = tell(CXXFIN); + seek(CXXFIN, 0, 0); + read CXXFIN, $cxxfData, $cxxfsize; + close CXXFIN; + while(($cxxfData =~ m/^[ \t]*\#include\s*[<\"](.*\.moc)[>\"]/gm)) { + $cpp2moc->{$cxxf}->{$1} = 1; + $moc2cpp->{$1}->{$cxxf} = 1; + } + } + foreach my $mocFile (keys (%mocFiles)) + { + @cppFiles = keys %{$moc2cpp->{"$mocFile.moc"}}; + if (@cppFiles == 1) { + $mocFiles{$mocFile} .= "\035" . $cppFiles[0]; + push(@depend, $mocFile); + } elsif (@cppFiles == 0) { + push (@newObs, $mocFile); # Produce new object file + next if ($haveAutomocTag); # This is expected... + # But this is an error we can deal with - let them know + print STDERR + "Warning: No c++ file that includes $mocFile.moc\n"; + } else { + # We can't decide which file to use, so it's fatal. Although as a + # guess we could use the mocFile.cpp file if it's in the list??? + print STDERR + "Error: Multiple c++ files that include $mocFile.moc\n"; + print STDERR "\t",join ("\t", @cppFiles),"\n"; + $errorflag = 1; + delete $mocFiles{$mocFile}; + # Let's continue and see what happens - They have been told! + } + } +} + +#----------------------------------------------------------------------------- + +# Add the rules for generating moc source from header files +# For Automoc output *.moc.cpp but normally we'll output *.moc +# (We must compile *.moc.cpp separately. *.moc files are included +# in the appropriate *.cpp file by the programmer) +sub addMocRules () +{ + my $cppFile; + my $hFile; + + foreach $mocFile (keys (%mocFiles)) + { + undef $cppFile; + ($dir, $hFile, $cppFile) = split ("\035", $mocFiles{$mocFile}, 3); + $dir =~ s#^\.#\$(srcdir)#; + if (defined ($cppFile)) + { + $cppFile =~ s,\.[^.]*$,,; + $target_adds{"$cppFile.o"} .= "$mocFile.moc "; + $target_adds{"$cppFile.lo"} .= "$mocFile.moc "; + appendLines ("$mocFile.moc: $dir/$hFile\n\t\$(MOC) $dir/$hFile -o $mocFile.moc\n"); + $cleanMoc .= " $mocFile.moc"; + appendLines ("mocs: $mocFile.moc\n"); + } + else + { + appendLines ("$mocFile$mocExt: $dir/$hFile\n\t\$(MOC) $dir/$hFile -o $mocFile$mocExt\n"); + $cleanMoc .= " $mocFile$mocExt"; + appendLines ("mocs: $mocFile$mocExt\n"); + } + } +} + +sub make_bcheck_target() +{ + my $lookup = 'RECURSIVE_TARGETS\s*=[ \t]*(.*)'; + my $bcheckdep = "bcheck-am"; + $bcheckdep = "bcheck-recursive" if ($MakefileData =~ /\n$lookup/); + + my $headers= ""; + $headers = $1 if($MakefileData =~ /\nHEADERS\s*=[ \t]*(.+)/); + $headers =~ s/\$\((?:noinst|EXTRA)_HEADERS\)//g; + + $target_adds{"clean-am"} .= "clean-bcheck "; + + my $t = "clean-bcheck: \n" . + "\trm -f *.bchecktest.cc *.bchecktest.cc.class a.out\n\n" . + "bcheck: $bcheckdep\n\n" . + "bcheck-am:\n" . + "\t\@for i in $headers; do \\\n" . + "\t if test \$(srcdir)/\$\$i -nt \$\$i.bchecktest.cc; then \\\n" . + "\t echo \"int main() {return 0;}\" > \$\$i.bchecktest.cc ; \\\n" . + "\t echo \"#include \\\"\$\$i\\\"\" >> \$\$i.bchecktest.cc ; \\\n" . + "\t echo \"\$\$i\"; \\\n" . + "\t if ! "; + $t .= $cxxsuffix eq "KKK" ? + "\$(CXX) \$(DEFS) -I. -I\$(srcdir) -I\$(top_builddir) \$(INCLUDES) \$(AM_CPPFLAGS) \$(CPPFLAGS) \$(CXXFLAGS) \$(KDE_CXXFLAGS) " : + "\$(CXXCOMPILE) "; + $t .= " --dump-class-hierarchy -c \$\$i.bchecktest.cc; then \\\n" . + "\t rm -f \$\$i.bchecktest.cc; exit 1; \\\n" . + "\t fi ; \\\n" . + "\t echo \"\" >> \$\$i.bchecktest.cc.class; \\\n" . + "\t perl \$(top_srcdir)/admin/bcheck.pl \$\$i.bchecktest.cc.class || { rm -f \$\$i.bchecktest.cc; exit 1; }; \\\n" . + "\t rm -f a.out; \\\n" . + "\t fi ; \\\n" . + "\tdone\n"; + appendLines("$t\n"); +} + +sub make_meta_classes () +{ + return if ($kdeopts{"qtonly"}); + + my $cppFile; + my $hFile; + my $moc_class_headers = ""; + foreach $program (@programs) { + my $mocs = ""; + my @progsources = split(/[\034\s]+/, $sources{$program}); + my @depmocs = split(' ', $dependmocs{$program}); + my %shash = (), %mhash = (); + @shash{@progsources} = 1; # we are only interested in the existence + @mhash{@depmocs} = 1; + + print STDOUT "program=$program\n" if ($verbose); + print STDOUT "psources=[".join(' ', keys %shash)."]\n" if ($verbose); + print STDOUT "depmocs=[".join(' ', keys %mhash)."]\n" if ($verbose); + print STDOUT "globalmocs=[".join(' ', keys(%globalmocs))."]\n" if ($verbose); + foreach my $mocFile (keys (%globalmocs)) + { + my ($dir, $hFile, $cppFile) = split ("\035", $globalmocs{$mocFile}, 3); + if (defined ($cppFile)) + { + $mocs .= " $mocFile.moc" if exists $shash{$cppFile}; + } + else + { + # Bah. This is the case, if no C++ file includes the .moc + # file. We make a .moc.cpp file for that. Unfortunately this + # is not included in the %sources hash, but rather is mentioned + # in %dependmocs. If the user wants to use AUTO he can't just + # use an unspecific METAINCLUDES. Instead he must use + # program_METAINCLUDES. Anyway, it's not working real nicely. + # E.g. Its not clear what happens if user specifies two + # METAINCLUDES=AUTO in the same Makefile.am. + $mocs .= " $mocFile.moc.$cxxsuffix" + if exists $mhash{$mocFile.".moc.$cxxsuffix"}; + } + } + if ($mocs) { + print STDOUT "==> mocs=[".$mocs."]\n" if ($verbose); + } + print STDOUT "\n" if $verbose; + } + if ($moc_class_headers) { + appendLines ("$cleantarget-moc-classes:\n\t-rm -f $moc_class_headers\n"); + $target_adds{"$cleantarget-am"} .= "$cleantarget-moc-classes "; + } +} + +#----------------------------------------------------------------------------- + +sub updateMakefile () +{ + return if ($dryrun); + + open (FILEOUT, "> $makefile") + || die "Could not create $makefile: $!\n"; + + $MakefileData =~ s/\034/\\\n/g; # Restore continuation lines + # Append our $progId line, _below_ the "generated by automake" line + # because automake-1.6 relies on the first line to be his own. + my $progIdLine = "\# $progId - " . '$Revision: 483858 $ '."\n"; + if ( !( $MakefileData =~ s/^(.*generated .*by automake.*\n)/$1$progIdLine/ ) ) { + warn "automake line not found in $makefile\n"; + # Fallback: first line + print FILEOUT $progIdLine; + }; + print FILEOUT $MakefileData; + close FILEOUT; +} + +#----------------------------------------------------------------------------- + +# The given line needs to be removed from the makefile +# Do this by adding the special "removed line" comment at the line start. +sub removeLine ($$) +{ + my ($lookup, $old) = @_; + + $old =~ s/\034/\\\n#>- /g; # Fix continuation lines + $MakefileData =~ s/\n$lookup/\n#>\- $old/; +} + +#----------------------------------------------------------------------------- + +# Replaces the old line with the new line +# old line(s) are retained but tagged as removed. The new line(s) have the +# "added" tag placed before it. +sub substituteLine ($$) +{ + my ($lookup, $new) = @_; + + if ($MakefileData =~ /\n($lookup)/) { + $old = $1; + $old =~ s/\034/\\\n#>\- /g; # Fix continuation lines + my $newCount = ($new =~ tr/\034//) + ($new =~ tr/\n//) + 1; + $new =~ s/\\\n/\034/g; + $MakefileData =~ s/\n$lookup/\n#>- $old\n#>\+ $newCount\n$new/; + } else { + warn "Warning: substitution of \"$lookup\" in $printname failed\n"; + } +} + +#----------------------------------------------------------------------------- + +# Slap new lines on the back of the file. +sub appendLines ($) +{ + my ($new) = @_; + my $copynew = $new; + my $newCount = ($new =~ tr/\034//) + ($new =~ tr/\n//) + 1; + $new =~ s/\\\n/\034/g; # Fix continuation lines + $MakefileData .= "\n#>\+ $newCount\n$new"; +} + +#----------------------------------------------------------------------------- + +# Restore the Makefile.in to the state it was before we fiddled with it +sub restoreMakefile () +{ + $MakefileData =~ s/# $progId[^\n\034]*[\n\034]*//g; + # Restore removed lines + $MakefileData =~ s/([\n\034])#>\- /$1/g; + # Remove added lines + while ($MakefileData =~ /[\n\034]#>\+ ([^\n\034]*)/) + { + my $newCount = $1; + my $removeLines = ""; + while ($newCount--) { + $removeLines .= "[^\n\034]*([\n\034]|)"; + } + $MakefileData =~ s/[\n\034]#>\+.*[\n\034]$removeLines/\n/; + } +} + +#----------------------------------------------------------------------------- + +# find the .kcfg file listed in the .kcfgc file +sub findKcfgFile($) +{ + my ($kcfgf) = @_; + open (KCFGFIN, $kcfgf) || die "Could not open $kcfgf: $!\n"; + seek(KCFGFIN, 0, 2); + my $kcfgfsize = tell(KCFGFIN); + seek(KCFGFIN, 0, 0); + read KCFGFIN, $kcfgfData, $kcfgfsize; + close KCFGFIN; + if(($kcfgfData =~ m/^File=(.*\.kcfg)/gm)) { + $kcfg = $1; + } +} diff --git a/admin/bcheck.pl b/admin/bcheck.pl new file mode 100644 index 0000000..0cdcea9 --- /dev/null +++ b/admin/bcheck.pl @@ -0,0 +1,157 @@ +#!/usr/bin/perl -w + +use DB_File; +use Fcntl ':flock'; + +if (!defined($ARGV[0])) { + print "usage: requires .class dump as parameter!\n"; + exit; +} + +sub bailout +{ + untie %bcheckdb if(defined(%bcheckdb)); + + if(defined(MYLOCK)) { + flock MYLOCK, LOCK_UN; + close(MYLOCK); + } + + print @_; + exit 5; +} + +sub ask_user +{ + my ($dbkey, $dbchunk) = @_; + + if (defined($ENV{"BCHECK_UPDATE"})) { + $bcheckdb{$dbkey} = $dbchunk; + return; + } + + &bailout("BC problem detected") if (! -t STDIN); + + print "(I)gnore / (Q)uit / (U)pdate: "; + + my $key; + while(defined(read STDIN, $key, 1)) { + $key = lc($key); + + print "got: >$key<\n"; + + return if ($key eq 'i'); + + &bailout("BC problem. aborted") if ($key eq 'q'); + + if ($key eq 'u') { + $bcheckdb{$dbkey} = $dbchunk; + return; + } + print "\n(I)gnore / (Q)uit / (U)pdate: "; + } +} + +sub diff_chunk($$) +{ + my ($oldl, $newl) = @_; + my @old = split /^/m, $oldl; + my @new = split /^/m, $newl; + my $haschanges = 0; + my $max = $#old > $#new ? $#old : $#new; + + die "whoops. key different" if ($old[0] ne $new[0]); + + if ($#old != $#new) { + warn ("Structural difference.\n"); + print @old; + print "-----------------------------------------------\n"; + print @new; + $haschanges = 1; + return $haschanges; + } + + print $old[0]; + + my ($class) = ($old[0] =~ /^(?:Class |Vtable for )(\S+)/); + + my $c = 1; + while ($c < $max) { + my ($o, $n) = ($old[$c], $new[$c]); + chomp $o; + chomp $n; + $c++; + next if ($o eq $n); + + if(defined($class) and $n =~ /^(\d+\s+)\w+(::\S+\s*.*)$/) { + next if ($n eq "$1$class$2"); + } + + $haschanges = 1; + + print "-$o\n+$n\n\n"; + } + + return $haschanges; +} + +local $dblock = $ENV{"HOME"} . "/bcheck.lock"; +my $dbfile = $ENV{"HOME"} . "/bcheck.db"; +my $cdump = $ARGV[0]; + +die "file $cdump is not readable: $!" if (! -f $cdump); + +# make sure the advisory lock exists +open(MYLOCK, ">$dblock"); +print MYLOCK ""; + +flock MYLOCK, LOCK_EX; + +tie %bcheckdb, 'DB_File', $dbfile; + +my $chunk = ""; + +open (IN, "<$cdump") or die "cannot open $cdump: $!"; +while () { + + chop; + + s/0x[0-9a-fA-F]+/0x......../g; + s/base size=/size=/g; + s/\(\)\s*$//g; + s/base align=/align=/g; + + $chunk .= $_ . "\n"; + + if(/^\s*$/) { + my @lines = split /^/m, $chunk; + my $key = $lines[0]; + chomp $key; + + if($key !~ // && + $key !~ //) { + if(defined($bcheckdb{$key})) { + my $dbversion = $bcheckdb{$key}; + + if($dbversion ne $chunk) { + &ask_user($key, $chunk) if(&diff_chunk($dbversion, $chunk)); + } + } + else { + $bcheckdb{$key} = $chunk; + print "NEW: $key\n"; + } + } + + $chunk = ""; + next; + } + +} +close(IN); + +untie %bcheckdb; +flock MYLOCK, LOCK_UN; +close(MYLOCK); + +exit 0; diff --git a/admin/compile b/admin/compile new file mode 100755 index 0000000..09da7f0 --- /dev/null +++ b/admin/compile @@ -0,0 +1,142 @@ +#! /bin/sh +# Wrapper for compilers which do not understand `-c -o'. + +scriptversion=2005-05-14.22 + +# Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc. +# Written by Tom Tromey . +# +# 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, 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 02110-1301, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + +case $1 in + '') + echo "$0: No command. Try \`$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: compile [--help] [--version] PROGRAM [ARGS] + +Wrapper for compilers which do not understand `-c -o'. +Remove `-o dest.o' from ARGS, run PROGRAM with the remaining +arguments, and rename the output as expected. + +If you are trying to build a whole package this is not the +right script to run: please start by reading the file `INSTALL'. + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "compile $scriptversion" + exit $? + ;; +esac + +ofile= +cfile= +eat= + +for arg +do + if test -n "$eat"; then + eat= + else + case $1 in + -o) + # configure might choose to run compile as `compile cc -o foo foo.c'. + # So we strip `-o arg' only if arg is an object. + eat=1 + case $2 in + *.o | *.obj) + ofile=$2 + ;; + *) + set x "$@" -o "$2" + shift + ;; + esac + ;; + *.c) + cfile=$1 + set x "$@" "$1" + shift + ;; + *) + set x "$@" "$1" + shift + ;; + esac + fi + shift +done + +if test -z "$ofile" || test -z "$cfile"; then + # If no `-o' option was seen then we might have been invoked from a + # pattern rule where we don't need one. That is ok -- this is a + # normal compilation that the losing compiler can handle. If no + # `.c' file was seen then we are probably linking. That is also + # ok. + exec "$@" +fi + +# Name of file we expect compiler to create. +cofile=`echo "$cfile" | sed -e 's|^.*/||' -e 's/\.c$/.o/'` + +# Create the lock directory. +# Note: use `[/.-]' here to ensure that we don't use the same name +# that we are using for the .o file. Also, base the name on the expected +# object file name, since that is what matters with a parallel build. +lockdir=`echo "$cofile" | sed -e 's|[/.-]|_|g'`.d +while true; do + if mkdir "$lockdir" >/dev/null 2>&1; then + break + fi + sleep 1 +done +# FIXME: race condition here if user kills between mkdir and trap. +trap "rmdir '$lockdir'; exit 1" 1 2 15 + +# Run the compile. +"$@" +ret=$? + +if test -f "$cofile"; then + mv "$cofile" "$ofile" +elif test -f "${cofile}bj"; then + mv "${cofile}bj" "$ofile" +fi + +rmdir "$lockdir" +exit $ret + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/admin/conf.change.pl b/admin/conf.change.pl new file mode 100644 index 0000000..94ed3b0 --- /dev/null +++ b/admin/conf.change.pl @@ -0,0 +1,191 @@ +#!/usr/bin/env perl + +# this script patches a config.status file, to use our own perl script +# in the main loop +# we do it this way to circumvent hacking (and thereby including) +# autoconf function (which are GPL) into our LGPL acinclude.m4.in +# written by Michael Matz +# adapted by Dirk Mueller +# +# This file is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. + +# This library 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 +# Library General Public License for more details. + +# You should have received a copy of the GNU Library General Public License +# along with this library; see the file COPYING.LIB. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. + +# we have to change two places +# 1. the splitting of the substitutions into chunks of 90 (or even 48 in +# later autoconf's +# 2. the big main loop which patches all Makefile.in's + +use strict; +use File::Basename; + +my $ac_aux_dir = dirname($0); +my ($flag); +my $ac_version = 0; +my $vpath_seen = 0; +$flag = 0; + +while (<>) { +# usage of $flag: 0 -- we have seen nothing yet +# 1 -- we are in (1) +# 2 -- we have ended (1) +# 3 -- we are in (2) +# 4 -- we ended (2) + + if ($flag == 4) { + print; + } elsif ($flag == 0) { +# 1. begins with (including): "ac_max_sed_\S+\s*=\s*[0-9]+..." +# ends with (excluding) "CONFIG_FILE=..." +# in later autoconf (2.14.1) there is no CONFIG_FILES= line, +# but instead the (2) directly follow (1) + if (/^\s*ac_max_sed_([a-z]+).*=\s*([0-9]+)/ ) { + $flag = 1; + if ($1 eq 'lines') { + # lets hope its different with 2141, + # wasn't able to verify that + if ($2 eq '48') { + $ac_version = 250; + } + else { + $ac_version = 2141; + } + } elsif ($1 eq 'cmds') { + $ac_version = 213; + } + # hmm, we don't know the autoconf version, but we try anyway + } else { + print; + } + } elsif ($flag == 1) { + if (/^\s*CONFIG_FILES=/ && ($ac_version != 250)) { + print; + $flag = 2; + } elsif (/^\s*for\s+ac_file\s+in\s+.*CONFIG_FILES/ ) { + $flag = 3; + } + } elsif ($flag == 2) { +# 2. begins with: "for ac_file in.*CONFIG_FILES" (the next 'for' after (1)) +# end with: "rm -f conftest.s\*" +# on autoconf 250, it ends with '# CONFIG_HEADER section' +# +# gg: if a post-processing commands section is found first, +# stop there and insert a new loop to honor the case/esac. +# (pattern: /^\s+#\sRun the commands associated with the file./) + + if (/^\s*for\s+ac_file\s+in\s+.*CONFIG_FILES/ ) { + $flag = 3; + } else { + print; + } + } elsif ($flag == 3) { + if (/^\s*rm\s+-f\s+conftest/ ) { + $flag = 4; + &insert_main_loop(); + } elsif (/^\s*rm\s+-f\s+.*ac_cs_root/ ) { + $flag = 4; + &insert_main_loop(); + #die "hhhhhhh"; + if ($ac_version != 2141) { + print STDERR "hmm, don't know autoconf version\n"; + } + } elsif (/^\#\s*CONFIG_(HEADER|COMMANDS) section.*|^\s+#\s(Run) the commands associated/) { + $flag = 4; + my $commands = defined $2; + &insert_main_loop(); + $commands && insert_command_loop(); + if($ac_version != 250) { + print STDERR "hmm, something went wrong :-(\n"; + } + } elsif (/VPATH/ ) { + $vpath_seen = 1; + } + } +} + +die "wrong input (flag != 4)" unless $flag == 4; +print STDERR "hmm, don't know autoconf version\n" unless $ac_version; + +sub insert_main_loop { + + if ($ac_version == 250) { + &insert_main_loop_250(); + } + else { + &insert_main_loop_213(); + } +} + +sub insert_main_loop_250 { + + print <>\$tmp/subs.sed +EOF + } + print <> \$tmp/subs.files + fi + done + if test -f \$tmp/subs.files ; then + perl $ac_aux_dir/config.pl "\$tmp/subs.sed" "\$tmp/subs.files" "\$srcdir" "\$INSTALL" + fi + rm -f \$tmp/subs.files + +fi +EOF + return; +} + +sub insert_main_loop_213 { + print <> \$ac_cs_root.subs +EOF + } + print <> \$ac_cs_root.sacfiles + fi +done +if test -f \$ac_cs_root.sacfiles ; then + perl $ac_aux_dir/config.pl "\$ac_cs_root.subs" "\$ac_cs_root.sacfiles" "\$ac_given_srcdir" "\$ac_given_INSTALL" +fi +rm -f \$ac_cs_root.s* + +EOF + return; +} + +sub insert_command_loop { + print <. +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit build system type. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep __ELF__ >/dev/null + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerppc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm:riscos:*:*|arm:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:SunOS:5.*:*) + echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[45]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + # avoid double evaluation of $set_cc_for_build + test -n "$CC_FOR_BUILD" || eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep __LP64__ >/dev/null + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + i*:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + x86:Interix*:[34]*) + echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//' + exit ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + arm*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + cris:Linux:*:*) + echo cris-axis-linux-gnu + exit ;; + crisv32:Linux:*:*) + echo crisv32-axis-linux-gnu + exit ;; + frv:Linux:*:*) + echo frv-unknown-linux-gnu + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + mips:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips + #undef mipsel + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mipsel + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips64 + #undef mips64el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mips64el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips64 + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + x86_64:Linux:*:*) + echo x86_64-unknown-linux-gnu + exit ;; + i*86:Linux:*:*) + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. cd to the root directory to prevent + # problems with other programs or directories called `ld' in the path. + # Set LC_ALL=C to ensure ld outputs messages in English. + ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ + | sed -ne '/supported targets:/!d + s/[ ][ ]*/ /g + s/.*supported targets: *// + s/ .*// + p'` + case "$ld_supported_targets" in + elf32-i386) + TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" + ;; + a.out-i386-linux) + echo "${UNAME_MACHINE}-pc-linux-gnuaout" + exit ;; + coff-i386) + echo "${UNAME_MACHINE}-pc-linux-gnucoff" + exit ;; + "") + # Either a pre-BFD a.out linker (linux-gnuoldld) or + # one that does not give us useful --help. + echo "${UNAME_MACHINE}-pc-linux-gnuoldld" + exit ;; + esac + # Determine whether the default compiler is a.out or elf + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + #ifdef __ELF__ + # ifdef __GLIBC__ + # if __GLIBC__ >= 2 + LIBC=gnu + # else + LIBC=gnulibc1 + # endif + # else + LIBC=gnulibc1 + # endif + #else + #ifdef __INTEL_COMPILER + LIBC=gnu + #else + LIBC=gnuaout + #endif + #endif + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` + test x"${LIBC}" != x && { + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" + exit + } + test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } + ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i386. + echo i386-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + case $UNAME_PROCESSOR in + *86) UNAME_PROCESSOR=i686 ;; + unknown) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NSE-?:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/admin/config.pl b/admin/config.pl new file mode 100644 index 0000000..cfbb609 --- /dev/null +++ b/admin/config.pl @@ -0,0 +1,238 @@ +#!/usr/bin/env perl +# a script for use by autoconf to make the Makefiles +# from the Makefile.in's +# +# the original autoconf mechanism first splits all substitutions into groups +# of ca. 90, and than invokes sed for _every_ Makefile.in and every group +# (so around 2-3 times per Makefile.in). So this takes forever, as sed +# has to recompile the regexps every time. +# +# this script does better. It changes all Makefile.ins in one process. +# in kdelibs the time for building Makefile went down from 2:59 min to 13 sec! +# +# written by Michael Matz +# adapted by Dirk Mueller + +# This file is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. + +# This library 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 +# Library General Public License for more details. + +# You should have received a copy of the GNU Library General Public License +# along with this library; see the file COPYING.LIB. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. + +use strict; + +use File::Path; + +my $ac_subs=$ARGV[0]; +my $ac_sacfiles = $ARGV[1]; +my $ac_given_srcdir=$ARGV[2]; +my $ac_given_INSTALL=$ARGV[3]; + +my @comp_match; +my @comp_subs; + +#print "ac_subs=$ac_subs\n"; +#print "ac_sacfiles=$ac_sacfiles\n"; +#print "ac_given_srcdir=$ac_given_srcdir\n"; +#print "ac_given_INSTALL=$ac_given_INSTALL\n"; + +my $configure_input; +my ($srcdir, $top_srcdir); +my $INSTALL; +my $bad_perl = ($] < 5.005); +my $created_file_count = 0; + +open(CF, "< $ac_subs") || die "can't open $ac_subs: $!"; +my @subs = ; +my $pat; +close(CF); +chomp @subs; +@comp_match=(); +@comp_subs=(); + +if ($bad_perl) { + print "Using perl older than version 5.005\n"; + foreach $pat (@subs) { + if ( ($pat =~ m/s%([^%]*)%([^%]*)%g/ ) + || ($pat =~ m/s%([^%]*)%([^%]*)%;t/ ) + || ($pat =~ m/s,([^,]*),(.*),;t/) + || ($pat =~ m%s/([^/]*)/([^/]*)/g% ) + || ($pat =~ m%s/([^/]*)/([^/]*)/;t% ) + ) { + # form : s%bla%blubb%g + # or s%bla%blubb%;t t (autoconf > 2.13 and < 2.52 ?) + # or s,bla,blubb,;t t (autoconf 2.52) + my $srch = $1; + my $repl = $2; + $repl =~ s/\\(.)/$1/g; + push @comp_subs, make_closure($srch, $repl); + + } elsif ( ($pat =~ /%([^%]*)%d/ ) + || ($pat =~ m%/([^/]*)/d% ) + ) { + push @comp_subs, make_closure($1, ""); + } else { + die "Uhh. Malformed pattern in $ac_subs ($pat)" + unless ( $pat =~ /^\s*$/ ); # ignore white lines + } + } +} else { + foreach $pat (@subs) { + if ( ($pat =~ /s%([^%]*)%([^%]*)%g/ ) || + ($pat =~ /s%([^%]*)%([^%]*)%;t/ ) || + ($pat =~ /s,([^,]*),(.*),;t/) ) { + # form : s%bla%blubb%g + # or s%bla%blubb%;t t (autoconf > 2.13 and < 2.52 ?) + # or s,bla,blubb,;t t (autoconf 2.52) + my $srch = $1; + my $repl = $2; + push @comp_match, eval "qr/\Q$srch\E/"; # compile match pattern + $repl =~ s/\\(.)/$1/g; + push @comp_subs, $repl; + } elsif ( ($pat =~ /%([^%]*)%d/ ) + || ($pat =~ m%/([^/]*)/d% ) + ) { + push @comp_match, eval "qr/\Q$1\E/"; + push @comp_subs, ""; + } else { + die "Uhh. Malformed pattern in $ac_subs ($pat)" + unless ( $pat =~ /^\s*$/ ); # ignore white lines + } + } +} +undef @subs; + +# read the list of files to be patched, form: +# ./Makefile arts/Makefile arts/examples/Makefile arts/flow/Makefile + +open(CF, "< $ac_sacfiles") || die "can't open $ac_sacfiles: $!"; +my @ac_files = ; +close(CF); +chomp @ac_files; + + +my $ac_file; +foreach $ac_file (@ac_files) { + next if $ac_file =~ /\.\./; + next if $ac_file =~ /^\s*$/; + my $ac_file_in; + my ($ac_dir, $ac_dots, $ac_dir_suffix); + + if ($ac_file =~ /.*:.*/ ) { + ($ac_file_in = $ac_file) =~ s%[^:]*:%%; + $ac_file =~ s%:.*%%; + } else { + $ac_file_in = $ac_file.".in"; + } + +# Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. + +# Remove last slash and all that follows it. Not all systems have dirname. + ($ac_dir = $ac_file) =~ s%/[^/][^/]*$%%; + if ( ($ac_dir ne $ac_file) && ($ac_dir ne ".")) { +# The file is in a subdirectory. + if (! -d "$ac_dir") { mkpath "$ac_dir", 0, 0777; } + ($ac_dir_suffix = $ac_dir) =~ s%^./%%; + $ac_dir_suffix="/".$ac_dir_suffix; +# A "../" for each directory in $ac_dir_suffix. + ($ac_dots = $ac_dir_suffix) =~ s%/[^/]*%../%g; + } else { + $ac_dir_suffix=""; + $ac_dots=""; + } + + if ($ac_given_srcdir eq ".") { + $srcdir="."; + if ($ac_dots) { + ( $top_srcdir = $ac_dots) =~ s%/$%%; + } else { $top_srcdir="."; } + } elsif ($ac_given_srcdir =~ m%^/%) { + $srcdir=$ac_given_srcdir.$ac_dir_suffix; + $top_srcdir = $ac_given_srcdir; + } else { + $srcdir = $ac_dots.$ac_given_srcdir.$ac_dir_suffix; + $top_srcdir = $ac_dots.$ac_given_srcdir; + } + + if ($ac_given_INSTALL) { + if ($ac_given_INSTALL =~ m%^/% ) { + $INSTALL = $ac_given_INSTALL; + } else { + $INSTALL = $ac_dots.$ac_given_INSTALL; + } + } + + print "fast creating $ac_file\n"; + unlink $ac_file; + my $ac_comsub=""; + my $fname=$ac_file_in; + $fname =~ s%.*/%%; + $configure_input="$ac_file. Generated from $fname by config.pl."; + + my $ac_file_inputs; + ($ac_file_inputs = $ac_file_in) =~ s%^%$ac_given_srcdir/%; + $ac_file_inputs =~ s%:% $ac_given_srcdir/%g; + + patch_file($ac_file, $ac_file_inputs); + ++$created_file_count; +} + +print "config.pl: fast created $created_file_count file(s).\n"; + +sub patch_file { + my ($outf, $infiles) = @_; + my $filedata; + my @infiles=split(' ', $infiles); + my $i=0; + my $name; + + foreach $name (@infiles) { + if (open(CF, "< $name")) { + while () { + $filedata .= $_; + } + close(CF); + } else { + print STDERR "can't open $name: $!"."\n"; + } + } + + $filedata =~ s%\@configure_input\@%$configure_input%g; + $filedata =~ s%\@srcdir\@%$srcdir%g; + $filedata =~ s%\@top_srcdir\@%$top_srcdir%g; + $filedata =~ s%\@INSTALL\@%$INSTALL%g; + + if ($bad_perl) { + while ($i <= $#comp_subs) { + my $ref = $comp_subs[$i]; + &$ref(\$filedata); + $i++; + } + } else { + while ($i <= $#comp_match) { + $filedata =~ s/$comp_match[$i]/$comp_subs[$i]/g; + $i++; + } + } + open(CF, "> $outf") || die "can't create $outf: $!"; + print CF $filedata; + close(CF); +} + +sub make_closure { + my ($pat, $sub) = @_; + my $ret = eval "return sub { my \$ref=shift; \$\$ref =~ s%\Q$pat\E%\Q$sub\E%g; }"; + if ($@) { + print "can't create CODE: $@\n"; + } + return $ret; +} diff --git a/admin/config.sub b/admin/config.sub new file mode 100755 index 0000000..292f85e --- /dev/null +++ b/admin/config.sub @@ -0,0 +1,1575 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + +timestamp='2005-07-01' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file 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 +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-dietlibc | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | \ + kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray) + os= + basic_machine=$1 + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | m32r | m32rle | m68000 | m68k | m88k | maxq | mcore \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64vr | mips64vrel \ + | mips64orion | mips64orionel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | ms1 \ + | msp430 \ + | ns16k | ns32k \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b \ + | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | v850 | v850e \ + | we32k \ + | x86 | xscale | xscalee[bl] | xstormy16 | xtensa \ + | z8k) + basic_machine=$basic_machine-unknown + ;; + m32c) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | ms1-* \ + | msp430-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | pyramid-* \ + | romp-* | rs6000-* \ + | sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tron-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xps100-* | xscale-* | xscalee[bl]-* \ + | xstormy16-* | xtensa-* \ + | ymp-* \ + | z8k-*) + ;; + m32c-*) + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16c) + basic_machine=cr16c-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tic55x | c55x*) + basic_machine=tic55x-unknown + os=-coff + ;; + tic6x | c6x*) + basic_machine=tic6x-unknown + os=-coff + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* | -openbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -linux-uclibc* | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* | -skyos*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -zvmoe) + os=-zvmoe + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/admin/configure.in.bot.end b/admin/configure.in.bot.end new file mode 100644 index 0000000..5b23719 --- /dev/null +++ b/admin/configure.in.bot.end @@ -0,0 +1,47 @@ +# Check if KDE_SET_PREFIX was called, and --prefix was passed to configure +if test -n "$kde_libs_prefix" -a -n "$given_prefix"; then + # And if so, warn when they don't match + if test "$kde_libs_prefix" != "$given_prefix"; then + # And if kde doesn't know about the prefix yet + echo ":"`kde-config --path exe`":" | grep ":$given_prefix/bin/:" 2>&1 >/dev/null + if test $? -ne 0; then + echo "" + echo "Warning: you chose to install this package in $given_prefix," + echo "but KDE was found in $kde_libs_prefix." + echo "For this to work, you will need to tell KDE about the new prefix, by ensuring" + echo "that KDEDIRS contains it, e.g. export KDEDIRS=$given_prefix:$kde_libs_prefix" + echo "Then restart KDE." + echo "" + fi + fi +fi + +if test x$GXX = "xyes" -a x$kde_have_gcc_visibility = "xyes" -a x$kde_cv_val_qt_gcc_visibility_patched = "xno"; then + echo "" + echo "Your GCC supports symbol visibility, but the patch for Qt supporting visibility" + echo "was not included. Therefore, GCC symbol visibility support remains disabled." + echo "" + echo "For better performance, consider including the Qt visibility supporting patch" + echo "located at:" + echo "" + echo "http://bugs.kde.org/show_bug.cgi?id=109386" + echo "" + echo "and recompile all of Qt and KDE. Note, this is entirely optional and" + echo "everything will continue to work just fine without it." + echo "" +fi + +if test "$all_tests" = "bad"; then + if test ! "$cache_file" = "/dev/null"; then + echo "" + echo "Please remove the file $cache_file after changing your setup" + echo "so that configure will find the changes next time." + echo "" + fi +else + echo "" + echo "Good - your configure finished. Start make now" + echo "" + echo "Note for non-GNU systems users: in order to compile SIM, you need to use GNU make (gmake)" + echo "" +fi diff --git a/admin/configure.in.min b/admin/configure.in.min new file mode 100644 index 0000000..370a38a --- /dev/null +++ b/admin/configure.in.min @@ -0,0 +1,70 @@ +dnl This file is part of the KDE libraries/packages +dnl Copyright (C) 2001 Stephan Kulow (coolo@kde.org) + +dnl This file is free software; you can redistribute it and/or +dnl modify it under the terms of the GNU Library General Public +dnl License as published by the Free Software Foundation; either +dnl version 2 of the License, or (at your option) any later version. + +dnl This library is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl Library General Public License for more details. + +dnl You should have received a copy of the GNU Library General Public License +dnl along with this library; see the file COPYING.LIB. If not, write to +dnl the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +dnl Boston, MA 02111-1307, USA. + +# Original Author was Kalle@kde.org +# I lifted it in some mater. (Stephan Kulow) +# I used much code from Janos Farkas + +dnl Process this file with autoconf to produce a configure script. + +AC_INIT(acinclude.m4) dnl a source file from your sub dir + +dnl This is so we can use kde-common +AC_CONFIG_AUX_DIR(admin) + +dnl This ksh/zsh feature conflicts with `cd blah ; pwd` +unset CDPATH + +dnl Checking host/target/build systems, for make, install etc. +AC_CANONICAL_SYSTEM +dnl Perform program name transformation +AC_ARG_PROGRAM + +dnl Automake doc recommends to do this only here. (Janos) +AM_INIT_AUTOMAKE(@MODULENAME@, @VERSION@) dnl searches for some needed programs + +AC_ARG_ENABLE(kde, + AC_HELP_STRING([--disable-kde],[don't use kde]), + use_kde=$enableval, use_kde=yes) + +if test "$use_kde" = "yes"; then + KDE_SET_PREFIX +else + SIM_SET_PREFIX + KDE_FAST_CONFIGURE +fi + +dnl generate the config header +AM_CONFIG_HEADER(config.h) dnl at the distribution this done + +dnl Checks for programs. +AC_CHECK_COMPILERS +AC_ENABLE_SHARED(yes) +AC_ENABLE_STATIC(no) +AC_LIBTOOL_DLOPEN +KDE_PROG_LIBTOOL + +dnl for NLS support. Call them in this order! +dnl WITH_NLS is for the po files +AM_KDE_WITH_NLS +if test "x$use_kde" != "xyes"; then + KDE_CHECK_STL + include_ARTS_TRUE='#' + include_ARTS_FALSE= +fi +AC_PATH_KDE diff --git a/admin/debianrules b/admin/debianrules new file mode 100755 index 0000000..7aaae58 --- /dev/null +++ b/admin/debianrules @@ -0,0 +1,43 @@ +#!/usr/bin/perl -w + +use Shell qw(mv cp mkdir rm) ; +use File::Find; +use Cwd; + +$origPwd = `pwd`; +chomp $origPwd; + +$kde_prefix = "/usr"; +$sysconfdir = "/etc"; +$kde_includedir = "$kde_prefix/include/kde"; +$infodir = "$kde_prefix/share/info"; +$mandir = "$kde_prefix/share/man"; +$qtdir = "/usr/share/qt3"; + +$kde_cgidir = "$kde_prefix/lib/cgi-bin"; +$kde_confdir = "$sysconfdir/kde3"; +$kde_htmldir = "$kde_prefix/share/doc/kde/HTML"; + +if (defined $ENV{DEB_BUILD_OPTIONS} && + $ENV{DEB_BUILD_OPTIONS} =~ /\bnostrip\b/) { + $enable_debug="--enable-debug=full"; +} else { + $enable_debug="--disable-debug"; +} + +if (@ARGV && $ARGV[0] eq 'echodirs') { + print STDOUT "export kde_prefix=$kde_prefix\n"; + print STDOUT "export sysconfdir=$sysconfdir\n"; + print STDOUT "export kde_includedir=$kde_includedir\n"; + print STDOUT "export infodir=$infodir\n"; + print STDOUT "export mandir=$mandir\n"; + print STDOUT "export qtdir=$qtdir\n"; + + print STDOUT "export kde_cgidir=$kde_cgidir\n"; + print STDOUT "export kde_confdir=$kde_confdir\n"; + print STDOUT "export kde_htmldir=$kde_htmldir\n"; + + print STDOUT "configkde=$enable_debug --disable-rpath --prefix=\$(kde_prefix) --sysconfdir=\$(sysconfdir) --includedir=\$(kde_includedir) --infodir=\$(infodir) --mandir=\$(mandir) --with-qt-dir=\$(qtdir)\n"; + + exit +} diff --git a/admin/depcomp b/admin/depcomp new file mode 100755 index 0000000..3c86718 --- /dev/null +++ b/admin/depcomp @@ -0,0 +1,530 @@ +#! /bin/sh +# depcomp - compile a program generating dependencies as side-effects + +scriptversion=2005-07-09.11 + +# Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc. + +# 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, 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 +# 02110-1301, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Originally written by Alexandre Oliva . + +case $1 in + '') + echo "$0: No command. Try \`$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: depcomp [--help] [--version] PROGRAM [ARGS] + +Run PROGRAMS ARGS to compile a file, generating dependencies +as side-effects. + +Environment variables: + depmode Dependency tracking mode. + source Source file read by `PROGRAMS ARGS'. + object Object file output by `PROGRAMS ARGS'. + DEPDIR directory where to store dependencies. + depfile Dependency file to output. + tmpdepfile Temporary file to use when outputing dependencies. + libtool Whether libtool is used (yes/no). + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "depcomp $scriptversion" + exit $? + ;; +esac + +if test -z "$depmode" || test -z "$source" || test -z "$object"; then + echo "depcomp: Variables source, object and depmode must be set" 1>&2 + exit 1 +fi + +# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. +depfile=${depfile-`echo "$object" | + sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} +tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} + +rm -f "$tmpdepfile" + +# Some modes work just like other modes, but use different flags. We +# parameterize here, but still list the modes in the big case below, +# to make depend.m4 easier to write. Note that we *cannot* use a case +# here, because this file can only contain one case statement. +if test "$depmode" = hp; then + # HP compiler uses -M and no extra arg. + gccflag=-M + depmode=gcc +fi + +if test "$depmode" = dashXmstdout; then + # This is just like dashmstdout with a different argument. + dashmflag=-xM + depmode=dashmstdout +fi + +case "$depmode" in +gcc3) +## gcc 3 implements dependency tracking that does exactly what +## we want. Yay! Note: for some reason libtool 1.4 doesn't like +## it if -MD -MP comes after the -MF stuff. Hmm. + "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## There are various ways to get dependency output from gcc. Here's +## why we pick this rather obscure method: +## - Don't want to use -MD because we'd like the dependencies to end +## up in a subdir. Having to rename by hand is ugly. +## (We might end up doing this anyway to support other compilers.) +## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like +## -MM, not -M (despite what the docs say). +## - Using -M directly means running the compiler twice (even worse +## than renaming). + if test -z "$gccflag"; then + gccflag=-MD, + fi + "$@" -Wp,"$gccflag$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +## The second -e expression handles DOS-style file names with drive letters. + sed -e 's/^[^:]*: / /' \ + -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" +## This next piece of magic avoids the `deleted header file' problem. +## The problem is that when a header file which appears in a .P file +## is deleted, the dependency causes make to die (because there is +## typically no way to rebuild the header). We avoid this by adding +## dummy dependencies for each header file. Too bad gcc doesn't do +## this for us directly. + tr ' ' ' +' < "$tmpdepfile" | +## Some versions of gcc put a space before the `:'. On the theory +## that the space means something, we add a space to the output as +## well. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +sgi) + if test "$libtool" = yes; then + "$@" "-Wp,-MDupdate,$tmpdepfile" + else + "$@" -MDupdate "$tmpdepfile" + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + + if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files + echo "$object : \\" > "$depfile" + + # Clip off the initial element (the dependent). Don't try to be + # clever and replace this with sed code, as IRIX sed won't handle + # lines with more than a fixed number of characters (4096 in + # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; + # the IRIX cc adds comments like `#:fec' to the end of the + # dependency line. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ + tr ' +' ' ' >> $depfile + echo >> $depfile + + # The second pass generates a dummy entry for each header file. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> $depfile + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +aix) + # The C for AIX Compiler uses -M and outputs the dependencies + # in a .u file. In older versions, this file always lives in the + # current directory. Also, the AIX compiler puts `$object:' at the + # start of each line; $object doesn't have directory information. + # Version 6 uses the directory in both cases. + stripped=`echo "$object" | sed 's/\(.*\)\..*$/\1/'` + tmpdepfile="$stripped.u" + if test "$libtool" = yes; then + "$@" -Wc,-M + else + "$@" -M + fi + stat=$? + + if test -f "$tmpdepfile"; then : + else + stripped=`echo "$stripped" | sed 's,^.*/,,'` + tmpdepfile="$stripped.u" + fi + + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + + if test -f "$tmpdepfile"; then + outname="$stripped.o" + # Each line is of the form `foo.o: dependent.h'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile" + sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +icc) + # Intel's C compiler understands `-MD -MF file'. However on + # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c + # ICC 7.0 will fill foo.d with something like + # foo.o: sub/foo.c + # foo.o: sub/foo.h + # which is wrong. We want: + # sub/foo.o: sub/foo.c + # sub/foo.o: sub/foo.h + # sub/foo.c: + # sub/foo.h: + # ICC 7.1 will output + # foo.o: sub/foo.c sub/foo.h + # and will wrap long lines using \ : + # foo.o: sub/foo.c ... \ + # sub/foo.h ... \ + # ... + + "$@" -MD -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each line is of the form `foo.o: dependent.h', + # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process this invocation + # correctly. Breaking it into two sed invocations is a workaround. + sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" | + sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +tru64) + # The Tru64 compiler uses -MD to generate dependencies as a side + # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. + # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put + # dependencies in `foo.d' instead, so we check for that too. + # Subdirectories are respected. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + + if test "$libtool" = yes; then + # With Tru64 cc, shared objects can also be used to make a + # static library. This mecanism is used in libtool 1.4 series to + # handle both shared and static libraries in a single compilation. + # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. + # + # With libtool 1.5 this exception was removed, and libtool now + # generates 2 separate objects for the 2 libraries. These two + # compilations output dependencies in in $dir.libs/$base.o.d and + # in $dir$base.o.d. We have to check for both files, because + # one of the two compilations can be disabled. We should prefer + # $dir$base.o.d over $dir.libs/$base.o.d because the latter is + # automatically cleaned when .libs/ is deleted, while ignoring + # the former would cause a distcleancheck panic. + tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 + tmpdepfile2=$dir$base.o.d # libtool 1.5 + tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 + tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 + "$@" -Wc,-MD + else + tmpdepfile1=$dir$base.o.d + tmpdepfile2=$dir$base.d + tmpdepfile3=$dir$base.d + tmpdepfile4=$dir$base.d + "$@" -MD + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a tab and a space in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +#nosideeffect) + # This comment above is used by automake to tell side-effect + # dependency tracking mechanisms from slower ones. + +dashmstdout) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + test -z "$dashmflag" && dashmflag=-M + # Require at least two characters before searching for `:' + # in the target name. This is to cope with DOS-style filenames: + # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise. + "$@" $dashmflag | + sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + tr ' ' ' +' < "$tmpdepfile" | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +dashXmstdout) + # This case only exists to satisfy depend.m4. It is never actually + # run, as this mode is specially recognized in the preamble. + exit 1 + ;; + +makedepend) + "$@" || exit $? + # Remove any Libtool call + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + # X makedepend + shift + cleared=no + for arg in "$@"; do + case $cleared in + no) + set ""; shift + cleared=yes ;; + esac + case "$arg" in + -D*|-I*) + set fnord "$@" "$arg"; shift ;; + # Strip any option that makedepend may not understand. Remove + # the object too, otherwise makedepend will parse it as a source file. + -*|$object) + ;; + *) + set fnord "$@" "$arg"; shift ;; + esac + done + obj_suffix="`echo $object | sed 's/^.*\././'`" + touch "$tmpdepfile" + ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + sed '1,2d' "$tmpdepfile" | tr ' ' ' +' | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" "$tmpdepfile".bak + ;; + +cpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + "$@" -E | + sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ + -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | + sed '$ s: \\$::' > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + cat < "$tmpdepfile" >> "$depfile" + sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvisualcpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o, + # because we must use -o when running libtool. + "$@" || exit $? + IFS=" " + for arg + do + case "$arg" in + "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") + set fnord "$@" + shift + shift + ;; + *) + set fnord "$@" "$arg" + shift + shift + ;; + esac + done + "$@" -E | + sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" + echo " " >> "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +none) + exec "$@" + ;; + +*) + echo "Unknown depmode $depmode" 1>&2 + exit 1 + ;; +esac + +exit 0 + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/admin/deps.am b/admin/deps.am new file mode 100644 index 0000000..ce0c5d3 --- /dev/null +++ b/admin/deps.am @@ -0,0 +1,19 @@ +$(top_srcdir)/acinclude.m4: $(top_srcdir)/admin/acinclude.m4.in $(top_srcdir)/admin/libtool.m4.in $(top_srcdir)/admin/cvs.sh $(top_srcdir)/admin/pkg.m4.in + @cd $(top_srcdir) && $(SHELL) admin/cvs.sh acinclude_m4 + +$(top_srcdir)/configure.in: $(top_srcdir)/subdirs $(top_srcdir)/configure.files $(top_srcdir)/admin/cvs.sh + @cd $(top_srcdir) && $(SHELL) admin/cvs.sh configure_in + +$(top_srcdir)/configure.files: $(top_srcdir)/subdirs $(CONF_FILES) + @cd $(top_srcdir) && $(SHELL) admin/cvs.sh configure.files $(top_srcdir)/admin/cvs.sh + +$(top_srcdir)/Makefile.am: $(top_srcdir)/Makefile.am.in $(top_srcdir)/subdirs $(top_srcdir)/admin/cvs.sh + @cd $(top_srcdir) && $(SHELL) admin/cvs.sh Makefile_am + +$(top_srcdir)/subdirs: $(top_srcdir)/Makefile.am.in $(top_srcdir)/admin/cvs.sh + @cd $(top_srcdir) && $(SHELL) admin/cvs.sh subdirs + +# defining default rules for files that may not be present +$(top_srcdir)/Makefile.am.in: +$(CONF_FILES): + diff --git a/admin/detect-autoconf.pl b/admin/detect-autoconf.pl new file mode 100755 index 0000000..5c1d8d1 --- /dev/null +++ b/admin/detect-autoconf.pl @@ -0,0 +1,172 @@ +#!/usr/bin/env perl + +# Try to locate best version of auto* +# By Michael Pyne +# +# Copyright (c) 2005. +# This code is public domain. You may use it however you like (including +# relicensing). + +# Emulate the 'which' program. +sub which +{ + my $prog = shift; + my @paths = split(/:/, $ENV{'PATH'}); + + for $path (@paths) + { + return "$path/$prog" if -x "$path/$prog"; + } + + return ""; +} + +# Subroutine to determine the highest installed version of the given program, +# searching from the given paths. +sub findBest +{ + my ($program, @paths) = @_; + my $best_version_found = '0'; # Deliberately a string. + my %versions; + my %minimumVersions = ( + 'autoconf' => '2.5', + 'automake' => '1.6', + ); + my %ignore = map { $_ => 1 } qw(wrapper); # BSDism + + # Allow user to use environment variable to override search. + return $ENV{uc $program} if $ENV{uc $program}; + + for $prefix (@paths) + { + @files = glob "$prefix/$program*"; + for $file (@files) + { + # Don't check non-executable scripts. + next unless -x $file; + + ($version) = $file =~ /$prefix\/$program-?(.*)$/; + $version =~ s/-|\.//g; + + next if $ignore{$version}; + + # Special case some programs to make sure it has a minimum version. + if (not $version and exists $minimumVersions{$program}) + { + my $min_version = $minimumVersions{$program}; + my $versionOutput = `$program --version 2>/dev/null | head -n 1`; + + # If we can't run the script to get the version it likely won't work later. + next unless $versionOutput; + + # Use number.number for version (we don't need the excess in general). + ($versionOutput) = ($versionOutput =~ /(\d\.\d)/); + + # Use lt to do lexicographical comparison of strings (which should be + # equivalent and doesn't involve issues with floating point conversions). + if (not $versionOutput or $versionOutput lt $min_version) + { + next; + } + } + + # If no version suffix then use it in favor of a versioned autotool + # since the ever-popular WANT_AUTOFOO should then work (in theory). + return $file unless $version; + + # Emulate 'which', and abort if we've already seen this version. + next if exists $versions{$version}; + + # Save filename of program. + $versions{$version} = $file; + + # Use string comparison so that e.g. 253a will be > 253 but < 254. + if ($version gt $best_version_found) + { + $best_version_found = $version; + } + } + } + + return $versions{$best_version_found}; +} + +# Find an appropriate "which" program for later use by the shell script calling +# us. +sub findWhich +{ + for $candidate ('type -p', 'which', 'type') + { + $test = `$candidate sh 2>/dev/null`; + chomp $test; + + return $candidate if -x $test; + } +} + +# Uses which() to find a program unless the user provided its path in the +# environment (the upper case program name is searched). +sub findProgram +{ + $suffix = ""; # For use if @_ has only one param. + my ($program, $suffix) = @_; + + return $ENV{uc $program} if $ENV{uc $program}; + return which("$program$suffix"); +} + +# SCRIPT STARTS. + +# Search in path. +@paths = split(/:/, $ENV{'PATH'}); + +# Make sure at least /usr/bin and /usr/local/bin are in this search. +unshift @paths, '/usr/local/bin' unless grep $_ eq '/usr/local/bin', @paths; +unshift @paths, '/usr/bin' unless grep $_ eq '/usr/bin', @paths; + +$autoconf = findBest('autoconf', @paths); +($autoconf_suffix) = $autoconf =~ /.*autoconf(.*)$/; + +# Find matching autoconf companions. +$autoheader = findProgram('autoheader', $autoconf_suffix); +$autom4te = findProgram('autom4te', $autoconf_suffix); + +# Get best automake, and look for unsermake to possibly override it. +$automake = findBest('automake', @paths); +$unsermake = ""; +# backward compatible: if $UNSERMAKE points to a path, use it +$unsermake = findProgram('unsermake') if (defined($ENV{'UNSERMAKE'}) and $ENV{'UNSERMAKE'} =~ /\//); +# new compatible: if it says 'yes', use the one from path +$unsermake = which('unsermake') if ($ENV{'UNSERMAKE'} ne 'no'); + +($automake_suffix) = $automake =~ /.*automake(.*)$/; + +# Use unsermake if we found it. +$automake = "$unsermake -c" if $unsermake; + +# Find matching automake companions. +$aclocal = findProgram('aclocal', $automake_suffix); + +$which = findWhich(); + +# Make sure we have all of the needed programs. +for $i (qw'autoconf autoheader autom4te automake aclocal') +{ + die "# $0: Unable to find $i!!\n" unless(${$i}) +} + +# Print results in eval-able form. +print <&2 + exit 1 + fi + # It's OK to call `install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +test -n "$dir_arg" || trap '(exit $?); exit' 1 2 13 15 + +for src +do + # Protect names starting with `-'. + case $src in + -*) src=./$src ;; + esac + + if test -n "$dir_arg"; then + dst=$src + dstdir=$dst + test -d "$dstdir" + dstdir_status=$? + else + + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dstarg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + + dst=$dstarg + # Protect names starting with `-'. + case $dst in + -*) dst=./$dst ;; + esac + + # If destination is a directory, append the input filename; won't work + # if double slashes aren't ignored. + if test -d "$dst"; then + if test -n "$no_target_directory"; then + echo "$0: $dstarg: Is a directory" >&2 + exit 1 + fi + dstdir=$dst + dst=$dstdir/`basename "$src"` + dstdir_status=0 + else + # Prefer dirname, but fall back on a substitute if dirname fails. + dstdir=` + (dirname "$dst") 2>/dev/null || + expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$dst" : 'X\(//\)[^/]' \| \ + X"$dst" : 'X\(//\)$' \| \ + X"$dst" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || + echo X"$dst" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q' + ` + + test -d "$dstdir" + dstdir_status=$? + fi + fi + + obsolete_mkdir_used=false + + if test $dstdir_status != 0; then + case $posix_mkdir in + '') + posix_mkdir=false + if $mkdirprog -m $test_mode -p -- / >/dev/null 2>&1; then + posix_mkdir=true + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./-m "$test_mode" ./-p ./-- 2>/dev/null + fi ;; + esac + + if + $posix_mkdir && { + + # With -d, create the new directory with the user-specified mode. + # Otherwise, create it using the same intermediate mode that + # mkdir -p would use when creating intermediate directories. + # POSIX says that this mode is "$(umask -S),u+wx", so use that + # if umask -S works. + + if test -n "$dir_arg"; then + mkdir_mode=$mode + else + case $intermediate_mode in + '') + if umask_S=`(umask -S) 2>/dev/null`; then + intermediate_mode=$umask_S,u+wx + else + intermediate_mode=$test_mode + fi ;; + esac + mkdir_mode=$intermediate_mode + fi + + $mkdirprog -m "$mkdir_mode" -p -- "$dstdir" + } + then : + else + + # mkdir does not conform to POSIX, or it failed possibly due to + # a race condition. Create the directory the slow way, step by + # step, checking for races as we go. + + case $dstdir in + /*) pathcomp=/ ;; + -*) pathcomp=./ ;; + *) pathcomp= ;; + esac + + case $posix_glob in + '') + if (set -f) 2>/dev/null; then + posix_glob=true + else + posix_glob=false + fi ;; + esac + + oIFS=$IFS + IFS=/ + $posix_glob && set -f + set fnord $dstdir + shift + $posix_glob && set +f + IFS=$oIFS + + for d + do + test "x$d" = x && continue + + pathcomp=$pathcomp$d + if test ! -d "$pathcomp"; then + $mkdirprog "$pathcomp" + # Don't fail if two instances are running concurrently. + test -d "$pathcomp" || exit 1 + fi + pathcomp=$pathcomp/ + done + obsolete_mkdir_used=true + fi + fi + + if test -n "$dir_arg"; then + { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && + { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || + test -z "$chmodcmd" || $doit $chmodcmd "$mode" "$dst"; } || exit 1 + else + + # Make a couple of temp file names in the proper directory. + dsttmp=$dstdir/_inst.$$_ + rmtmp=$dstdir/_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + + # Copy the file name to the temp name. + $doit $cpprog "$src" "$dsttmp" && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \ + && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \ + && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \ + && { test -z "$chmodcmd" || $doit $chmodcmd "$mode" "$dsttmp"; } && + + # Now rename the file to the real destination. + { $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null \ + || { + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + if test -f "$dst"; then + $doit $rmcmd -f "$dst" 2>/dev/null \ + || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null \ + && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }; }\ + || { + echo "$0: cannot unlink or rename $dst" >&2 + (exit 1); exit 1 + } + else + : + fi + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dst" + } + } || exit 1 + + trap '' 0 + fi +done + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/admin/libtool.m4.in b/admin/libtool.m4.in new file mode 100644 index 0000000..84a5436 --- /dev/null +++ b/admin/libtool.m4.in @@ -0,0 +1,5891 @@ +# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- +## Copyright 1996, 1997, 1998, 1999, 2000, 2001 +## Free Software Foundation, Inc. +## Originally by Gordon Matzigkeit , 1996 +## +## 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 02110-1301, USA. +## +## As a special exception to the GNU General Public License, if you +## distribute this file as part of a program that contains a +## configuration script generated by Autoconf, you may include it under +## the same distribution terms that you use for the rest of that program. + +# serial 47 AC_PROG_LIBTOOL + + +# AC_PROVIDE_IFELSE(MACRO-NAME, IF-PROVIDED, IF-NOT-PROVIDED) +# ----------------------------------------------------------- +# If this macro is not defined by Autoconf, define it here. +m4_ifdef([AC_PROVIDE_IFELSE], + [], + [m4_define([AC_PROVIDE_IFELSE], + [m4_ifdef([AC_PROVIDE_$1], + [$2], [$3])])]) + + +# AC_PROG_LIBTOOL +# --------------- +AC_DEFUN([AC_PROG_LIBTOOL], +[AC_REQUIRE([_AC_PROG_LIBTOOL])dnl +dnl If AC_PROG_CXX has already been expanded, run AC_LIBTOOL_CXX +dnl immediately, otherwise, hook it in at the end of AC_PROG_CXX. + AC_PROVIDE_IFELSE([AC_PROG_CXX], + [AC_LIBTOOL_CXX], + [define([AC_PROG_CXX], defn([AC_PROG_CXX])[AC_LIBTOOL_CXX + ])]) +dnl And a similar setup for Fortran 77 support + AC_PROVIDE_IFELSE([AC_PROG_F77], + [AC_LIBTOOL_F77], + [define([AC_PROG_F77], defn([AC_PROG_F77])[AC_LIBTOOL_F77 +])]) + +dnl Quote A][M_PROG_GCJ so that aclocal doesn't bring it in needlessly. +dnl If either AC_PROG_GCJ or A][M_PROG_GCJ have already been expanded, run +dnl AC_LIBTOOL_GCJ immediately, otherwise, hook it in at the end of both. + AC_PROVIDE_IFELSE([AC_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [ifdef([AC_PROG_GCJ], + [define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[AC_LIBTOOL_GCJ])]) + ifdef([A][M_PROG_GCJ], + [define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[AC_LIBTOOL_GCJ])]) + ifdef([LT_AC_PROG_GCJ], + [define([LT_AC_PROG_GCJ], + defn([LT_AC_PROG_GCJ])[AC_LIBTOOL_GCJ])])])]) +])])# AC_PROG_LIBTOOL + + +# _AC_PROG_LIBTOOL +# ---------------- +AC_DEFUN([_AC_PROG_LIBTOOL], +[AC_REQUIRE([AC_LIBTOOL_SETUP])dnl +AC_BEFORE([$0],[AC_LIBTOOL_CXX])dnl +AC_BEFORE([$0],[AC_LIBTOOL_F77])dnl +AC_BEFORE([$0],[AC_LIBTOOL_GCJ])dnl + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool --silent' +AC_SUBST(LIBTOOL)dnl + +# Prevent multiple expansion +define([AC_PROG_LIBTOOL], []) +])# _AC_PROG_LIBTOOL + + +# AC_LIBTOOL_SETUP +# ---------------- +AC_DEFUN([AC_LIBTOOL_SETUP], +[AC_PREREQ(2.50)dnl +AC_REQUIRE([AC_ENABLE_SHARED])dnl +AC_REQUIRE([AC_ENABLE_STATIC])dnl +AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_LD])dnl +AC_REQUIRE([AC_PROG_LD_RELOAD_FLAG])dnl +AC_REQUIRE([AC_PROG_NM])dnl + +AC_REQUIRE([AC_PROG_LN_S])dnl +AC_REQUIRE([AC_DEPLIBS_CHECK_METHOD])dnl +# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers! +AC_REQUIRE([AC_OBJEXT])dnl +AC_REQUIRE([AC_EXEEXT])dnl +dnl + +AC_LIBTOOL_SYS_MAX_CMD_LEN +AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE +AC_LIBTOOL_OBJDIR + +AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl +_LT_AC_PROG_ECHO_BACKSLASH + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='sed -e s/^X//' +[sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g'] + +# Same as above, but do not quote variable references. +[double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g'] + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +# Constants: +rm="rm -f" + +# Global variables: +default_ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except M$VC, +# which needs '.lib'). +libext=a +ltmain="$ac_aux_dir/ltmain.sh" +ofile="$default_ofile" +with_gnu_ld="$lt_cv_prog_gnu_ld" + +AC_CHECK_TOOL(AR, ar, false) +AC_CHECK_TOOL(RANLIB, ranlib, :) +AC_CHECK_TOOL(STRIP, strip, :) + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru +test -z "$AS" && AS=as +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$DLLTOOL" && DLLTOOL=dlltool +test -z "$LD" && LD=ld +test -z "$LN_S" && LN_S="ln -s" +test -z "$MAGIC_CMD" && MAGIC_CMD=file +test -z "$NM" && NM=nm +test -z "$SED" && SED=sed +test -z "$OBJDUMP" && OBJDUMP=objdump +test -z "$RANLIB" && RANLIB=: +test -z "$STRIP" && STRIP=: +test -z "$ac_objext" && ac_objext=o + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="\$RANLIB -t \$oldlib~$old_postinstall_cmds" + ;; + *) + old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi + +# Only perform the check for file, if the check method requires it +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + AC_PATH_MAGIC + fi + ;; +esac + +AC_PROVIDE_IFELSE([AC_LIBTOOL_DLOPEN], enable_dlopen=yes, enable_dlopen=no) +AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL], +enable_win32_dll=yes, enable_win32_dll=no) + +AC_ARG_ENABLE([libtool-lock], + [AC_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +AC_ARG_WITH([pic], + [AC_HELP_STRING([--with-pic], + [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], + [pic_mode="$withval"], + [pic_mode=default]) +test -z "$pic_mode" && pic_mode=default + +# Use C for the default configuration in the libtool script +tagname= +AC_LIBTOOL_LANG_C_CONFIG +_LT_AC_TAGCONFIG +])# AC_LIBTOOL_SETUP + + +# _LT_AC_SYS_COMPILER +# ------------------- +AC_DEFUN([_LT_AC_SYS_COMPILER], +[AC_REQUIRE([AC_PROG_CC])dnl + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# Allow CC to be a program name with arguments. +compiler=$CC +])# _LT_AC_SYS_COMPILER + + +# _LT_AC_SYS_LIBPATH_AIX +# ---------------------- +# Links a minimal program and checks the executable +# for the system default hardcoded library path. In most cases, +# this is /usr/lib:/lib, but when the MPI compilers are used +# the location of the communication and MPI libs are included too. +# If we don't find anything, use the default library path according +# to the aix ld manual. +AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX], +[AC_LINK_IFELSE(AC_LANG_PROGRAM,[ +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'`; fi],[]) +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi +])# _LT_AC_SYS_LIBPATH_AIX + + +# _LT_AC_SHELL_INIT(ARG) +# ---------------------- +AC_DEFUN([_LT_AC_SHELL_INIT], +[ifdef([AC_DIVERSION_NOTICE], + [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)], + [AC_DIVERT_PUSH(NOTICE)]) +$1 +AC_DIVERT_POP +])# _LT_AC_SHELL_INIT + + +# _LT_AC_PROG_ECHO_BACKSLASH +# -------------------------- +# Add some code to the start of the generated configure script which +# will find an echo command which doesn't interpret backslashes. +AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH], +[_LT_AC_SHELL_INIT([ +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} + +case X$ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','` + ;; +esac + +echo=${ECHO-echo} +if test "X[$]1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X[$]1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t' ; then + # Yippee, $echo works! + : +else + # Restart under the correct shell. + exec $SHELL "[$]0" --no-reexec ${1+"[$]@"} +fi + +if test "X[$]1" = X--fallback-echo; then + # used as fallback echo + shift + cat </dev/null && + echo_test_string="`eval $cmd`" && + (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null + then + break + fi + done +fi + +if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : +else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for dir in $PATH /usr/ucb; do + IFS="$lt_save_ifs" + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$dir/echo" + break + fi + done + IFS="$lt_save_ifs" + + if test "X$echo" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + echo='print -r' + elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} + else + # Try using printf. + echo='printf %s\n' + if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + echo="$CONFIG_SHELL [$]0 --fallback-echo" + elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$CONFIG_SHELL [$]0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do + if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null + then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "[$]0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} + else + # Oops. We lost completely, so just stick with echo. + echo=echo + fi + fi + fi + fi +fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +ECHO=$echo +if test "X$ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then + ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo" +fi + +AC_SUBST(ECHO) +])])# _LT_AC_PROG_ECHO_BACKSLASH + + +# _LT_AC_LOCK +# ----------- +AC_DEFUN([_LT_AC_LOCK], +[AC_ARG_ENABLE([libtool-lock], + [AC_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '[#]line __oline__ "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case "`/usr/bin/file conftest.o`" in + *32-bit*) + LINUX_64_MODE="32" + case $host in + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + LINUX_64_MODE="64" + case $host in + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_LANG_PUSH(C) + AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) + AC_LANG_POP]) + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL], +[*-*-cygwin* | *-*-mingw* | *-*-pw32*) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + ;; + ]) +esac + +need_locks="$enable_libtool_lock" + +])# _LT_AC_LOCK + + +# AC_LIBTOOL_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------------------- +# Check whether the given compiler option works +AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], +[AC_REQUIRE([LT_AC_PROG_SED]) +AC_CACHE_CHECK([$1], [$2], + [$2=no + ifelse([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$3" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test ! -s conftest.err; then + $2=yes + fi + fi + $rm conftest* +]) + +if test x"[$]$2" = xyes; then + ifelse([$5], , :, [$5]) +else + ifelse([$6], , :, [$6]) +fi +])# AC_LIBTOOL_COMPILER_OPTION + + +# AC_LIBTOOL_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [ACTION-SUCCESS], [ACTION-FAILURE]) +# ------------------------------------------------------------ +# Check whether the given compiler option works +AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], +[AC_CACHE_CHECK([$1], [$2], + [$2=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $3" + printf "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&AS_MESSAGE_LOG_FD + else + $2=yes + fi + fi + $rm conftest* + LDFLAGS="$save_LDFLAGS" +]) + +if test x"[$]$2" = xyes; then + ifelse([$4], , :, [$4]) +else + ifelse([$5], , :, [$5]) +fi +])# AC_LIBTOOL_LINKER_OPTION + + +# AC_LIBTOOL_SYS_MAX_CMD_LEN +# -------------------------- +AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], +[# find the maximum length of command line arguments +AC_MSG_CHECKING([the maximum length of command line arguments]) +AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl + i=0 + testring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + *) + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while (test "X"`$CONFIG_SHELL [$]0 --fallback-echo "X$testring" 2>/dev/null` \ + = "XX$testring") >/dev/null 2>&1 && + new_result=`expr "X$testring" : ".*" 2>&1` && + lt_cv_sys_max_cmd_len=$new_result && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + testring=$testring$testring + done + testring= + # Add a significant safety factor because C++ compilers can tack on massive + # amounts of additional arguments before passing them to the linker. + # It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + ;; + esac +]) +if test -n $lt_cv_sys_max_cmd_len ; then + AC_MSG_RESULT($lt_cv_sys_max_cmd_len) +else + AC_MSG_RESULT(none) +fi +])# AC_LIBTOOL_SYS_MAX_CMD_LEN + + +# _LT_AC_CHECK_DLFCN +# -------------------- +AC_DEFUN([_LT_AC_CHECK_DLFCN], +[AC_CHECK_HEADERS(dlfcn.h)dnl +])# _LT_AC_CHECK_DLFCN + + +# _LT_AC_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, +# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) +# ------------------------------------------------------------------ +AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF], +[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl +if test "$cross_compiling" = yes; then : + [$4] +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext < +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" void exit (int); +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + + exit (status); +}] +EOF + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) $1 ;; + x$lt_dlneed_uscore) $2 ;; + x$lt_unknown|x*) $3 ;; + esac + else : + # compilation failed + $3 + fi +fi +rm -fr conftest* +])# _LT_AC_TRY_DLOPEN_SELF + + +# AC_LIBTOOL_DLOPEN_SELF +# ------------------- +AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], +[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ]) + ;; + + *) + AC_CHECK_FUNC([shl_load], + [lt_cv_dlopen="shl_load"], + [AC_CHECK_LIB([dld], [shl_load], + [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"], + [AC_CHECK_FUNC([dlopen], + [lt_cv_dlopen="dlopen"], + [AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], + [AC_CHECK_LIB([svld], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], + [AC_CHECK_LIB([dld], [dld_link], + [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"]) + ]) + ]) + ]) + ]) + ]) + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + AC_CACHE_CHECK([whether a program can dlopen itself], + lt_cv_dlopen_self, [dnl + _LT_AC_TRY_DLOPEN_SELF( + lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, + lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) + ]) + + if test "x$lt_cv_dlopen_self" = xyes; then + LDFLAGS="$LDFLAGS $link_static_flag" + AC_CACHE_CHECK([whether a statically linked program can dlopen itself], + lt_cv_dlopen_self_static, [dnl + _LT_AC_TRY_DLOPEN_SELF( + lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, + lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) + ]) + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi +])# AC_LIBTOOL_DLOPEN_SELF + + +# AC_LIBTOOL_PROG_CC_C_O([TAGNAME]) +# --------------------------------- +# Check to see if options -c and -o are simultaneously supported by compiler +AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O], +[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl +AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], + [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)], + [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no + $rm -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + # According to Tom Tromey, Ian Lance Taylor reported there are C compilers + # that will create temporary files in the current directory regardless of + # the output directory. Thus, making CWD read-only will cause this test + # to fail, enabling locking or at least warning the user not to do parallel + # builds. + chmod -w . + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test ! -s out/conftest.err; then + _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + fi + fi + chmod u+w . + $rm conftest* out/* + rmdir out + cd .. + rmdir conftest + $rm conftest* +]) +])# AC_LIBTOOL_PROG_CC_C_O + + +# AC_LIBTOOL_SYS_HARD_LINK_LOCKS([TAGNAME]) +# ----------------------------------------- +# Check to see if we can do hard links to lock some files if needed +AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], +[AC_REQUIRE([_LT_AC_LOCK])dnl + +hard_links="nottested" +if test "$_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + AC_MSG_CHECKING([if we can lock with hard links]) + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + AC_MSG_RESULT([$hard_links]) + if test "$hard_links" = no; then + AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) + need_locks=warn + fi +else + need_locks=no +fi +])# AC_LIBTOOL_SYS_HARD_LINK_LOCKS + + +# AC_LIBTOOL_OBJDIR +# ----------------- +AC_DEFUN([AC_LIBTOOL_OBJDIR], +[AC_CACHE_CHECK([for objdir], [lt_cv_objdir], +[rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null]) +objdir=$lt_cv_objdir +])# AC_LIBTOOL_OBJDIR + + +# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH([TAGNAME]) +# ---------------------------------------------- +# Check hardcoding attributes. +AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], +[AC_MSG_CHECKING([how to hardcode library paths into programs]) +_LT_AC_TAGVAR(hardcode_action, $1)= +if test -n "$_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)" || \ + test -n "$_LT_AC_TAGVAR(runpath_var $1)" || \ + test "X$_LT_AC_TAGVAR(hardcode_automatic, $1)"="Xyes" ; then + + # We can hardcode non-existant directories. + if test "$_LT_AC_TAGVAR(hardcode_direct, $1)" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)" != no && + test "$_LT_AC_TAGVAR(hardcode_minus_L, $1)" != no; then + # Linking always hardcodes the temporary library directory. + _LT_AC_TAGVAR(hardcode_action, $1)=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + _LT_AC_TAGVAR(hardcode_action, $1)=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + _LT_AC_TAGVAR(hardcode_action, $1)=unsupported +fi +AC_MSG_RESULT([$_LT_AC_TAGVAR(hardcode_action, $1)]) + +if test "$_LT_AC_TAGVAR(hardcode_action, $1)" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi +])# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH + + +# AC_LIBTOOL_SYS_LIB_STRIP +# ------------------------ +AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP], +[striplib= +old_striplib= +AC_MSG_CHECKING([whether stripping libraries is possible]) +if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) +fi + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac +fi +])# AC_LIBTOOL_SYS_LIB_STRIP + + +# AC_LIBTOOL_SYS_DYNAMIC_LINKER +# ----------------------------- +# PORTME Fill in your ld.so characteristics +AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER], +[AC_MSG_CHECKING([dynamic linker characteristics]) +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix4* | aix5*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[[01]] | aix4.[[01]].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "(cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a)"; (cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a) || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi4*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32*) + version_type=windows + shrext=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $rm \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | [grep ';[c-zC-Z]:/' >/dev/null]; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext='$(test .$module = .yes && echo .so || echo .dylib)' + # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same. + if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"` + else + sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib' + fi + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +kfreebsd*-gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='GNU ld.so' + ;; + +freebsd*) + objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout` + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + *) # from 3.2 on + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case "$host_cpu" in + ia64*) + shrext='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + libsuff= + if test "x$LINUX_64_MODE" = x64; then + # Some platforms are per default 64-bit, so there's no /lib64 + if test -d /lib64; then + libsuff=64 + fi + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + sys_lib_dlsearch_path_spec="/lib${libsuff} /usr/lib${libsuff}" + sys_lib_search_path_spec="/lib${libsuff} /usr/lib${libsuff} /usr/local/lib${libsuff}" + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +nto-qnx*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +openbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[[89]] | openbsd2.[[89]].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +sco3.2v5*) + version_type=osf + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + export_dynamic_flag_spec='${wl}-Blargedynsym' + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +AC_MSG_RESULT([$dynamic_linker]) +test "$dynamic_linker" = no && can_build_shared=no +])# AC_LIBTOOL_SYS_DYNAMIC_LINKER + + +# _LT_AC_TAGCONFIG +# ---------------- +AC_DEFUN([_LT_AC_TAGCONFIG], +[AC_ARG_WITH([tags], + [AC_HELP_STRING([--with-tags@<:@=TAGS@:>@], + [include additional configurations @<:@automatic@:>@])], + [tagnames="$withval"]) + +if test -f "$ltmain" && test -n "$tagnames"; then + if test ! -f "${ofile}"; then + AC_MSG_WARN([output file `$ofile' does not exist]) + fi + + if test -z "$LTCC"; then + eval "`$SHELL ${ofile} --config | grep '^LTCC='`" + if test -z "$LTCC"; then + AC_MSG_WARN([output file `$ofile' does not look like a libtool script]) + else + AC_MSG_WARN([using `LTCC=$LTCC', extracted from `$ofile']) + fi + fi + + # Extract list of available tagged configurations in $ofile. + # Note that this assumes the entire list is on one line. + available_tags=`grep "^available_tags=" "${ofile}" | $SED -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'` + + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for tagname in $tagnames; do + IFS="$lt_save_ifs" + # Check whether tagname contains only valid characters + case `$echo "X$tagname" | $Xsed -e 's:[[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]]::g'` in + "") ;; + *) AC_MSG_ERROR([invalid tag name: $tagname]) + ;; + esac + + if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null + then + AC_MSG_ERROR([tag name \"$tagname\" already exists]) + fi + + # Update the list of available tags. + if test -n "$tagname"; then + echo appending configuration tag \"$tagname\" to $ofile + + case $tagname in + CXX) + if test -n "$CXX" && test "X$CXX" != "Xno"; then + AC_LIBTOOL_LANG_CXX_CONFIG + else + tagname="" + fi + ;; + + F77) + if test -n "$F77" && test "X$F77" != "Xno"; then + AC_LIBTOOL_LANG_F77_CONFIG + else + tagname="" + fi + ;; + + GCJ) + if test -n "$GCJ" && test "X$GCJ" != "Xno"; then + AC_LIBTOOL_LANG_GCJ_CONFIG + else + tagname="" + fi + ;; + + RC) + AC_LIBTOOL_LANG_RC_CONFIG + ;; + + *) + AC_MSG_ERROR([Unsupported tag name: $tagname]) + ;; + esac + + # Append the new tag name to the list of available tags. + if test -n "$tagname" ; then + available_tags="$available_tags $tagname" + fi + fi + done + IFS="$lt_save_ifs" + + # Now substitute the updated list of available tags. + if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then + mv "${ofile}T" "$ofile" + chmod +x "$ofile" + else + rm -f "${ofile}T" + AC_MSG_ERROR([unable to update list of available tagged configurations.]) + fi +fi +])# _LT_AC_TAGCONFIG + + +# AC_LIBTOOL_DLOPEN +# ----------------- +# enable checks for dlopen support +AC_DEFUN([AC_LIBTOOL_DLOPEN], + [AC_BEFORE([$0],[AC_LIBTOOL_SETUP]) +])# AC_LIBTOOL_DLOPEN + + +# AC_LIBTOOL_WIN32_DLL +# -------------------- +# declare package support for building win32 dll's +AC_DEFUN([AC_LIBTOOL_WIN32_DLL], +[AC_BEFORE([$0], [AC_LIBTOOL_SETUP]) +])# AC_LIBTOOL_WIN32_DLL + + +# AC_ENABLE_SHARED([DEFAULT]) +# --------------------------- +# implement the --enable-shared flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_SHARED], +[define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([shared], + [AC_HELP_STRING([--enable-shared@<:@=PKGS@:>@], + [build shared libraries @<:@default=]AC_ENABLE_SHARED_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_shared=]AC_ENABLE_SHARED_DEFAULT) +])# AC_ENABLE_SHARED + + +# AC_DISABLE_SHARED +# ----------------- +#- set the default shared flag to --disable-shared +AC_DEFUN([AC_DISABLE_SHARED], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_SHARED(no) +])# AC_DISABLE_SHARED + + +# AC_ENABLE_STATIC([DEFAULT]) +# --------------------------- +# implement the --enable-static flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_STATIC], +[define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([static], + [AC_HELP_STRING([--enable-static@<:@=PKGS@:>@], + [build static libraries @<:@default=]AC_ENABLE_STATIC_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_static=]AC_ENABLE_STATIC_DEFAULT) +])# AC_ENABLE_STATIC + + +# AC_DISABLE_STATIC +# ----------------- +# set the default static flag to --disable-static +AC_DEFUN([AC_DISABLE_STATIC], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_STATIC(no) +])# AC_DISABLE_STATIC + + +# AC_ENABLE_FAST_INSTALL([DEFAULT]) +# --------------------------------- +# implement the --enable-fast-install flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_FAST_INSTALL], +[define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([fast-install], + [AC_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], + [optimize for fast installation @<:@default=]AC_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_fast_install=]AC_ENABLE_FAST_INSTALL_DEFAULT) +])# AC_ENABLE_FAST_INSTALL + + +# AC_DISABLE_FAST_INSTALL +# ----------------------- +# set the default to --disable-fast-install +AC_DEFUN([AC_DISABLE_FAST_INSTALL], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_FAST_INSTALL(no) +])# AC_DISABLE_FAST_INSTALL + + +# AC_LIBTOOL_PICMODE([MODE]) +# -------------------------- +# implement the --with-pic flag +# MODE is either `yes' or `no'. If omitted, it defaults to `both'. +AC_DEFUN([AC_LIBTOOL_PICMODE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +pic_mode=ifelse($#,1,$1,default) +])# AC_LIBTOOL_PICMODE + + +# AC_PROG_EGREP +# ------------- +# This is predefined starting with Autoconf 2.54, so this conditional +# definition can be removed once we require Autoconf 2.54 or later. +m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP], +[AC_CACHE_CHECK([for egrep], [ac_cv_prog_egrep], + [if echo a | (grep -E '(a|b)') >/dev/null 2>&1 + then ac_cv_prog_egrep='grep -E' + else ac_cv_prog_egrep='egrep' + fi]) + EGREP=$ac_cv_prog_egrep + AC_SUBST([EGREP]) +])]) + + +# AC_PATH_TOOL_PREFIX +# ------------------- +# find a file program which can recognise shared library +AC_DEFUN([AC_PATH_TOOL_PREFIX], +[AC_REQUIRE([AC_PROG_EGREP])dnl +AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, +[case $MAGIC_CMD in +[[\\/*] | ?:[\\/]*]) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="ifelse([$2], , $PATH, [$2])" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$1; then + lt_cv_path_MAGIC_CMD="$ac_dir/$1" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`" + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac]) +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + AC_MSG_RESULT($MAGIC_CMD) +else + AC_MSG_RESULT(no) +fi +])# AC_PATH_TOOL_PREFIX + + +# AC_PATH_MAGIC +# ------------- +# find a file program which can recognise a shared library +AC_DEFUN([AC_PATH_MAGIC], +[AC_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + AC_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) + else + MAGIC_CMD=: + fi +fi +])# AC_PATH_MAGIC + + +# AC_PROG_LD +# ---------- +# find the pathname to the GNU or non-GNU linker +AC_DEFUN([AC_PROG_LD], +[AC_ARG_WITH([gnu-ld], + [AC_HELP_STRING([--with-gnu-ld], + [assume the C compiler uses GNU ld @<:@default=no@:>@])], + [test "$withval" = no || with_gnu_ld=yes], + [with_gnu_ld=no]) +AC_REQUIRE([LT_AC_PROG_SED])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by $CC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]]* | ?:[[\\/]]*) + re_direlt='/[[^/]][[^/]]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(lt_cv_path_LD, +[if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD)/i[[3-9]]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case "$host_cpu" in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'] + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + irix5* | nonstopux*) + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method="file_magic ELF 32-bit MSB dynamic lib MIPS - version 1" + ;; + *) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method="file_magic ELF ${libmagic} MSB mips-[[1234]] dynamic lib MIPS - version 1" + ;; + esac + lt_cv_file_magic_test_file=`echo /lib${libsuff}/libc.so*` + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux*) + case $host_cpu in + alpha* | hppa* | i*86 | ia64* | m68* | mips* | powerpc* | sparc* | s390* | sh* | x86_64* ) + lt_cv_deplibs_check_method=pass_all ;; + # the debian people say, arm and glibc 2.3.1 works for them with pass_all + arm* ) + lt_cv_deplibs_check_method=pass_all ;; + *) + # glibc up to 2.1.1 does not perform some relocations on ARM + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' ;; + esac + lt_cv_file_magic_test_file=`echo /lib/libc.so* /lib/libc-*.so` + ;; + +netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +nto-qnx*) + lt_cv_deplibs_check_method=unknown + ;; + +openbsd*) + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB shared object' + else + lt_cv_deplibs_check_method='file_magic OpenBSD.* shared library' + fi + ;; + +osf3* | osf4* | osf5*) + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method='file_magic COFF format alpha shared library' + lt_cv_file_magic_test_file=/shlib/libc.so + lt_cv_deplibs_check_method=pass_all + ;; + +sco3.2v5*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + lt_cv_file_magic_test_file=/lib/libc.so + ;; + +sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; +esac +]) +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown +])# AC_DEPLIBS_CHECK_METHOD + + +# AC_PROG_NM +# ---------- +# find the pathname to a BSD-compatible name lister +AC_DEFUN([AC_PROG_NM], +[AC_CACHE_CHECK([for BSD-compatible nm], lt_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/${ac_tool_prefix}nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + esac + fi + done + IFS="$lt_save_ifs" + test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm +fi]) +NM="$lt_cv_path_NM" +])# AC_PROG_NM + + +# AC_CHECK_LIBM +# ------------- +# check for math library +AC_DEFUN([AC_CHECK_LIBM], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*) + # These system don't have libm, or don't need it + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") + AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, cos, LIBM="-lm") + ;; +esac +])# AC_CHECK_LIBM + + +# AC_LIBLTDL_CONVENIENCE([DIRECTORY]) +# ----------------------------------- +# sets LIBLTDL to the link flags for the libltdl convenience library and +# LTDLINCL to the include flags for the libltdl header and adds +# --enable-ltdl-convenience to the configure arguments. Note that LIBLTDL +# and LTDLINCL are not AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called. If +# DIRECTORY is not provided, it is assumed to be `libltdl'. LIBLTDL will +# be prefixed with '${top_builddir}/' and LTDLINCL will be prefixed with +# '${top_srcdir}/' (note the single quotes!). If your package is not +# flat and you're not using automake, define top_builddir and +# top_srcdir appropriately in the Makefiles. +AC_DEFUN([AC_LIBLTDL_CONVENIENCE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + case $enable_ltdl_convenience in + no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;; + "") enable_ltdl_convenience=yes + ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;; + esac + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la + LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + # For backwards non-gettext consistent compatibility... + INCLTDL="$LTDLINCL" +])# AC_LIBLTDL_CONVENIENCE + + +# AC_LIBLTDL_INSTALLABLE([DIRECTORY]) +# ----------------------------------- +# sets LIBLTDL to the link flags for the libltdl installable library and +# LTDLINCL to the include flags for the libltdl header and adds +# --enable-ltdl-install to the configure arguments. Note that LIBLTDL +# and LTDLINCL are not AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called. If +# DIRECTORY is not provided and an installed libltdl is not found, it is +# assumed to be `libltdl'. LIBLTDL will be prefixed with '${top_builddir}/' +# and LTDLINCL will be prefixed with '${top_srcdir}/' (note the single +# quotes!). If your package is not flat and you're not using automake, +# define top_builddir and top_srcdir appropriately in the Makefiles. +# In the future, this macro may have to be called after AC_PROG_LIBTOOL. +AC_DEFUN([AC_LIBLTDL_INSTALLABLE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + AC_CHECK_LIB(ltdl, lt_dlinit, + [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no], + [if test x"$enable_ltdl_install" = xno; then + AC_MSG_WARN([libltdl not installed, but installation disabled]) + else + enable_ltdl_install=yes + fi + ]) + if test x"$enable_ltdl_install" = x"yes"; then + ac_configure_args="$ac_configure_args --enable-ltdl-install" + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la + LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + else + ac_configure_args="$ac_configure_args --enable-ltdl-install=no" + LIBLTDL="-lltdl" + LTDLINCL= + fi + # For backwards non-gettext consistent compatibility... + INCLTDL="$LTDLINCL" +])# AC_LIBLTDL_INSTALLABLE + + +# AC_LIBTOOL_CXX +# -------------- +# enable support for C++ libraries +AC_DEFUN([AC_LIBTOOL_CXX], +[AC_REQUIRE([_LT_AC_LANG_CXX]) +])# AC_LIBTOOL_CXX + + +# _LT_AC_LANG_CXX +# --------------- +AC_DEFUN([_LT_AC_LANG_CXX], +[AC_REQUIRE([AC_PROG_CXX]) +AC_REQUIRE([AC_PROG_CXXCPP]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}CXX]) +])# _LT_AC_LANG_CXX + + +# AC_LIBTOOL_F77 +# -------------- +# enable support for Fortran 77 libraries +AC_DEFUN([AC_LIBTOOL_F77], +[AC_REQUIRE([_LT_AC_LANG_F77]) +])# AC_LIBTOOL_F77 + + +# _LT_AC_LANG_F77 +# --------------- +AC_DEFUN([_LT_AC_LANG_F77], +[AC_REQUIRE([AC_PROG_F77]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}F77]) +])# _LT_AC_LANG_F77 + + +# AC_LIBTOOL_GCJ +# -------------- +# enable support for GCJ libraries +AC_DEFUN([AC_LIBTOOL_GCJ], +[AC_REQUIRE([_LT_AC_LANG_GCJ]) +])# AC_LIBTOOL_GCJ + + +# _LT_AC_LANG_GCJ +# --------------- +AC_DEFUN([_LT_AC_LANG_GCJ], +[AC_PROVIDE_IFELSE([AC_PROG_GCJ],[], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],[], + [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],[], + [ifdef([AC_PROG_GCJ],[AC_REQUIRE([AC_PROG_GCJ])], + [ifdef([A][M_PROG_GCJ],[AC_REQUIRE([A][M_PROG_GCJ])], + [AC_REQUIRE([A][C_PROG_GCJ_OR_A][M_PROG_GCJ])])])])])]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}GCJ]) +])# _LT_AC_LANG_GCJ + + +# AC_LIBTOOL_RC +# -------------- +# enable support for Windows resource files +AC_DEFUN([AC_LIBTOOL_RC], +[AC_REQUIRE([LT_AC_PROG_RC]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}RC]) +])# AC_LIBTOOL_RC + + +# AC_LIBTOOL_LANG_C_CONFIG +# ------------------------ +# Ensure that the configuration vars for the C compiler are +# suitably defined. Those variables are subsequently used by +# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. +AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG], [_LT_AC_LANG_C_CONFIG]) +AC_DEFUN([_LT_AC_LANG_C_CONFIG], +[lt_save_CC="$CC" +AC_LANG_PUSH(C) + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +_LT_AC_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;\n" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}\n' + +_LT_AC_SYS_COMPILER + +# +# Check for any special shared library compilation flags. +# +_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)= +if test "$GCC" = no; then + case $host_os in + sco3.2v5*) + _LT_AC_TAGVAR(lt_prog_cc_shlib, $1)='-belf' + ;; + esac +fi +if test -n "$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)"; then + AC_MSG_WARN([`$CC' requires `$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)' to build shared libraries]) + if echo "$old_CC $old_CFLAGS " | grep "[[ ]]$]_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)[[[ ]]" >/dev/null; then : + else + AC_MSG_WARN([add `$_LT_AC_TAGVAR(lt_prog_cc_shlib, $1)' to the CC or CFLAGS env variable and reconfigure]) + _LT_AC_TAGVAR(lt_cv_prog_cc_can_build_shared, $1)=no + fi +fi + + +# +# Check to make sure the static flag actually works. +# +AC_LIBTOOL_LINKER_OPTION([if $compiler static flag $_LT_AC_TAGVAR(lt_prog_compiler_static, $1) works], + _LT_AC_TAGVAR(lt_prog_compiler_static_works, $1), + $_LT_AC_TAGVAR(lt_prog_compiler_static, $1), + [], + [_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=]) + + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1) +AC_LIBTOOL_PROG_COMPILER_PIC($1) +AC_LIBTOOL_PROG_CC_C_O($1) +AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) +AC_LIBTOOL_PROG_LD_SHLIBS($1) +AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) +AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) +AC_LIBTOOL_SYS_LIB_STRIP +AC_LIBTOOL_DLOPEN_SELF($1) + +# Report which librarie types wil actually be built +AC_MSG_CHECKING([if libtool supports shared libraries]) +AC_MSG_RESULT([$can_build_shared]) + +AC_MSG_CHECKING([whether to build shared libraries]) +test "$can_build_shared" = "no" && enable_shared=no + +# On AIX, shared libraries and static libraries use the same namespace, and +# are all built from PIC. +case "$host_os" in +aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + +aix4*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + darwin* | rhapsody*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + case "$host_os" in + rhapsody* | darwin1.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-Wl,-undefined -Wl,suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-Wl,-flat_namespace -Wl,-undefined -Wl,suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[012]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-Wl,-flat_namespace -Wl,-undefined -Wl,suppress' + ;; + 10.*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-Wl,-undefined -Wl,dynamic_lookup' + ;; + esac + fi + ;; + esac + output_verbose_link_cmd='echo' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib $allow_undefined_flag -o $lib $compiler_flags $libobjs $deplibs -install_name $rpath/$soname $verstring' + _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $compiler_flags $libobjs $deplibs' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $compiler_flags $libobjs $deplibs -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $compiler_flags $libobjs $deplibs~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_automatic, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-all_load $convenience' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; +esac +AC_MSG_RESULT([$enable_shared]) + +AC_MSG_CHECKING([whether to build static libraries]) +# Make sure either enable_shared or enable_static is yes. +test "$enable_shared" = yes || enable_static=yes +AC_MSG_RESULT([$enable_static]) + +AC_LIBTOOL_CONFIG($1) + +AC_LANG_POP +CC="$lt_save_CC" +])# AC_LIBTOOL_LANG_C_CONFIG + + +# AC_LIBTOOL_LANG_CXX_CONFIG +# -------------------------- +# Ensure that the configuration vars for the C compiler are +# suitably defined. Those variables are subsequently used by +# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. +AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG], [_LT_AC_LANG_CXX_CONFIG(CXX)]) +AC_DEFUN([_LT_AC_LANG_CXX_CONFIG], +[AC_LANG_PUSH(C++) +AC_REQUIRE([AC_PROG_CXX]) +AC_REQUIRE([AC_PROG_CXXCPP]) + +_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_AC_TAGVAR(allow_undefined_flag, $1)= +_LT_AC_TAGVAR(always_export_symbols, $1)=no +_LT_AC_TAGVAR(archive_expsym_cmds, $1)= +_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_AC_TAGVAR(hardcode_direct, $1)=no +_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_AC_TAGVAR(hardcode_libdir_separator, $1)= +_LT_AC_TAGVAR(hardcode_minus_L, $1)=no +_LT_AC_TAGVAR(hardcode_automatic, $1)=no +_LT_AC_TAGVAR(module_cmds, $1)= +_LT_AC_TAGVAR(module_expsym_cmds, $1)= +_LT_AC_TAGVAR(link_all_deplibs, $1)=unknown +_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_AC_TAGVAR(no_undefined_flag, $1)= +_LT_AC_TAGVAR(whole_archive_flag_spec, $1)= +_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Dependencies to place before and after the object being linked: +_LT_AC_TAGVAR(predep_objects, $1)= +_LT_AC_TAGVAR(postdep_objects, $1)= +_LT_AC_TAGVAR(predeps, $1)= +_LT_AC_TAGVAR(postdeps, $1)= +_LT_AC_TAGVAR(compiler_lib_search_path, $1)= + +# Source file extension for C++ test sources. +ac_ext=cc + +# Object file extension for compiled C++ test sources. +objext=o +_LT_AC_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;\n" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(int, char *[]) { return(0); }\n' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_AC_SYS_COMPILER + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_LD=$LD +lt_save_GCC=$GCC +GCC=$GXX +lt_save_with_gnu_ld=$with_gnu_ld +lt_save_path_LD=$lt_cv_path_LD +if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx +else + unset lt_cv_prog_gnu_ld +fi +if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX +else + unset lt_cv_path_LD +fi +test -z "${LDCXX+set}" || LD=$LDCXX +CC=${CXX-"c++"} +compiler=$CC +_LT_AC_TAGVAR(compiler, $1)=$CC +cc_basename=`$echo X"$compiler" | $Xsed -e 's%^.*/%%'` + +# We don't want -fno-exception wen compiling C++ code, so set the +# no_builtin_flag separately +if test "$GXX" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' +else + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= +fi + +if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + AC_PROG_LD + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | \ + grep 'no-whole-archive' > /dev/null; then + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + +else + GXX=no + with_gnu_ld=no + wlarc= +fi + +# PORTME: fill in a description of your system's C++ link characteristics +AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +_LT_AC_TAGVAR(ld_shlibs, $1)=yes +case $host_os in + aix3*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # KDE requires run time linking. Make it the default. + aix_use_runtimelinking=yes + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_AC_TAGVAR(archive_cmds, $1)='' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + if test "$GXX" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + else + # We have old collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + fi + esac + shared_flag='-shared' + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='-qmkshrobj ${wl}-G' + else + shared_flag='-qmkshrobj' + fi + fi + fi + + # Let the compiler handle the export list. + _LT_AC_TAGVAR(always_export_symbols, $1)=no + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + + _LT_AC_TAGVAR(archive_cmds, $1)="\$CC"' -o $output_objdir/$soname $compiler_flags $libobjs $deplibs `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '" $shared_flag" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $compiler_flags $libobjs $deplibs `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $compiler_flags $libobjs $deplibs ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # -bexpall does not export symbols beginning with underscore (_) + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + # Exported symbols can be pulled into shared objects from archives + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=' ' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds it's shared libraries. + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $compiler_flags $libobjs $deplibs ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=no + _LT_AC_TAGVAR(always_export_symbols, $1)=no + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + darwin* | rhapsody*) + if test "$GXX" = yes; then + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + case "$host_os" in + rhapsody* | darwin1.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-Wl,-undefined -Wl,suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-Wl,-flat_namespace -Wl,-undefined -Wl,suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[012]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-Wl,-flat_namespace -Wl,-undefined -Wl,suppress' + ;; + 10.*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-Wl,-undefined -Wl,dynamic_lookup' + ;; + esac + fi + ;; + esac + lt_int_apple_cc_single_mod=no + output_verbose_link_cmd='echo' + if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then + lt_int_apple_cc_single_mod=yes + fi + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $compiler_flags $libobjs $deplibs -install_name $rpath/$soname $verstring' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $compiler_flags $deplibs -install_name $rpath/$soname $verstring' + fi + _LT_AC_TAGVAR(module_cmds, $1)='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $compiler_flags $libobjs $deplibs' + + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $compiler_flags $libobjs $deplibs -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $compiler_flags $deplibs -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $compiler_flags $libobjs $deplibs~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_automatic, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-all_load $convenience' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + dgux*) + case $cc_basename in + ec++) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + ghcx) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + freebsd[12]*) + # C++ shared libraries reported to be fairly broken before switch to ELF + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + freebsd-elf*) + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + freebsd* | kfreebsd*-gnu) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + ;; + gnu*) + ;; + hpux9*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aCC) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | egrep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + case "$host_cpu" in + hppa*64*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + ia64*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + ;; + *) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + esac + fi + case "$host_cpu" in + hppa*64*) + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + ia64*) + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + *) + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aCC) + case "$host_cpu" in + hppa*64*|ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case "$host_cpu" in + ia64*|hppa*64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $linker_flags $libobjs $deplibs' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + irix5* | irix6*) + case $cc_basename in + CC) + # SGI C++ + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib' + fi + fi + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + esac + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + linux*) + case $cc_basename in + KCC) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects --soname $soname -o \$templib; mv \$templib $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | grep "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc) + # Intel C++ + with_gnu_ld=yes + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + cxx) + # Compaq C++ + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + esac + ;; + lynxos*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + m88k*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + mvs*) + case $cc_basename in + cxx) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + osf3*) + case $cc_basename in + KCC) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects --soname $soname -o \$templib; mv \$templib $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + + ;; + RCC) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + cxx) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + osf4* | osf5*) + case $cc_basename in + KCC) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects --soname $soname -o \$templib; mv \$templib $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' + ;; + RCC) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + cxx) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects -msym -soname $soname -Wl,-input -Wl,$lib.exp `test -n "$verstring" && echo -set_version $verstring` -update_registry $objdir/so_locations -o $lib~ + $rm $lib.exp' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + psos*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + sco*) + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + case $cc_basename in + CC) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + lcc) + # Lucid + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + solaris*) + case $cc_basename in + CC) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_AC_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -nolib -h$soname -o $lib $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} -nolib ${wl}-M ${wl}$lib.exp -h$soname -o $lib $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects~$rm $lib.exp' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The C++ compiler is used as linker so we must use $wl + # flag to pass the commands to the underlying system + # linker. + # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + ;; + esac + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep "\-[[LR]]"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + gcx) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' + if $CC --version | grep -v '^2\.7' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects ${wl}-h $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects~$rm $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects ${wl}-h $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $compiler_flags $predep_objects $libobjs $deplibs $postdep_objects~$rm $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" + fi + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' + fi + ;; + esac + ;; + sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7*) + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + tandem*) + case $cc_basename in + NCC) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + vxworks*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; +esac +AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)]) +test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +_LT_AC_TAGVAR(GCC, $1)="$GXX" +_LT_AC_TAGVAR(LD, $1)="$LD" + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +AC_LIBTOOL_POSTDEP_PREDEP($1) +AC_LIBTOOL_PROG_COMPILER_PIC($1) +AC_LIBTOOL_PROG_CC_C_O($1) +AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) +AC_LIBTOOL_PROG_LD_SHLIBS($1) +AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) +AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) +AC_LIBTOOL_SYS_LIB_STRIP +AC_LIBTOOL_DLOPEN_SELF($1) + +AC_LIBTOOL_CONFIG($1) + +AC_LANG_POP +CC=$lt_save_CC +LDCXX=$LD +LD=$lt_save_LD +GCC=$lt_save_GCC +with_gnu_ldcxx=$with_gnu_ld +with_gnu_ld=$lt_save_with_gnu_ld +lt_cv_path_LDCXX=$lt_cv_path_LD +lt_cv_path_LD=$lt_save_path_LD +lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld +lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +])# AC_LIBTOOL_LANG_CXX_CONFIG + +# AC_LIBTOOL_POSTDEP_PREDEP([TAGNAME]) +# ------------------------ +# Figure out "hidden" library dependencies from verbose +# compiler output when linking a shared library. +# Parse the compiler output and extract the necessary +# objects, libraries and library flags. +AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP],[ +dnl we can't use the lt_simple_compile_test_code here, +dnl because it contains code intended for an executable, +dnl not a library. It's possible we should let each +dnl tag define a new lt_????_link_test_code variable, +dnl but it's only used here... +ifelse([$1],[],[cat > conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext <> "$cfgfile" +ifelse([$1], [], +[#! $SHELL + +# `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 +# Free Software Foundation, Inc. +# +# This file is part of GNU Libtool: +# Originally by Gordon Matzigkeit , 1996 +# +# 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 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# A sed program that does not truncate output. +SED=$lt_SED + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="$SED -e s/^X//" + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +if test "X\${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi + +# The names of the tagged configurations supported by this script. +available_tags= + +# ### BEGIN LIBTOOL CONFIG], +[# ### BEGIN LIBTOOL TAG CONFIG: $tagname]) + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$_LT_AC_TAGVAR(archive_cmds_need_lc, $1) + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=$_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1) + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A C compiler. +LTCC=$lt_LTCC + +# A language-specific compiler. +CC=$lt_[]_LT_AC_TAGVAR(compiler, $1) + +# Is the compiler the GNU C compiler? +with_gcc=$_LT_AC_TAGVAR(GCC, $1) + +# An ERE matcher. +EGREP=$lt_EGREP + +# The linker used to build libraries. +LD=$lt_[]_LT_AC_TAGVAR(LD, $1) + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally ".so"). +shrext='$shrext' + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) +pic_mode=$pic_mode + +# What is the maximum length of a command? +max_cmd_len=$lt_cv_sys_max_cmd_len + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_[]_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1) + +# Must we lock files when doing compilation ? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_static, $1) + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_[]_LT_AC_TAGVAR(export_dynamic_flag_spec, $1) + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_[]_LT_AC_TAGVAR(whole_archive_flag_spec, $1) + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_[]_LT_AC_TAGVAR(thread_safe_flag_spec, $1) + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_cmds, $1) +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_new_cmds, $1) + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) + +# Commands used to build and install a shared archive. +archive_cmds=$lt_[]_LT_AC_TAGVAR(archive_cmds, $1) +archive_expsym_cmds=$lt_[]_LT_AC_TAGVAR(archive_expsym_cmds, $1) +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds=$lt_[]_LT_AC_TAGVAR(module_cmds, $1) +module_expsym_cmds=$lt_[]_LT_AC_TAGVAR(module_expsym_cmds, $1) + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects=$lt_[]_LT_AC_TAGVAR(predep_objects, $1) + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects=$lt_[]_LT_AC_TAGVAR(postdep_objects, $1) + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps=$lt_[]_LT_AC_TAGVAR(predeps, $1) + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps=$lt_[]_LT_AC_TAGVAR(postdeps, $1) + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_[]_LT_AC_TAGVAR(compiler_lib_search_path, $1) + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_[]_LT_AC_TAGVAR(allow_undefined_flag, $1) + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_[]_LT_AC_TAGVAR(no_undefined_flag, $1) + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$_LT_AC_TAGVAR(hardcode_action, $1) + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) + +# If ld is used when linking, flag to hardcode \$libdir into +# a binary during linking. This must work even if \$libdir does +# not exist. +hardcode_libdir_flag_spec_ld=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1) + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_separator, $1) + +# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$_LT_AC_TAGVAR(hardcode_direct, $1) + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$_LT_AC_TAGVAR(hardcode_minus_L, $1) + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1) + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=$_LT_AC_TAGVAR(hardcode_automatic, $1) + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$_LT_AC_TAGVAR(link_all_deplibs, $1) + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path="$_LT_AC_TAGVAR(fix_srcfile_path, $1)" + +# Set to yes if exported symbols are required. +always_export_symbols=$_LT_AC_TAGVAR(always_export_symbols, $1) + +# The commands to list exported symbols. +export_symbols_cmds=$lt_[]_LT_AC_TAGVAR(export_symbols_cmds, $1) + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_[]_LT_AC_TAGVAR(exclude_expsyms, $1) + +# Symbols that must always be exported. +include_expsyms=$lt_[]_LT_AC_TAGVAR(include_expsyms, $1) + +ifelse([$1],[], +[# ### END LIBTOOL CONFIG], +[# ### END LIBTOOL TAG CONFIG: $tagname]) + +__EOF__ + +ifelse([$1],[], [ + case $host_os in + aix3*) + cat <<\EOF >> "$cfgfile" + +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +EOF + ;; + esac + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || \ + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" +]) +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + test -f Makefile && make "$ltmain" +fi +])# AC_LIBTOOL_CONFIG + + +# AC_LIBTOOL_PROG_COMPILER_NO_RTTI([TAGNAME]) +# ------------------------------------------- +AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], +[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl + +_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + +if test "$GCC" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + + AC_LIBTOOL_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], + lt_cv_prog_compiler_rtti_exceptions, + [-fno-rtti -fno-exceptions], [], + [_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) +fi +])# AC_LIBTOOL_PROG_COMPILER_NO_RTTI + + +# AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE +# --------------------------------- +AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], +[AC_REQUIRE([AC_CANONICAL_HOST]) +AC_REQUIRE([AC_PROG_NM]) +AC_REQUIRE([AC_OBJEXT]) +# Check for command to grab the raw symbol name followed by C symbol from nm. +AC_MSG_CHECKING([command to parse $NM output from $compiler object]) +AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], +[ +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[[BCDEGRST]]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' + +# Transform the above into a raw symbol and a C symbol. +symxfrm='\1 \2\3 \3' + +# Transform an extracted symbol line into a proper C declaration +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[[BCDT]]' + ;; +cygwin* | mingw* | pw32*) + symcode='[[ABCDGISTW]]' + ;; +hpux*) # Its linker distinguishes data from code symbols + if test "$host_cpu" = ia64; then + symcode='[[ABCDEGRST]]' + fi + lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + ;; +irix* | nonstopux*) + symcode='[[BCDEGRST]]' + ;; +osf*) + symcode='[[BCDEGQRST]]' + ;; +solaris* | sysv5*) + symcode='[[BDT]]' + ;; +sysv4) + symcode='[[DFNSTU]]' + ;; +esac + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[[ABCDGISTW]]' ;; +esac + +# Try without a prefix undercore, then with it. +for ac_symprfx in "" "_"; do + + # Write the raw and C identifiers. + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*\($ac_symprfx\)$sympat$opt_cr$/$symxfrm/p'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext < $nlist) && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if grep ' nm_test_var$' "$nlist" >/dev/null; then + if grep ' nm_test_func$' "$nlist" >/dev/null; then + cat < conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext' + + cat <> conftest.$ac_ext +#if defined (__STDC__) && __STDC__ +# define lt_ptr_t void * +#else +# define lt_ptr_t char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + lt_ptr_t address; +} +lt_preloaded_symbols[[]] = +{ +EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext + cat <<\EOF >> conftest.$ac_ext + {0, (lt_ptr_t) 0} +}; + +#ifdef __cplusplus +} +#endif +EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_save_LIBS="$LIBS" + lt_save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS="$lt_save_LIBS" + CFLAGS="$lt_save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD + fi + else + echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD + cat conftest.$ac_ext >&5 + fi + rm -f conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done +]) +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + AC_MSG_RESULT(failed) +else + AC_MSG_RESULT(ok) +fi +]) # AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE + + +# AC_LIBTOOL_PROG_COMPILER_PIC([TAGNAME]) +# --------------------------------------- +AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC], +[_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)= +_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= +_LT_AC_TAGVAR(lt_prog_compiler_static, $1)= + +AC_MSG_CHECKING([for $compiler option to produce PIC]) + ifelse([$1],[CXX],[ + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | os2* | pw32*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case "$host_cpu" in + hppa*64*|ia64*) + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + case $host_os in + aix4* | aix5*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68) + # Green Hills C++ Compiler + # _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + dgux*) + case $cc_basename in + ec++) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + ghcx) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | kfreebsd*-gnu) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive" + if test "$host_cpu" != ia64; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + fi + ;; + aCC) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="${ac_cv_prog_cc_wl}-a ${ac_cv_prog_cc_wl}archive" + case "$host_cpu" in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux*) + case $cc_basename in + KCC) + # KAI C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + icpc) + # Intel C++ + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + cxx) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd*) + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + ;; + RCC) + # Rational C++ 2.4.1 + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + cxx) + # Digital/Compaq C++ + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + sco*) + case $cc_basename in + CC) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + *) + ;; + esac + ;; + solaris*) + case $cc_basename in + CC) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + gcx) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC) + # Sun C++ 4.x + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + lcc) + # Lucid + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC) + # NonStop-UX NCC 3.20 + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + *) + ;; + esac + ;; + unixware*) + ;; + vxworks*) + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +], +[ + if test "$GCC" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + + beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + enable_shared=no + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case "$host_cpu" in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case "$host_cpu" in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC (with -KPIC) is the default. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + newsos6) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + linux*) + case $CC in + icc* | ecc*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + ccc*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All Alpha code is PIC. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + esac + ;; + + osf3* | osf4* | osf5*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All OSF/1 code is PIC. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + sco3.2v5*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kpic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-dn' + ;; + + solaris*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sunos4*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + uts4*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *) + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +]) +AC_MSG_RESULT([$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)]) + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)"; then + AC_LIBTOOL_COMPILER_OPTION([if $compiler PIC flag $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) works], + _LT_AC_TAGVAR(lt_prog_compiler_pic_works, $1), + [$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])], [], + [case $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) in + "" | " "*) ;; + *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)" ;; + esac], + [_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) +fi +case "$host_os" in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])" + ;; +esac +]) + + +# AC_LIBTOOL_PROG_LD_SHLIBS([TAGNAME]) +# ------------------------------------ +# See if the linker supports building shared libraries. +AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS], +[AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +ifelse([$1],[CXX],[ + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + case $host_os in + aix4* | aix5*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + else + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + _LT_AC_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" + ;; + cygwin* | mingw*) + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGS]] /s/.* \([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols' + ;; + *) + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac +],[ + runpath_var= + _LT_AC_TAGVAR(allow_undefined_flag, $1)= + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no + _LT_AC_TAGVAR(archive_cmds, $1)= + _LT_AC_TAGVAR(archive_expsym_cmds, $1)= + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)= + _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1)= + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + _LT_AC_TAGVAR(thread_safe_flag_spec, $1)= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_minus_L, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(link_all_deplibs, $1)=unknown + _LT_AC_TAGVAR(hardcode_automatic, $1)=no + _LT_AC_TAGVAR(module_cmds, $1)= + _LT_AC_TAGVAR(module_expsym_cmds, $1)= + _LT_AC_TAGVAR(always_export_symbols, $1)=no + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + _LT_AC_TAGVAR(include_expsyms, $1)= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + _LT_AC_TAGVAR(exclude_expsyms, $1)="_GLOBAL_OFFSET_TABLE_" + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # See if GNU ld supports shared libraries. + case $host_os in + aix3* | aix4* | aix5*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + _LT_AC_TAGVAR(ld_shlibs, $1)=no + cat <&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +EOF + fi + ;; + + amigaos*) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + + # Samuel A. Falvo II reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we can't use + # them. + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $compiler_flags $libobjs $deplibs ${wl}-soname $wl$soname -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=no + _LT_AC_TAGVAR(always_export_symbols, $1)=no + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGS]] /s/.* \([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $compiler_flags $libobjs $deplibs -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $compiler_flags $libobjs $deplibs -o $output_objdir/$soname ${wl}--image-base=0x10000000 ${wl}--out-implib,$lib' + else + ld_shlibs=no + fi + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $compiler_flags $libobjs $deplibs ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $compiler_flags $libobjs $deplibs ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris* | sysv5*) + if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then + _LT_AC_TAGVAR(ld_shlibs, $1)=no + cat <&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +EOF + elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $compiler_flags $libobjs $deplibs ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $compiler_flags $libobjs $deplibs ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + sunos4*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $compiler_flags $libobjs $deplibs ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $compiler_flags $libobjs $deplibs ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + + if test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = yes; then + runpath_var=LD_RUN_PATH + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + fi + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + if test "$GCC" = yes && test -z "$link_static_flag"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + fi + ;; + + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + else + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + fi + + # KDE requires run time linking. Make it the default. + aix_use_runtimelinking=yes + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_AC_TAGVAR(archive_cmds, $1)='' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + else + # We have old collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + fi + esac + shared_flag='-shared' + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='-qmkshrobj ${wl}-G' + else + shared_flag='-qmkshrobj' + fi + fi + fi + + # Let the compiler handle the export list. + _LT_AC_TAGVAR(always_export_symbols, $1)=no + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + _LT_AC_TAGVAR(archive_cmds, $1)="\$CC"' -o $output_objdir/$soname $compiler_flags $libobjs $deplibs `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '" $shared_flag" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $compiler_flags $libobjs $deplibs `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $compiler_flags $libobjs $deplibs ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # -bexpall does not export symbols beginning with underscore (_) + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + # Exported symbols can be pulled into shared objects from archives + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=' ' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds it's shared libraries. + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $compiler_flags $libobjs $deplibs ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + # see comment about different semantics on the GNU ld section + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + bsdi4*) + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic + ;; + + cygwin* | mingw* | pw32*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=no + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -o $lib $compiler_flags $libobjs `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='true' + # FIXME: Should let the user specify the lib program. + _LT_AC_TAGVAR(old_archive_cmds, $1)='lib /OUT:$oldlib$oldobjs$old_deplibs' + fix_srcfile_path='`cygpath -w "$srcfile"`' + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + + darwin* | rhapsody*) + if test "$GXX" = yes ; then + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + case "$host_os" in + rhapsody* | darwin1.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-Wl,-undefined -Wl,suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-Wl,-flat_namespace -Wl,-undefined -Wl,suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[012]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-Wl,-flat_namespace -Wl,-undefined -Wl,suppress' + ;; + 10.*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-Wl,-undefined -Wl,dynamic_lookup' + ;; + esac + fi + ;; + esac + lt_int_apple_cc_single_mod=no + output_verbose_link_cmd='echo' + if $CC -dumpspecs 2>&1 | grep 'single_module' >/dev/null ; then + lt_int_apple_cc_single_mod=yes + fi + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $compiler_flags $libobjs $deplibs -install_name $rpath/$soname $verstring' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $compiler_flags $deplibs -install_name $rpath/$soname $verstring' + fi + _LT_AC_TAGVAR(module_cmds, $1)='$CC ${wl}-bind_at_load $allow_undefined_flag -o $lib -bundle $compiler_flags $libobjs $deplibs' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin ld's + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $compiler_flags $libobjs $deplibs -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r ${wl}-bind_at_load -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $compiler_flags $deplibs -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $compiler_flags $libobjs $deplibs~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_automatic, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-all_load $convenience' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + dgux*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + freebsd1*) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | kfreebsd*-gnu) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $compiler_flags $libobjs $deplibs' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + hpux9*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $compiler_flags $libobjs $deplibs~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + + hpux10* | hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case "$host_cpu" in + hppa*64*|ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $compiler_flags $libobjs $deplibs' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $compiler_flags $libobjs $deplibs' + ;; + esac + else + case "$host_cpu" in + hppa*64*|ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname -o $lib $libobjs $deplibs $linker_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + case "$host_cpu" in + hppa*64*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + ia64*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + ;; + *) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $compiler_flags $libobjs $deplibs ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + newsos6) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + openbsd*) + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $compiler_flags $libobjs $deplibs' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + else + case $host_os in + openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $compiler_flags $libobjs $deplibs' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + ;; + esac + fi + ;; + + os2*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(archive_cmds, $1)='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $compiler_flags $libobjs $deplibs$output_objdir/$libname.def' + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $compiler_flags $libobjs $deplibs ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $compiler_flags $libobjs $deplibs ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + else + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ + $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp' + + # Both c and cxx compiler support -rpath directly + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + fi + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + sco3.2v5*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ;; + + solaris*) + _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text' + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $compiler_flags $libobjs $deplibs' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $compiler_flags $libobjs $deplibs~$rm $lib.exp' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;; + esac + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $compiler_flags $libobjs $deplibs' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4) + case $host_vendor in + sni) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + ;; + motorola) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4.3*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + fi + ;; + + sysv4.2uw2*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + hardcode_runpath_var=yes + runpath_var=LD_RUN_PATH + ;; + + sysv5OpenUNIX8* | sysv5UnixWare7* | sysv5uw[[78]]* | unixware7*) + _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z ${wl}text' + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $compiler_flags $libobjs $deplibs' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h ${wl}$soname -o $lib $compiler_flags $libobjs $deplibs' + fi + runpath_var='LD_RUN_PATH' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv5*) + _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text' + # $CC -shared without GNU ld will not create a library from C++ + # object files and a static libstdc++, better avoid it by now + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + ;; + + uts4*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + fi +]) +AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)]) +test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +# +# Do we need to explicitly link libc? +# +case "x$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)" in +x|xyes) + # Assume -lc should be added + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $_LT_AC_TAGVAR(archive_cmds, $1) in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + AC_MSG_CHECKING([whether -lc should be explicitly linked in]) + $rm conftest* + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + if AC_TRY_EVAL(ac_compile) 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$_LT_AC_TAGVAR(allow_undefined_flag, $1) + _LT_AC_TAGVAR(allow_undefined_flag, $1)= + if AC_TRY_EVAL(_LT_AC_TAGVAR(archive_cmds, $1) 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) + then + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + else + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + fi + _LT_AC_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $rm conftest* + AC_MSG_RESULT([$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)]) + ;; + esac + fi + ;; +esac +])# AC_LIBTOOL_PROG_LD_SHLIBS + + +# _LT_AC_FILE_LTDLL_C +# ------------------- +# Be careful that the start marker always follows a newline. +AC_DEFUN([_LT_AC_FILE_LTDLL_C], [ +# /* ltdll.c starts here */ +# #define WIN32_LEAN_AND_MEAN +# #include +# #undef WIN32_LEAN_AND_MEAN +# #include +# +# #ifndef __CYGWIN__ +# # ifdef __CYGWIN32__ +# # define __CYGWIN__ __CYGWIN32__ +# # endif +# #endif +# +# #ifdef __cplusplus +# extern "C" { +# #endif +# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved); +# #ifdef __cplusplus +# } +# #endif +# +# #ifdef __CYGWIN__ +# #include +# DECLARE_CYGWIN_DLL( DllMain ); +# #endif +# HINSTANCE __hDllInstance_base; +# +# BOOL APIENTRY +# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved) +# { +# __hDllInstance_base = hInst; +# return TRUE; +# } +# /* ltdll.c ends here */ +])# _LT_AC_FILE_LTDLL_C + + +# _LT_AC_TAGVAR(VARNAME, [TAGNAME]) +# --------------------------------- +AC_DEFUN([_LT_AC_TAGVAR], [ifelse([$2], [], [$1], [$1_$2])]) + + +# old names +AC_DEFUN([AM_PROG_LIBTOOL], [AC_PROG_LIBTOOL]) +AC_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) +AC_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) +AC_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) +AC_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) +AC_DEFUN([AM_PROG_LD], [AC_PROG_LD]) +AC_DEFUN([AM_PROG_NM], [AC_PROG_NM]) + +# This is just to silence aclocal about the macro not being used +ifelse([AC_DISABLE_FAST_INSTALL]) + +AC_DEFUN([LT_AC_PROG_GCJ], +[AC_CHECK_TOOL(GCJ, gcj, no) + test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" + AC_SUBST(GCJFLAGS) +]) + +AC_DEFUN([LT_AC_PROG_RC], +[AC_CHECK_TOOL(RC, windres, no) +]) + +############################################################ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_SED. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +############################################################ +# LT_AC_PROG_SED +# -------------- +# Check for a fully-functional sed program, that truncates +# as few characters as possible. Prefer GNU sed if found. +AC_DEFUN([LT_AC_PROG_SED], +[AC_MSG_CHECKING([for a sed that does not truncate output]) +AC_CACHE_VAL(lt_cv_path_SED, +[# Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for lt_ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then + lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" + fi + done + done +done +lt_ac_max=0 +lt_ac_count=0 +# Add /usr/xpg4/bin/sed as it is typically found on Solaris +# along with /bin/sed that truncates output. +for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do + test ! -f $lt_ac_sed && break + cat /dev/null > conftest.in + lt_ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >conftest.in + # Check for GNU sed and select it if it is found. + if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then + lt_cv_path_SED=$lt_ac_sed + break + fi + while true; do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo >>conftest.nl + $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break + cmp -s conftest.out conftest.nl || break + # 10000 chars as input seems more than enough + test $lt_ac_count -gt 10 && break + lt_ac_count=`expr $lt_ac_count + 1` + if test $lt_ac_count -gt $lt_ac_max; then + lt_ac_max=$lt_ac_count + lt_cv_path_SED=$lt_ac_sed + fi + done +done +]) +SED=$lt_cv_path_SED +AC_MSG_RESULT([$SED]) +]) diff --git a/admin/missing b/admin/missing new file mode 100755 index 0000000..32ba9f3 --- /dev/null +++ b/admin/missing @@ -0,0 +1,353 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. + +scriptversion=2004-09-07.08 + +# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004 +# Free Software Foundation, Inc. +# Originally by Fran,cois Pinard , 1996. + +# 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, 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., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +run=: + +# In the cases where this matters, `missing' is being run in the +# srcdir already. +if test -f configure.ac; then + configure_ac=configure.ac +else + configure_ac=configure.in +fi + +msg="missing on your system" + +case "$1" in +--run) + # Try to run requested program, and just exit if it succeeds. + run= + shift + "$@" && exit 0 + # Exit code 63 means version mismatch. This often happens + # when the user try to use an ancient version of a tool on + # a file that requires a minimum version. In this case we + # we should proceed has if the program had been absent, or + # if --run hadn't been passed. + if test $? = 63; then + run=: + msg="probably too old" + fi + ;; + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + --run try to run the given command, and emulate it if it fails + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + help2man touch the output file + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + tar try tar, gnutar, gtar, then tar without non-portable flags + yacc create \`y.tab.[ch]', if possible, from existing .[ch] + +Send bug reports to ." + exit 0 + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing $scriptversion (GNU Automake)" + exit 0 + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + +esac + +# Now exit if we have it, but it failed. Also exit now if we +# don't have it and --version was passed (most likely to detect +# the program). +case "$1" in + lex|yacc) + # Not GNU programs, they don't have --version. + ;; + + tar) + if test -n "$run"; then + echo 1>&2 "ERROR: \`tar' requires --run" + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + exit 1 + fi + ;; + + *) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + # Could not run --version or --help. This is probably someone + # running `$TOOL --version' or `$TOOL --help' to check whether + # $TOOL exists and not knowing $TOOL uses missing. + exit 1 + fi + ;; +esac + +# If it does not exist, or fails to run (possibly an outdated version), +# try to emulate it. +case "$1" in + aclocal*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acinclude.m4' or \`${configure_ac}'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`${configure_ac}'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acconfig.h' or \`${configure_ac}'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case "$f" in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + autom4te) + echo 1>&2 "\ +WARNING: \`$1' is needed, but is $msg. + You might have modified some files without having the + proper tools for further handling them. + You can get \`$1' as part of \`Autoconf' from any GNU + archive site." + + file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'` + test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo "#! /bin/sh" + echo "# Created by GNU Automake missing as a replacement of" + echo "# $ $@" + echo "exit 0" + chmod +x $file + exit 1 + fi + ;; + + bison|yacc) + echo 1>&2 "\ +WARNING: \`$1' $msg. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if [ ! -f y.tab.h ]; then + echo >y.tab.h + fi + if [ ! -f y.tab.c ]; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex|flex) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if [ ! -f lex.yy.c ]; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + help2man) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a dependency of a manual page. You may need the + \`Help2man' package in order for those modifications to take + effect. You can get \`Help2man' from any GNU archive site." + + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'` + fi + if [ -f "$file" ]; then + touch $file + else + test -z "$file" || exec >$file + echo ".ab help2man is required to generate this page" + exit 1 + fi + ;; + + makeinfo) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file` + fi + touch $file + ;; + + tar) + shift + + # We have already tried tar in the generic part. + # Look for gnutar/gtar before invocation to avoid ugly error + # messages. + if (gnutar --version > /dev/null 2>&1); then + gnutar "$@" && exit 0 + fi + if (gtar --version > /dev/null 2>&1); then + gtar "$@" && exit 0 + fi + firstarg="$1" + if shift; then + case "$firstarg" in + *o*) + firstarg=`echo "$firstarg" | sed s/o//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + case "$firstarg" in + *h*) + firstarg=`echo "$firstarg" | sed s/h//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + fi + + echo 1>&2 "\ +WARNING: I can't seem to be able to run \`tar' with the given arguments. + You may want to install GNU tar or Free paxutils, or check the + command line arguments." + exit 1 + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and is $msg. + You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequisites for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/admin/mkinstalldirs b/admin/mkinstalldirs new file mode 100644 index 0000000..8ef092d --- /dev/null +++ b/admin/mkinstalldirs @@ -0,0 +1,158 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy + +scriptversion=2005-06-29.22 + +# Original author: Noah Friedman +# Created: 1993-05-16 +# Public domain. +# +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + +errstatus=0 +dirmode= + +usage="\ +Usage: mkinstalldirs [-h] [--help] [--version] [-m MODE] DIR ... + +Create each directory DIR (with mode MODE, if specified), including all +leading file name components. + +Report bugs to ." + +# process command line arguments +while test $# -gt 0 ; do + case $1 in + -h | --help | --h*) # -h for help + echo "$usage" + exit $? + ;; + -m) # -m PERM arg + shift + test $# -eq 0 && { echo "$usage" 1>&2; exit 1; } + dirmode=$1 + shift + ;; + --version) + echo "$0 $scriptversion" + exit $? + ;; + --) # stop option processing + shift + break + ;; + -*) # unknown option + echo "$usage" 1>&2 + exit 1 + ;; + *) # first non-opt arg + break + ;; + esac +done + +for file +do + if test -d "$file"; then + shift + else + break + fi +done + +case $# in + 0) exit 0 ;; +esac + +# Solaris 8's mkdir -p isn't thread-safe. If you mkdir -p a/b and +# mkdir -p a/c at the same time, both will detect that a is missing, +# one will create a, then the other will try to create a and die with +# a "File exists" error. This is a problem when calling mkinstalldirs +# from a parallel make. We use --version in the probe to restrict +# ourselves to GNU mkdir, which is thread-safe. +case $dirmode in + '') + if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then + echo "mkdir -p -- $*" + exec mkdir -p -- "$@" + else + # On NextStep and OpenStep, the `mkdir' command does not + # recognize any option. It will interpret all options as + # directories to create, and then abort because `.' already + # exists. + test -d ./-p && rmdir ./-p + test -d ./--version && rmdir ./--version + fi + ;; + *) + if mkdir -m "$dirmode" -p --version . >/dev/null 2>&1 && + test ! -d ./--version; then + echo "mkdir -m $dirmode -p -- $*" + exec mkdir -m "$dirmode" -p -- "$@" + else + # Clean up after NextStep and OpenStep mkdir. + for d in ./-m ./-p ./--version "./$dirmode"; + do + test -d $d && rmdir $d + done + fi + ;; +esac + +for file +do + case $file in + /*) pathcomp=/ ;; + *) pathcomp= ;; + esac + oIFS=$IFS + IFS=/ + set fnord $file + shift + IFS=$oIFS + + for d + do + test "x$d" = x && continue + + pathcomp=$pathcomp$d + case $pathcomp in + -*) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" + + mkdir "$pathcomp" || lasterr=$? + + if test ! -d "$pathcomp"; then + errstatus=$lasterr + else + if test ! -z "$dirmode"; then + echo "chmod $dirmode $pathcomp" + lasterr= + chmod "$dirmode" "$pathcomp" || lasterr=$? + + if test ! -z "$lasterr"; then + errstatus=$lasterr + fi + fi + fi + fi + + pathcomp=$pathcomp/ + done +done + +exit $errstatus + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/admin/nmcheck b/admin/nmcheck new file mode 100755 index 0000000..f799186 --- /dev/null +++ b/admin/nmcheck @@ -0,0 +1,371 @@ +#!/usr/bin/perl -w + +# Check namespace cleanness of a library. +# Allowed symbols are passed as arguments. +# They may have trailing * = wildcard. +# Wildcards may be also specified as *::* (e.g. K*::* for all KDE classes) +# Symbols are listed as full function unmangled names without arguments, +# e.g. 'foo bar* nspace::*' allows foo(), foo(int), bar(), barbar() +# and all symbols in namespace/class nspace. +# If an argument has comma in it, it's a filename of a file containing +# allowed symbols, one per line. + + +$thisProg = "$0"; # This programs name + +$library = ""; +$allowed_symbols = ""; +$debug = 0; +$allowed_weak = ""; +$weak_specified = 0; + +while( defined( $ARGV[ 0 ] )) +{ + $_ = shift; + if( /^--verbose$|^-v$/ ) + { + $debug = 1; + } + elsif( /^--help$|^-h$/ ) + { + print STDOUT "Usage $thisProg [OPTION] ... library [allowed symbols] ...\n", + "\n", + "Check if the given library has only allowed public symbols.\n", + "\n", + " --allowweak=[symbol] allow only these weak symbols\n", + " -v, --verbose verbosely list files processed\n", + " -h, --help print this help, then exit\n"; + exit 0; + } + elsif( /^--allowweak=(.*)$/ ) + { + $allowed_weak .= " " . $1; + $weak_specified = 1; + } + elsif( /^--allowweak$/ ) # simply list all weak + { + $allowed_weak .= " "; + $weak_specified = 1; + } + elsif( /^--*/ ) + { + die "Invalid argument!\n"; + } + else + { + if( ! $library ) + { + $library = $_; + } + else + { + $allowed_symbols .= " " . $_; + } + } +} + +if( ! $weak_specified ) +{ + $allowed_weak = "*"; + # allow all weak symbols by default + # instances of templates and similar stuff - unfortunately includes also things from other libraries, + # so it cannot be on by default +} + +print STDERR "library:" . $library . "\n" if $debug; +print STDERR "allowed_symbols:" . $allowed_symbols . "\n" if $debug; +print STDERR "allowed_weak:" . $allowed_weak . "\n" if $debug; + +$default_symbols = "_fini _init"; # system symbols +# on my system, every .so has : +# A _DYNAMIC +# A _GLOBAL_OFFSET_TABLE_ +# A __bss_start +# A _edata +# A _end +# T _fini +# T _init +# no need to list A symbols in $default_symbols + +print STDERR "default_symbols: " . $default_symbols . "\n" if $debug; + +print STDOUT "Namespace cleanness check for " . $library . " :\n"; + +$lib_file = ""; +if( $library =~ /\.la$/ ) +{ + # get the real library file from .la + open( FILEIN, $library ) || die "Couldn't open $! !\n"; + while( $line = ) + { + if( $line =~ /library_names=\'([^ ]*).*/o ) + { + $lib_file = $1; + } + } + close( FILEIN ); + if( ! $lib_file ) + { + print STDERR "Library file not found in .la file!\n"; + exit 1; + } + my $libpath = $library; + $libpath =~ s%[^/]*$%%; + if( -e $libpath . ".libs/" . $lib_file ) + { + $lib_file = $libpath . ".libs/" . $lib_file; + } + else + { + $lib_file = $libpath . $lib_file; + } +} +else +{ + $lib_file = $library; +} + +print STDERR "libfile: ". $lib_file . "\n" if $debug; + +$allowed_symbols .= " " . $default_symbols; + +sub process_symbols($\@\%\@); + +@wildcards = (); +%exacts = (); +@regwildcards = (); +process_symbols( $allowed_symbols, @wildcards, %exacts, @regwildcards ); +@weak_wildcards = (); +%weak_exacts = (); +@weak_regwildcards = (); +process_symbols( $allowed_weak, @weak_wildcards, %weak_exacts, @weak_regwildcards ); + +# grep is for stripping not exported symbols, which don't have address (=first column) +$nm_command = "nm -BDCg " . $lib_file . " | grep -v '^ ' |"; + +# TODO how portable is this nmcheck stuff? + +print STDERR "nm command:" . $nm_command . "\n" if $debug; + +open( FILEIN, $nm_command ) || die "nm command failed\n"; + +my $exit_code = 0; + +while( $line = ) +{ + my $type; + my $symbol; + if( $line =~ /^[^ ]* (.) (.*)$/o ) + { + $type = $1; + $symbol = $2; + } + else + { + die "Invalid line: " . $line . "\n"; + } + + print STDERR "Type: " . $type . " , symbol: " . $symbol . "\n" if $debug; + if( $type eq "A" ) + { # these should be system symbols, so ignore them + next; + } + + my $orig_symbol = $symbol; + + if( $symbol =~ /\(anonymous namespace\)/o ) + { # TODO tell to prefer named namespaces? (shorter symbols) + next; + } + + # strip prefixes + # the :: appending is to make "CLASS::*" work also for "vtable for CLASS" + $symbol =~ s/^typeinfo for (.*)$/$1::/o; + $symbol =~ s/^typeinfo fn for (.*)$/$1::/o; + $symbol =~ s/^typeinfo name for (.*)$/$1::/o; + $symbol =~ s/^vtable for (.*)$/$1::/o; + $symbol =~ s/^guard variable for (.*)$/$1::/o; + $symbol =~ s/^reference temporary for (.*)$/$1::/o; + $symbol =~ s/^VTT for (.*)$/$1::/o; + $symbol =~ s/^virtual thunk \[[^\]]*\] to (.*)$/$1::/o; + $symbol =~ s/^non-virtual thunk \[[^\]]*\] to (.*)$/$1::/o; + $symbol =~ s/^covariant return thunk \[[^\]]*\] to (.*)$/$1::/o; + $symbol =~ s/^construction vtable thunk for (.*)$/$1::/o; + $symbol =~ s/^construction vtable for .*-in-(.*) [0-9]*$/$1::/o; + + # templates seem to have also return types mangled in their name, and nm prints it too + # they have also template arguments in the symbol + # get rid of both of those + while( $symbol =~ /<.*>/o ) + { + $symbol =~ s/<[^<>]*>//o; # strip innermost <> + } + if( $symbol !~ /operator\(\)/o ) + { + $symbol =~ s/ ?\(.*\).*$//o; # strip () and all after it + } + else + { + $symbol =~ s/(^|:| )operator\(\) ?\(.*\).*$//o; # strip () and all after it + } + $symbol =~ s/\[.*\] *$//o; # strip [in-charge] etc. + if( $symbol =~ /(^|:| )operator /o ) + { + $symbol =~ s/.* ([^\s]*)operator /$1/o; # strip everything before 'X::operator blah' + } + else + { + $symbol =~ s/.* ([^\s]+) *$/$1/o; # get last word (strip return type) + } + + # print STDERR "Processed symbol: " . $symbol . "\n" if $debug; + + my $found = 0; + if( $exacts{ $symbol } ) + { + $found = 1; + } + if( ! $found ) + { + for my $wild ( @wildcards ) + { + if( index( $symbol, $wild ) == 0 ) + { + $found = 1; + last; + } + } + } + if( ! $found ) + { + for my $wild ( @regwildcards ) + { + if( $symbol =~ /^$wild$/ ) + { + $found = 1; + last; + } + } + } + if( ( ! $found ) && ( $type eq "W" || $type eq "V" )) + { + if( $weak_exacts{ $symbol } ) + { + $found = 1; + } + if( ! $found ) + { + for my $wild ( @weak_wildcards ) + { + if( index( $symbol, $wild ) == 0 ) + { + $found = 1; + last; + } + } + } + if( ! $found ) + { + for my $wild ( @weak_regwildcards ) + { + if( $symbol =~ /^$wild$/ ) + { + $found = 1; + last; + } + } + } + } + + if( ! $found ) + { + print STDERR "Public symbol " . $orig_symbol . " is not allowed!\n"; + $exit_code = 1; + } +} + +close( FILEIN ); + +print STDOUT $exit_code == 0 ? "OK\n" : "FAILED\n"; + +exit $exit_code; + +sub process_symbols($\@\%\@) +{ + my $allowed_symbols = $_[ 0 ]; + my $wildcards_ref = $_[ 1 ]; + my $exacts_ref = $_[ 2 ]; + my $regwildcards_ref = $_[ 3 ]; + + $allowed_symbols =~ s/^ *//o; # strip whitespace + $allowed_symbols =~ s/ *$//o; + + if( $allowed_symbols eq "NONE" ) + { + $allowed_symbols = ""; + } + + my @symbols1 = split( ' ', $allowed_symbols ); + my $i = 0; + my @symbols2 = (); + while( defined( $symbols1[ $i ] )) + { + my $symbol = $symbols1[ $i ]; + if( $symbol =~ /\./ ) # dot in name -> file + { + open( SYMIN, $symbol ) || die ( "Cannot open file " . $symbol . "!" ); + while( $line = ) + { + $line =~ s/^\s*//o; # strip whitespace + $line =~ s/\s*$//o; + if( $line !~ /^$/o # empty line + && $line !~ /^\s*#/ ) # comment line starting with # + { + $symbols2[ $#symbols2 + 1 ] = $line; + } + } + close( SYMIN ); + } + else + { + $symbols2[ $#symbols2 + 1 ] = $symbol; + } + $i++; + } + $i = 0; + while( defined( $symbols2[ $i ] )) + { + my $symbol = $symbols2[ $i ]; + if( $symbol =~ /__/ + || $symbol =~ /^_[A-Z]/ ) + { # ISO C++ 2.10.2 + die "Symbols containing a double underscore or beginning with an underscore and an upper-case letter are reserved!\n"; + } + elsif( $symbol eq "main" + || $symbol eq "main*" ) + { + die "Symbol main is not allowed!\n"; + } + if( $symbol =~ /^([^\*]*)\*$/o # trailing * without any * before it + && $symbol !~ /operator\*$/o ) + { + print STDERR "wildcard:" . $symbol . "\n" if $debug; + $wildcards_ref->[ $#{$wildcards_ref} + 1 ] = $1; + } + elsif( $symbol =~ /\*$/o + && ( $symbol =~ /\*::/o || $symbol =~ /::\*/o ) + && $symbol !~ /^\*/o + && $symbol !~ /operator\*$/o ) + { + print STDERR "regwildcard:" . $symbol . "\n" if $debug; + $symbol =~ s/\*/\.\*/go; # change * to .* (regexp) + $regwildcards_ref->[ $#{$regwildcards_ref} + 1 ] = $symbol; + } + else + { + print STDERR "exact:" . $symbol . "\n" if $debug; + $exacts_ref->{ $symbol } = 1; + } + $i++; + } +} diff --git a/admin/oldinclude.m4.in b/admin/oldinclude.m4.in new file mode 100644 index 0000000..0b64619 --- /dev/null +++ b/admin/oldinclude.m4.in @@ -0,0 +1,192 @@ +### -*- autoconf -*- + +dnl This file is part of the KDE libraries/packages +dnl Copyright (C) 1997 Janos Farkas (chexum@shadow.banki.hu) +dnl (C) 1997,98,99 Stephan Kulow (coolo@kde.org) + +dnl This file is free software; you can redistribute it and/or +dnl modify it under the terms of the GNU Library General Public +dnl License as published by the Free Software Foundation; either +dnl version 2 of the License, or (at your option) any later version. + +dnl This library is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl Library General Public License for more details. + +dnl You should have received a copy of the GNU Library General Public License +dnl along with this library; see the file COPYING.LIB. If not, write to +dnl the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +dnl Boston, MA 02110-1301, USA. + +AC_DEFUN([KDE_CHECK_MICO], +[ +AC_REQUIRE([KDE_CHECK_LIBDL]) +AC_REQUIRE([KDE_MISC_TESTS]) +AC_MSG_CHECKING(for MICO) + +if test -z "$MICODIR"; then + kde_micodir=/usr/local + else + kde_micodir="$MICODIR" +fi + +AC_ARG_WITH(micodir, + [ --with-micodir=micodir where mico is installed ], + kde_micodir=$withval, + kde_micodir=$kde_micodir +) + +AC_CACHE_VAL(kde_cv_mico_incdir, +[ + mico_incdirs="$kde_micodir/include /usr/include /usr/local/include /usr/local/include /opt/local/include $kde_extra_includes" +AC_FIND_FILE(CORBA.h, $mico_incdirs, kde_cv_mico_incdir) + +]) +kde_micodir=`echo $kde_cv_mico_incdir | sed -e 's#/include##'` + +if test ! -r $kde_micodir/include/CORBA.h; then + AC_MSG_ERROR([No CORBA.h found, specify another micodir]) +fi + +AC_MSG_RESULT($kde_micodir) + +MICO_INCLUDES=-I$kde_micodir/include +AC_SUBST(MICO_INCLUDES) +MICO_LDFLAGS=-L$kde_micodir/lib +AC_SUBST(MICO_LDFLAGS) +micodir=$kde_micodir +AC_SUBST(micodir) + +AC_MSG_CHECKING([for MICO version]) +AC_CACHE_VAL(kde_cv_mico_version, +[ +AC_LANG_C +cat >conftest.$ac_ext < +#include +int main() { + + printf("MICO_VERSION=%s\n",MICO_VERSION); + return (0); +} +EOF +ac_compile='${CC-gcc} $CFLAGS $MICO_INCLUDES conftest.$ac_ext -o conftest' +if AC_TRY_EVAL(ac_compile); then + if eval `./conftest 2>&5`; then + kde_cv_mico_version=$MICO_VERSION + else + AC_MSG_ERROR([your system is not able to execute a small application to + find MICO version! Check $kde_micodir/include/mico/version.h]) + fi +else + AC_MSG_ERROR([your system is not able to compile a small application to + find MICO version! Check $kde_micodir/include/mico/version.h]) +fi +]) + +dnl installed MICO version +mico_v_maj=`echo $kde_cv_mico_version | sed -e 's/^\(.*\)\..*\..*$/\1/'` +mico_v_mid=`echo $kde_cv_mico_version | sed -e 's/^.*\.\(.*\)\..*$/\1/'` +mico_v_min=`echo $kde_cv_mico_version | sed -e 's/^.*\..*\.\(.*\)$/\1/'` + +if test "x$1" = "x"; then + req_version="2.3.0" +else + req_version=$1 +fi + +dnl required MICO version +req_v_maj=`echo $req_version | sed -e 's/^\(.*\)\..*\..*$/\1/'` +req_v_mid=`echo $req_version | sed -e 's/^.*\.\(.*\)\..*$/\1/'` +req_v_min=`echo $req_version | sed -e 's/^.*\..*\.\(.*\)$/\1/'` + +if test "$mico_v_maj" -lt "$req_v_maj" || \ + ( test "$mico_v_maj" -eq "$req_v_maj" && \ + test "$mico_v_mid" -lt "$req_v_mid" ) || \ + ( test "$mico_v_mid" -eq "$req_v_mid" && \ + test "$mico_v_min" -lt "$req_v_min" ) + +then + AC_MSG_ERROR([found MICO version $kde_cv_mico_version but version $req_version \ +at least is required. You should upgrade MICO.]) +else + AC_MSG_RESULT([$kde_cv_mico_version (minimum version $req_version, ok)]) +fi + +LIBMICO="-lmico$kde_cv_mico_version $LIBCRYPT $LIBSOCKET $LIBDL" +AC_SUBST(LIBMICO) +if test -z "$IDL"; then + IDL='$(kde_bindir)/cuteidl' +fi +AC_SUBST(IDL) +IDL_DEPENDENCIES='$(kde_includes)/CUTE.h' +AC_SUBST(IDL_DEPENDENCIES) + +idldir="\$(includedir)/idl" +AC_SUBST(idldir) + +]) + +AC_DEFUN([KDE_CHECK_MINI_STL], +[ +AC_REQUIRE([KDE_CHECK_MICO]) + +AC_MSG_CHECKING(if we use mico's mini-STL) +AC_CACHE_VAL(kde_cv_have_mini_stl, +[ +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +kde_save_cxxflags="$CXXFLAGS" +CXXFLAGS="$CXXFLAGS $MICO_INCLUDES" +AC_TRY_COMPILE( +[ +#include +], +[ +#ifdef HAVE_MINI_STL +#error "nothing" +#endif +], +kde_cv_have_mini_stl=no, +kde_cv_have_mini_stl=yes) +CXXFLAGS="$kde_save_cxxflags" +AC_LANG_RESTORE +]) + +if test "x$kde_cv_have_mini_stl" = "xyes"; then + AC_MSG_RESULT(yes) + $1 +else + AC_MSG_RESULT(no) + $2 +fi +]) + +]) + +AC_DEFUN([KDE_CHECK_ANSI], +[ +]) + +AC_DEFUN([KDE_CHECK_INSURE], +[ + AC_ARG_ENABLE(insure, [ --enable-insure use insure++ for debugging [default=no]], + [ + if test $enableval = "no"; dnl + then ac_use_insure="no" + else ac_use_insure="yes" + fi + ], [ac_use_insure="no"]) + + AC_MSG_CHECKING(if we will use Insure++ to debug) + AC_MSG_RESULT($ac_use_insure) + if test "$ac_use_insure" = "yes"; dnl + then CC="insure"; CXX="insure"; dnl CFLAGS="$CLAGS -fno-rtti -fno-exceptions "???? + fi +]) + +AC_DEFUN([KDE_CHECK_NEWLIBS], +[ + +]) diff --git a/admin/pkg.m4.in b/admin/pkg.m4.in new file mode 100644 index 0000000..e9c38f1 --- /dev/null +++ b/admin/pkg.m4.in @@ -0,0 +1,57 @@ + +dnl PKG_CHECK_MODULES(GSTUFF, gtk+-2.0 >= 1.3 glib = 1.3.4, action-if, action-not) +dnl defines GSTUFF_LIBS, GSTUFF_CFLAGS, see pkg-config man page +dnl also defines GSTUFF_PKG_ERRORS on error +AC_DEFUN([PKG_CHECK_MODULES], [ + succeeded=no + + if test -z "$PKG_CONFIG"; then + AC_PATH_PROG(PKG_CONFIG, pkg-config, no) + fi + + if test "$PKG_CONFIG" = "no" ; then + echo "*** The pkg-config script could not be found. Make sure it is" + echo "*** in your path, or set the PKG_CONFIG environment variable" + echo "*** to the full path to pkg-config." + echo "*** Or see http://www.freedesktop.org/software/pkgconfig to get pkg-config." + else + PKG_CONFIG_MIN_VERSION=0.9.0 + if $PKG_CONFIG --atleast-pkgconfig-version $PKG_CONFIG_MIN_VERSION; then + AC_MSG_CHECKING(for $2) + + if $PKG_CONFIG --exists "$2" ; then + AC_MSG_RESULT(yes) + succeeded=yes + + AC_MSG_CHECKING($1_CFLAGS) + $1_CFLAGS=`$PKG_CONFIG --cflags "$2"` + AC_MSG_RESULT($$1_CFLAGS) + + AC_MSG_CHECKING($1_LIBS) + $1_LIBS=`$PKG_CONFIG --libs "$2"` + AC_MSG_RESULT($$1_LIBS) + else + $1_CFLAGS="" + $1_LIBS="" + ## If we have a custom action on failure, don't print errors, but + ## do set a variable so people can do so. + $1_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"` + ifelse([$4], ,echo $$1_PKG_ERRORS,) + fi + + AC_SUBST($1_CFLAGS) + AC_SUBST($1_LIBS) + else + echo "*** Your version of pkg-config is too old. You need version $PKG_CONFIG_MIN_VERSION or newer." + echo "*** See http://www.freedesktop.org/software/pkgconfig" + fi + fi + + if test $succeeded = yes; then + ifelse([$3], , :, [$3]) + else + ifelse([$4], , AC_MSG_ERROR([Library requirements ($2) not met; consider adjusting the PKG_CONFIG_PATH environment variable if your libraries are in a nonstandard prefix so pkg-config can find them.]), [$4]) + fi +]) + + diff --git a/admin/ylwrap b/admin/ylwrap new file mode 100755 index 0000000..6f5828c --- /dev/null +++ b/admin/ylwrap @@ -0,0 +1,223 @@ +#! /bin/sh +# ylwrap - wrapper for lex/yacc invocations. + +scriptversion=2005-05-14.22 + +# Copyright (C) 1996, 1997, 1998, 1999, 2001, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# Written by Tom Tromey . +# +# 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, 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 +# 02110-1301, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + +case "$1" in + '') + echo "$0: No files given. Try \`$0 --help' for more information." 1>&2 + exit 1 + ;; + --basedir) + basedir=$2 + shift 2 + ;; + -h|--h*) + cat <<\EOF +Usage: ylwrap [--help|--version] INPUT [OUTPUT DESIRED]... -- PROGRAM [ARGS]... + +Wrapper for lex/yacc invocations, renaming files as desired. + + INPUT is the input file + OUTPUT is one file PROG generates + DESIRED is the file we actually want instead of OUTPUT + PROGRAM is program to run + ARGS are passed to PROG + +Any number of OUTPUT,DESIRED pairs may be used. + +Report bugs to . +EOF + exit $? + ;; + -v|--v*) + echo "ylwrap $scriptversion" + exit $? + ;; +esac + + +# The input. +input="$1" +shift +case "$input" in + [\\/]* | ?:[\\/]*) + # Absolute path; do nothing. + ;; + *) + # Relative path. Make it absolute. + input="`pwd`/$input" + ;; +esac + +pairlist= +while test "$#" -ne 0; do + if test "$1" = "--"; then + shift + break + fi + pairlist="$pairlist $1" + shift +done + +# The program to run. +prog="$1" +shift +# Make any relative path in $prog absolute. +case "$prog" in + [\\/]* | ?:[\\/]*) ;; + *[\\/]*) prog="`pwd`/$prog" ;; +esac + +# FIXME: add hostname here for parallel makes that run commands on +# other machines. But that might take us over the 14-char limit. +dirname=ylwrap$$ +trap "cd `pwd`; rm -rf $dirname > /dev/null 2>&1" 1 2 3 15 +mkdir $dirname || exit 1 + +cd $dirname + +case $# in + 0) $prog "$input" ;; + *) $prog "$@" "$input" ;; +esac +ret=$? + +if test $ret -eq 0; then + set X $pairlist + shift + first=yes + # Since DOS filename conventions don't allow two dots, + # the DOS version of Bison writes out y_tab.c instead of y.tab.c + # and y_tab.h instead of y.tab.h. Test to see if this is the case. + y_tab_nodot="no" + if test -f y_tab.c || test -f y_tab.h; then + y_tab_nodot="yes" + fi + + # The directory holding the input. + input_dir=`echo "$input" | sed -e 's,\([\\/]\)[^\\/]*$,\1,'` + # Quote $INPUT_DIR so we can use it in a regexp. + # FIXME: really we should care about more than `.' and `\'. + input_rx=`echo "$input_dir" | sed 's,\\\\,\\\\\\\\,g;s,\\.,\\\\.,g'` + + while test "$#" -ne 0; do + from="$1" + # Handle y_tab.c and y_tab.h output by DOS + if test $y_tab_nodot = "yes"; then + if test $from = "y.tab.c"; then + from="y_tab.c" + else + if test $from = "y.tab.h"; then + from="y_tab.h" + fi + fi + fi + if test -f "$from"; then + # If $2 is an absolute path name, then just use that, + # otherwise prepend `../'. + case "$2" in + [\\/]* | ?:[\\/]*) target="$2";; + *) target="../$2";; + esac + + # We do not want to overwrite a header file if it hasn't + # changed. This avoid useless recompilations. However the + # parser itself (the first file) should always be updated, + # because it is the destination of the .y.c rule in the + # Makefile. Divert the output of all other files to a temporary + # file so we can compare them to existing versions. + if test $first = no; then + realtarget="$target" + target="tmp-`echo $target | sed s/.*[\\/]//g`" + fi + # Edit out `#line' or `#' directives. + # + # We don't want the resulting debug information to point at + # an absolute srcdir; it is better for it to just mention the + # .y file with no path. + # + # We want to use the real output file name, not yy.lex.c for + # instance. + # + # We want the include guards to be adjusted too. + FROM=`echo "$from" | sed \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'\ + -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'` + TARGET=`echo "$2" | sed \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'\ + -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'` + + sed -e "/^#/!b" -e "s,$input_rx,," -e "s,$from,$2," \ + -e "s,$FROM,$TARGET," "$from" >"$target" || ret=$? + + # Check whether header files must be updated. + if test $first = no; then + if test -f "$realtarget" && cmp -s "$realtarget" "$target"; then + echo "$2" is unchanged + rm -f "$target" + else + echo updating "$2" + mv -f "$target" "$realtarget" + fi + fi + else + # A missing file is only an error for the first file. This + # is a blatant hack to let us support using "yacc -d". If -d + # is not specified, we don't want an error when the header + # file is "missing". + if test $first = yes; then + ret=1 + fi + fi + shift + shift + first=no + done +else + ret=$? +fi + +# Remove the directory. +cd .. +rm -rf $dirname + +exit $ret + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/altlinux.spec b/altlinux.spec new file mode 100644 index 0000000..c23d3bb --- /dev/null +++ b/altlinux.spec @@ -0,0 +1,476 @@ +%define versuffix %nil + +%def_enable simqt +%def_enable simkde + +%if_enabled simqt +%define simqtinstalldir %_builddir/%name-%version/qtinstalldir/ +%endif + +%if_enabled simkde +%define siminstalldir %_builddir/%name-%version/installdir/ +%endif + +Name: sim +Version: 0.9.5 +Release: alt0.2 +Serial: 1 + +Group: Networking/Instant messaging +Summary: SIM - Simple Instant Messenger (with KDE support) +Summary(ru_RU.CP1251): SIM - êëèåíò ICQ/AIM/MSN/Jabber (ñ ïîääåðæêîé KDE) +License: GPL +Packager: SIM Development Team + +Url: http://sim-im.org/ + +Source: %name-%version%versuffix.tar.bz2 + +Patch0: %name-alt-play_wrapper.patch + +BuildPreReq: cmake >= 2.4.4 + +BuildPreReq: libXScrnSaver-devel + +BuildPreReq: gcc-c++ flex libqt3-devel +BuildPreReq: libssl-devel libxslt-devel zip +BuildPreReq: libpng-devel +BuildPreReq: libqt3-devel-cxx = %__gcc_version_base + +%if_enabled simkde +BuildPreReq: kdelibs-devel +BuildPreReq: kdelibs-devel-cxx = %__gcc_version_base +%endif +%if_enabled simqt +BuildPreReq: libaspell-devel +%endif + +%if_enabled simkde +Requires: %name-common >= %version-%release +Requires: sound_handler + +Obsoletes: libsim sim-plugins +#Provides: libsim sim-plugins +Conflicts: libsim-qt +Conflicts: sim-qt < 0.9.3-alt0.2 +%endif + +%description +A simple ICQ client for X win system (requires QT, +can be build for KDE). It also runs under MS Windows. +Supported protocols: ICQ v8 (2001), Jabber, MSN, AIM, YIM. + +This package contains version built with KDE support. + +%description -l ru_RU.CP1251 +Êðîññïëàòôîðìåííûé, ìíîãîïðîòîêîëüíûé êëèåíò îáìåíà ìãíîâåííûìè +ñîîáùåíèÿìè (òðåáóåò Qt, ìîæåò áûòü ñîáðàí ñ ïîääåðæêîé KDE). +Ïîääåðæèâàþòñÿ ïðîòîêîëû ICQ, Jabber, MSN, AIM, YIM, à òàêæå +LiveJournal. Êðîìå òîãî, èìååòñÿ ìíîæåñòâî ïëàãèíîâ, ðåàëèçóþùèõ +äîïîëíèòåëüíûå âîçìîæíîñòè. + +Äàííûé ïàêåò ñîäåðæèò âåðñèþ, ñîáðàííóþ ñ ïîääåðæêîé KDE. + +%if_enabled simqt +%package qt +Group: Networking/Instant messaging +Summary: SIM - Simple Instant Messenger (without KDE support) +Summary(ru_RU.CP1251): SIM - êëèåíò ICQ/AIM/MSN/Jabber (áåç ïîääåðæêè KDE) + +Requires: %name-common >= %version-%release +Requires: sound_handler + +Obsoletes: libsim-qt sim-qt-plugins +#Provides: libsim-qt sim-qt-plugins +Conflicts: libsim +Conflicts: sim < 0.9.3-alt0.2 + +%description qt +A simple ICQ client for X win system (requires QT, +can be build for KDE). It also runs under MS Windows. +Supported protocols: ICQ v8 (2001), Jabber, MSN, AIM, YIM. + +This package contains version built without KDE support. + +%description qt -l ru_RU.CP1251 +Êðîññïëàòôîðìåííûé, ìíîãîïðîòîêîëüíûé êëèåíò îáìåíà ìãíîâåííûìè +ñîîáùåíèÿìè (òðåáóåò Qt, ìîæåò áûòü ñîáðàí ñ ïîääåðæêîé KDE). +Ïîääåðæèâàþòñÿ ïðîòîêîëû ICQ, Jabber, MSN, AIM, YIM, à òàêæå +LiveJournal. Êðîìå òîãî, èìååòñÿ ìíîæåñòâî ïëàãèíîâ, ðåàëèçóþùèõ +äîïîëíèòåëüíûå âîçìîæíîñòè. + +Äàííûé ïàêåò ñîäåðæèò âåðñèþ, ñîáðàííóþ áåç ïîääåðæêè KDE. +%endif + +%package common +Group: Networking/Instant messaging +Summary: SIM - Simple Instant Messenger (data files) +Summary(ru_RU.CP1251): SIM - êëèåíò ICQ/AIM/MSN/Jabber (ôàéëû äàííûõ) + +Obsoletes: sim-data sim-qt-data +#Provides: sim-data sim-qt-data +Conflicts: sim < 0.9.0 +Conflicts: sim-qt < 0.9.0 + +%description common +A simple ICQ client for X win system (requires QT, +can be build for KDE). It also runs under MS Windows. +Supported protocols: ICQ v8 (2001), Jabber, MSN, AIM, YIM. + +This package contains common files for both sim and sim-qt. + +%description common -l ru_RU.CP1251 +Êðîññïëàòôîðìåííûé, ìíîãîïðîòîêîëüíûé êëèåíò îáìåíà ìãíîâåííûìè +ñîîáùåíèÿìè (òðåáóåò Qt, ìîæåò áûòü ñîáðàí ñ ïîääåðæêîé KDE). +Ïîääåðæèâàþòñÿ ïðîòîêîëû ICQ, Jabber, MSN, AIM, YIM, à òàêæå +LiveJournal. Êðîìå òîãî, èìååòñÿ ìíîæåñòâî ïëàãèíîâ, ðåàëèçóþùèõ +äîïîëíèòåëüíûå âîçìîæíîñòè. + +Äàííûé ïàêåò ñîäåðæèò ôàéëû äàííûõ, íåîáõîäèìûå äëÿ sim è sim-qt. + +%prep +%if_disabled simqt +%if_disabled simkde +echo "Error: one of simkde and simqt must be enabled" +exit 1 +%endif +%endif + +%setup #-n %name + +%patch0 -p1 + +%build +## Without KDE ## +%if_enabled simqt +mkdir simqt +pushd simqt +cmake %_builddir/%name-%version \ + -DCMAKE_C_FLAGS:STRING="%optflags" \ + -DCMAKE_CXX_FLAGS:STRING="%optflags" \ + -DCMAKE_INSTALL_PREFIX=%_prefix \ + -DCMAKE_SKIP_RPATH=YES \ + -DUSE_GCC_VISIBILITY=1 \ + -DENABLE_KDE3=0 \ + -DSIM_FLAVOUR="-qt" +%make_build +%makeinstall DESTDIR=%simqtinstalldir +popd +%endif + +## With KDE ## +%if_enabled simkde +mkdir simkde +pushd simkde +cmake %_builddir/%name-%version \ + -DCMAKE_C_FLAGS:STRING="%optflags" \ + -DCMAKE_CXX_FLAGS:STRING="%optflags" \ + -DCMAKE_INSTALL_PREFIX=%_prefix \ + -DCMAKE_SKIP_RPATH=YES \ + -DUSE_GCC_VISIBILITY=1 \ + -DENABLE_KDE3=1 +%make_build +%makeinstall DESTDIR=%siminstalldir +%endif + +%install +mkdir -p %buildroot/ +cp -a %siminstalldir/* %buildroot/ +cp -a %simqtinstalldir/* %buildroot/ + +%if_enabled simqt +cp %buildroot%_desktopdir/kde/%name.desktop %buildroot%_desktopdir/%name-qt.desktop +%__subst 's,^Exec=sim$,\0-qt,' %buildroot%_desktopdir/%name-qt.desktop +%__subst 's,^Name.*=Sim.*,\0 (without KDE),g' %buildroot%_desktopdir/%name-qt.desktop +%__subst '\,Categ,s,KDE;,,' %buildroot%_desktopdir/%name-qt.desktop +%endif + +rm -rf %buildroot%_libdir/libsim.so +rm -rf %buildroot%_libdir/libsim-qt.so + +%find_lang %name + +%if_enabled simkde +%post +%post_ldconfig +%update_menus +%postun +%postun_ldconfig +%clean_menus +%endif + +%if_enabled simqt +%post qt +%post_ldconfig +%update_menus +%postun qt +%postun_ldconfig +%clean_menus +%endif + +%if_enabled simkde +%files +%_bindir/%name +%_desktopdir/kde/%name.desktop +%_libdir/libsim.so.* +%dir %_libdir/%name +%_libdir/%name/*.so* +%_libdir/%name/styles/ +%endif + +%if_enabled simqt +%files qt +%_bindir/%name-qt +%_desktopdir/%name-qt.desktop +%_libdir/libsim-qt.so.* +%dir %_libdir/%name-qt +%_libdir/%name-qt/*.so* +%_libdir/%name-qt/styles/ +%endif + +%files common -f %name.lang +%_bindir/simctrl +%_datadir/apps/%name +%_datadir/services/simctrl.desktop +%_iconsdir/*/*/*/*.png + +%changelog +* Tue Feb 20 2007 Andrey Rahmatullin 1:0.9.5-alt0.2 +- 0.9.5 r1860 + +* Thu Jan 04 2007 Andrey Rahmatullin 1:0.9.5-alt0.1 +- 0.9.5 r1738 +- Daedalus build +- use CMake +- spec cleanup + +* Sat Oct 21 2006 Andrey Rahmatullin 1:0.9.4.1-alt1 +- 0.9.4.1 +- spec cleanup +- update BuildRequires + +* Thu Jul 06 2006 Andrey Rahmatullin 1:0.9.4-alt14 +- bump release + +* Thu Jun 29 2006 Andrey Rahmatullin 1:0.9.4-alt13 +- 0.9.4 release, finally :) + +* Wed May 03 2006 Andrey Rahmatullin 1:0.9.4-alt12 +- 0.9.4 RC2 + +* Sat Feb 25 2006 Andrey Rahmatullin 1:0.9.4-alt11 +- 0.9.4 RC1 +- update URL +- remove menu file + +* Mon Apr 11 2005 Andrey Rahmatullin 1:0.9.4-alt10 +- update from CVS 20050411 + +* Sat Dec 11 2004 Andrey Rahmatullin 1:0.9.4-alt9 +- update from CVS 20041211 + +* Thu Oct 07 2004 Andrey Rahmatullin 1:0.9.4-alt8.1 +- remove %_datadir/mimelnk/application/x-icq.desktop from sim-common + (#5278) + +* Tue Sep 21 2004 Andrey Rahmatullin 1:0.9.4-alt8 +- CVS 20040921 +- build autoaway plugin since it now doesn't crash +- add ability to build packages for Master 2.2 (use --enable M22) +- all fixes gone upstream + +* Sat Aug 14 2004 Andrey Rahmatullin 1:0.9.4-alt7 +- add Packager: sim@packages.a.o +- do `make clean' between two builds (fixes some segfaults in sim-kde) +- add %%{post,postun}_ldconfig +- update Russian translation for sim-qt +- some fixes + +* Fri Aug 06 2004 Andy Gorev 1:0.9.4-alt6 +- %%packager removed from spec, use ~/.rpmmacros please +- BuildPreReq and BuildReq fixed for build in hasher + +* Mon Aug 02 2004 Andrey Rahmatullin 1:0.9.4-alt5 +- fix buildreqs +- fix Patch4 +- fix Russian translation + +* Mon Jul 26 2004 Andrey Rahmatullin 1:0.9.4-alt4 +- update translations from CVS 20040726 +- add requires: sound_handler (#4314) + +* Thu Jul 22 2004 Andrey Rahmatullin 1:0.9.4-alt3.1 +- update buildreqs +- update obsoletes/conflicts + +* Fri Jul 16 2004 Andrey Rahmatullin 1:0.9.4-alt3 +- CVS 20040716 +- rebuilt without kdelibs-gcc_compiled (#4436) +- menu files fixed (#4312) +- default sound player changed from play to play_wrapper.sh (#4314) +- .so files removed (#4672) +- include all locales (see `fortune ALT -m '19 .*\?'` :)) +- Russian summaries and descriptions added +- add ability to build only sim or sim-qt + (use --disable simqt or --disable simkde) +- do not build autoaway plugin, since it segfaults on exit +- a lot of new features and bugs :( + +* Tue May 11 2004 ALT QA Team Robot 1:0.9.4-alt2.1 +- Rebuilt with openssl-0.9.7d. + +* Tue Apr 27 2004 Albert R. Valiev 1:0.9.4-alt2 +- Fixed contact list information retrieve problem + +* Fri Apr 23 2004 Albert R. Valiev 1:0.9.4-alt1 +- Change Jabber browser +- MSN: Add hotmail notification +- GPG: Add support passphrase +- ICQ: Add packets flow control +- ICQ: Fix send URL and contacts +- ICQ: Fix send large messages +- Redesign search window + +* Mon Mar 29 2004 Albert R. Valiev 1:0.9.3-alt2 +- Fixed Jabber plugin + +* Thu Mar 25 2004 Albert R. Valiev 1:0.9.3-alt1 +- Fixed build scheme +- Release build +- Add LiveJournal plugin +- Jabber: fix send rich-text messages +- ICQ: Fix set birthday flag +- Fix apply custom fonts +- Fix communication-problem with AIM-Screennames > 13 chars +- Fix not receive AuthGrant from some ICQ-users +- Proxy: add support listen sockets for SOCKS4 and SOCKS5 +- Add Yahoo! plugin +- MSN: Fix remove contact +- Add replace text plugin +- Add option "Show/hide empty groups" +- Add weather plugin +- Move plugins from prefix/share into prefix/lib +- Fix acinclude for automake-1.8 +- MSN: add HTTP polling +- Jabber: add HTTP polling +- OSD: add show message content +- Jabber: add select resource for send + +* Thu Mar 18 2004 Albert R. Valiev 1:0.9.3-alt0.2 +- Build from CVS 20040318 +- build scheme change (3 packages from 1 source RPM) +- removed kdebase from requires (#3651) +- removed /usr/share/locale/ru etc. from package (#3502) +- rename libs for kde-disabled build (to make possible installing both builds + simultaneously) +- Very big thanks to Andrey Rahmatullin for new scheme patches + +* Wed Mar 10 2004 Albert R. Valiev 1:0.9.3-alt0.1 +- Build from CVS 20040310 +- Fixed buildrequres + +* Tue Nov 04 2003 Albert R. Valiev 1:0.9.0-alt2 +- Fixed login rate bug in icq plugin + +* Mon Nov 03 2003 Albert R. Valiev 1:0.9.0-alt1 +- sim-0.9.0 release + +* Mon Oct 27 2003 Albert R. Valiev 1:0.9.0-alt0.11 +- Rebuild with 20031027 cvs snapshot + +* Tue Sep 23 2003 Albert R. Valiev 1:0.9.0-alt0.10 +- Fixed conflicts (thanks to Sergey V. Turchin for help + +* Mon Sep 22 2003 Albert R. Valiev 1:0.9.0-alt0.9 +- Now data files are in sim-common package +- Now plugins are in sim-plugins package +- Fixed conflicts and deps + +* Sun Sep 21 2003 Albert R. Valiev 1:0.9.0-alt0.8 +- Added conflicts with sim-qt, libsim-qt, sim-qt-data +- Build from cvs 20030921 + +* Fri Sep 19 2003 Albert R. Valiev 1:0.9.0-alt0.7 +- Fixed depends + +* Thu Sep 18 2003 Albert R. Valiev 1:0.9.0-alt0.6 +- Fixed buildrequires +- Enabled Jabber protocol build + +* Thu Sep 18 2003 Albert R. Valiev 1:0.9.0-alt0.5 +- Build from CVS 20030918 +- translation fixes +- Makefile fixes + +* Sun Sep 14 2003 Albert R. Valiev 1:0.9.0-alt0.4 +- Build from CVS 20030914 + +* Tue Sep 09 2003 Albert R. Valiev 1:0.9.0-alt0.3 +- Build from CVS 20030909 + +* Wed Sep 03 2003 Albert R. Valiev 1:0.9.0-alt0.2 +- Build from CVS 20030903 + +* Fri Aug 29 2003 Albert R. Valiev 1:0.9.0-alt0.1 +- Build from CVS 20030828 + +* Tue Aug 12 2003 Albert R. Valiev 1:0.8.3-alt1 +- 0.8.3 Release build + +* Sat Jun 14 2003 Albert R. Valiev 1:0.8.2-alt1 +- Release build + +* Mon Apr 21 2003 Albert R. Valiev 1:0.8.2-alt0.6 +- BuildRequires fix + +* Tue Apr 15 2003 Albert R. Valiev 1:0.8.2-alt0.5 +- Fixed crash at startup + +* Sun Apr 13 2003 Albert R. Valiev 1:0.8.2-alt0.4 +- New cvs snapshot build +- Fixed bug #0002387 + +* Fri Apr 04 2003 Albert R. Valiev 1:0.8.2-alt0.3 +- Test for bug with libqt3-3.1.2 + +* Mon Mar 17 2003 Albert R. Valiev 1:0.8.2-alt0.2 +- Build cvs snapshot for Sisyphus +- Add Bulgarian translation +- Add Hebrew translation +- Add random chat +- Add settings for groups +- Add GKrellM2 plugin +- Add French translation + +* Mon Feb 24 2003 Albert R. Valiev 1:0.8.2-alt0.1 +- Build cvs snapshot for Daedalus + +* Sun Feb 02 2003 Albert R. Valiev 1:0.8.1-alt1 +- downgrade to sim-0.8.1 + +* Mon Jan 20 2003 Albert R. Valiev 0.9-alt0.5 +- Build cvs snapshot (2003.01.20) + +* Sat Jan 04 2003 Albert R. Valiev 0.9-alt0.4 +- Build cvs snapshot (2003.01.05) + +* Thu Nov 28 2002 Albert R. Valiev 0.9-alt0.3 +- Build CVS Snaphot (fixed some bugs) + +* Sat Nov 16 2002 Albert R. Valiev 0.9-alt0.2 +- menu files attr corrections + +* Tue Nov 12 2002 Albert R. Valiev 0.9-alt0.1 +- Build CVS snapshot (because current version incompatible with glibc) + +* Sat Oct 26 2002 Albert R. Valiev 0.8-alt1 +- New version + +* Wed Oct 9 2002 Albert R. Valiev 0.7-alt3 +- Spec corrections + +* Wed Oct 9 2002 Albert R. Valiev 0.7-alt2 +- Rebuild with new KDE requirements + +* Thu Sep 12 2002 Sergey V Turchin 0.7-alt1 +- initial spec diff --git a/asp-linux.spec b/asp-linux.spec new file mode 100644 index 0000000..b2db56f --- /dev/null +++ b/asp-linux.spec @@ -0,0 +1,169 @@ +%define subversion 1 +%define date 20031105 +%define is_release 1 +%define desktop_file 1 +%define gkrellm 0 + +Summary: SIM - Simple Instant Messenger +Name: sim +Version: 0.9.1 +%if %{is_release} +Release: 1asp +%else +Release: 1.%{date}.1asp +%endif +License: GPL +Url: http://sim-im.berlios.de/ +Group: Applications/Communications +%if %{is_release} +Source: sim-%{version}.tar.bz2 +%else +Source: sim-%{date}.tar.bz2 +%endif +BuildRoot: %{_tmppath}/sim-buildroot +BuildRequires: qt-devel kdelibs-devel arts-devel /usr/bin/dos2unix /usr/bin/perl +%if %{desktop_file} +BuildRequires: desktop-file-utils +%endif + +%description +A simple ICQ client with v8 protocol support (2001) for X win system +(requires QT, can be build for KDE). It also runs under MS Windows. + +%if %{gkrellm} +%package gkrellm +Summary: sim GKrellM2 plugin +Group: Applications/Communications +Requires: gkrellm >= 2.1.0 +Requires: %{name} = %{version}-%{release} + +%description gkrellm +sim GKrellM2 plugin +%endif + +%prep + +%if %{is_release} +%setup +%else +%setup -q -n sim +%endif + +%build + +make -f admin/Makefile.common + +%if %{gkrellm} +%configure +%else +%configure --without-gkrellm_plugin +%endif + +make %{?_smp_mflags} + +%install + +rm -rf %{buildroot} +make install-strip DESTDIR=$RPM_BUILD_ROOT + +# desktop file install + +%if %{desktop_file} +mkdir -p $RPM_BUILD_ROOT/%{_datadir}/applications + +dos2unix $RPM_BUILD_ROOT%{_datadir}/applnk-redhat/Internet/sim.desktop +# perl -pi -e "s|sim.png|licq|g" $RPM_BUILD_ROOT%{_datadir}/applnk-redhat/Internet/sim.desktop + +desktop-file-install --delete-original --vendor net \ + --dir $RPM_BUILD_ROOT%{_datadir}/applications \ + --add-category X-Red-Hat-Base \ + --add-category Network \ + --add-category Application \ + $RPM_BUILD_ROOT%{_datadir}/applnk-redhat/Internet/sim.desktop +%endif + +%find_lang %{name} + +# clean unused files +rm -rf %{buildroot}%{_libdir}/menu + +%clean +rm -rf %{buildroot} + +%files -f %{name}.lang +%defattr(-, root, root, 755) +%doc AUTHORS COPYING README TODO INSTALL +%{_bindir}/sim +%{_libdir}/libsim* +%if %{desktop_file} +%{_datadir}/applications/net-sim.desktop +%else +%{_datadir}/applnk/Internet/sim.desktop +%endif +%dir %{_datadir}/apps/sim +%{_datadir}/apps/sim/COPYING +%dir %{_datadir}/apps/sim/plugins +%dir %{_datadir}/apps/sim/plugins/* +%dir %{_datadir}/apps/sim/pict +%{_datadir}/apps/sim/pict/* +%dir %{_datadir}/apps/sim/sounds +%{_datadir}/apps/sim/sounds/* +%{_datadir}/icons/*/*/*/* + +%if %{gkrellm} +%files gkrellm +%{_libdir}/gkrellm2/plugins/* +%endif + +%changelog + +* Tue Nov 11 2005 Leonid Kanter 0.9.1-1asp +- 0.9.1 + +* Wed Nov 05 2005 Leonid Kanter +- Post-release 20031105 (should fix login problem after icq servers update) + +* Wed Oct 21 2003 Leonid Kanter +- 20031021 + +* Wed Sep 24 2003 Leonid Kanter +- 20030924 + +* Wed Sep 17 2003 Leonid Kanter +- 20030917 + +* Tue Aug 26 2003 Leonid Kanter +- update to 20030826 + +* Mon Jul 28 2003 Leonid Kanter 0.9-cvs +- update to current 0.9 state + +* Sat Apr 26 2003 Leonid Kanter 0.8.2-1asp +- 0.8.2 release + +* Wed Apr 23 2003 Leonid Kanter +- build gkrellm2 plugin as separate package + +* Mon Mar 03 2003 Leonid Kanter +- cvs snapshot 20030303, more improvements in spec + +* Wed Feb 12 2003 Leonid Kanter +- new cvs snapshot, use desktop-file-utils + +* Tue Dec 17 2002 Leon Kanter +- Universal spec, included missed simctrl + +* Tue Dec 17 2002 Leon Kanter +- 0.8.1 + +* Wed Oct 23 2002 Leon Kanter +- Apply fontsize patch from cvs + +* Tue Oct 22 2002 Leon Kanter +- Built official release for asp7.3 + +* Tue Sep 24 2002 Leon Kanter +- this cvs snapshot should fix font-related problems + +* Wed Sep 11 2002 Leon Kanter +- Spec cleanup, built for asplinux%{_bindir}/sim diff --git a/cmake/COPYING-CMAKE-SCRIPTS b/cmake/COPYING-CMAKE-SCRIPTS new file mode 100644 index 0000000..ed45ca7 --- /dev/null +++ b/cmake/COPYING-CMAKE-SCRIPTS @@ -0,0 +1,27 @@ +All provided cmake scripts are distributed under the GNU Public License +version 2 or later, except for scripts that are part of KDE, which are +covered with the following license: + + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/cmake/CheckStructMember.cmake b/cmake/CheckStructMember.cmake new file mode 100644 index 0000000..2f0aabe --- /dev/null +++ b/cmake/CheckStructMember.cmake @@ -0,0 +1,42 @@ +# - Check if the given struct or class has the specified member variable +# CHECK_STRUCT_MEMBER (STRUCT MEMBER HEADER VARIABLE) +# +# STRUCT - the name of the struct or class you are interested in +# MEMBER - the member which existence you want to check +# HEADER - the header(s) where the prototype should be declared +# VARIABLE - variable to store the result +# +# The following variables may be set before calling this macro to +# modify the way the check is run: +# +# CMAKE_REQUIRED_FLAGS = string of compile command line flags +# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar) +# CMAKE_REQUIRED_INCLUDES = list of include directories + +# Copyright (c) 2006, Alexander Neundorf, +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + + +INCLUDE(CheckCXXSourceCompiles) + +MACRO (CHECK_STRUCT_MEMBER _STRUCT _MEMBER _HEADER _RESULT) + SET(_INCLUDE_FILES) + FOREACH (it ${_HEADER}) + SET(_INCLUDE_FILES "${_INCLUDE_FILES}#include <${it}>\n") + ENDFOREACH (it) + + SET(_CHECK_STRUCT_MEMBER_SOURCE_CODE " +${_INCLUDE_FILES} +int main() +{ + ${_STRUCT}* tmp; + tmp->${_MEMBER}; + return 0; +} +") + CHECK_CXX_SOURCE_COMPILES("${_CHECK_STRUCT_MEMBER_SOURCE_CODE}" ${_RESULT}) + +ENDMACRO (CHECK_STRUCT_MEMBER) + diff --git a/cmake/DistTarget.cmake b/cmake/DistTarget.cmake new file mode 100644 index 0000000..773bf22 --- /dev/null +++ b/cmake/DistTarget.cmake @@ -0,0 +1,36 @@ +# dist target +# from cmake wiki, feel free to modify + +SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Sim-IM") +SET(CPACK_PACKAGE_VENDOR "Sim-IM developers") +SET(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README") +SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/COPYING") +SET(CPACK_PACKAGE_VERSION_MAJOR "0") +SET(CPACK_PACKAGE_VERSION_MINOR "9") +SET(CPACK_PACKAGE_VERSION_PATCH "5") +#SET(CPACK_INSTALL_CMAKE_PROJECTS "sim") +SET(CPACK_PACKAGE_INSTALL_DIRECTORY "Sim-IM ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}") + +IF(WIN32 AND NOT UNIX) + SET(CPACK_GENERATOR NSIS) # can be NSIS, STGZ, TBZ2, TGZ, TZ and ZIP + SET(CPACK_NSIS_COMPRESSOR "/SOLID lzma") + # There is a bug in NSI that does not handle full unix paths properly. Make + # sure there is at least one set of four (4) backlasshes. + SET(CPACK_PACKAGE_ICON "${CMAKE_SOURCE_DIR}/install_win32\\\\sim-window-small.bmp") + SET(CPACK_NSIS_INSTALLED_ICON_NAME "sim.exe") + SET(CPACK_NSIS_DISPLAY_NAME "${CPACK_PACKAGE_INSTALL_DIRECTORY}") + SET(CPACK_NSIS_HELP_LINK "http:\\\\\\\\www.sim-im.org") + SET(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\www.sim-im.org") + SET(CPACK_NSIS_CONTACT "sim-im-main@lists.sim-im.org") + + SET(CPACK_SOURCE_GENERATOR "NSIS") + SET(CPACK_SOURCE_IGNORE_FILES "/\\\\.svn/") +ELSE(WIN32 AND NOT UNIX) + SET(CPACK_GENERATOR TBZ2) # can be STGZ, TBZ2, TGZ, TZ and ZIP + + SET(CPACK_SOURCE_GENERATOR "TBZ2;TGZ") + SET(CPACK_SOURCE_IGNORE_FILES "/install_win32/" "/sim/win32/" "/\\\\.svn/") +ENDIF(WIN32 AND NOT UNIX) +SET(CPACK_PACKAGE_EXECUTABLES "sim" "sim") + +INCLUDE(CPack) diff --git a/cmake/FindFlex.cmake b/cmake/FindFlex.cmake new file mode 100644 index 0000000..aa72e0e --- /dev/null +++ b/cmake/FindFlex.cmake @@ -0,0 +1,32 @@ +# - Try to find Flex +# Once done this will define +# +# FLEX_FOUND - system has Flex +# FLEX_EXECUTABLE - path of the flex executable +# FLEX_VERSION - the version string, like "2.5.31" +# + + +FIND_PROGRAM(FLEX_EXECUTABLE NAMES flex) + +INCLUDE(MacroEnsureVersion) + +IF(FLEX_EXECUTABLE) + SET(FLEX_FOUND TRUE) + + EXECUTE_PROCESS(COMMAND ${FLEX_EXECUTABLE} --version + OUTPUT_VARIABLE _FLEX_VERSION + ) + string (REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" FLEX_VERSION "${_FLEX_VERSION}") +ENDIF(FLEX_EXECUTABLE) + +IF(FLEX_FOUND) + IF(NOT Flex_FIND_QUIETLY) + MESSAGE(STATUS "Found Flex: ${FLEX_EXECUTABLE}") + ENDIF(NOT Flex_FIND_QUIETLY) +ELSE(FLEX_FOUND) + IF(Flex_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could not find Flex") + ENDIF(Flex_FIND_REQUIRED) +ENDIF(FLEX_FOUND) + diff --git a/cmake/FindLibIconv.cmake b/cmake/FindLibIconv.cmake new file mode 100644 index 0000000..85c74fa --- /dev/null +++ b/cmake/FindLibIconv.cmake @@ -0,0 +1,40 @@ +# - Try to find LibIconv +# Once done this will define +# +# LIBICONV_FOUND - system has LibIconv +# LIBICONV_INCLUDE_DIR - the LibIconv include directory +# LIBICONV_LIBRARIES - the libraries needed to use LibIconv +# LIBICONV_DEFINITIONS - Compiler switches required for using LibIconv + +if (LIBICONV_INCLUDE_DIR AND LIBICONV_LIBRARIES) + + # in cache already + SET(LIBICONV_FOUND TRUE) + +else (LIBICONV_INCLUDE_DIR AND LIBICONV_LIBRARIES) + + IF (NOT WIN32) + MESSAGE(FATAL_ERROR "Please set this to the correct values!") + # use pkg-config to get the directories and then use these values + # in the FIND_PATH() and FIND_LIBRARY() calls + INCLUDE(UsePkgConfig) + PKGCONFIG(libiconv-1.9 _LibIconvIncDir _LibIconvLinkDir _LibIconvLinkFlags _LiIconvCflags) + SET(LIBICONV_DEFINITIONS ${_LibIconvCflags}) + ENDIF (NOT WIN32) + + FIND_PATH(LIBICONV_INCLUDE_DIR iconv.h + PATHS + ${_LibIconvIncDir} + PATH_SUFFIXES libiconv + ) + + FIND_LIBRARY(LIBICONV_LIBRARIES NAMES iconv iconv-2 libiconv libiconv-2 + PATHS + ${_LibIconvLinkDir} + ) + + FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibIconv DEFAULT_MSG LIBICONV_INCLUDE_DIR LIBICONV_LIBRARIES) + + MARK_AS_ADVANCED(LIBICONV_INCLUDE_DIR LIBICONV_LIBRARIES) + +endif (LIBICONV_INCLUDE_DIR AND LIBICONV_LIBRARIES) diff --git a/cmake/FindLibraryWithDebug.cmake b/cmake/FindLibraryWithDebug.cmake new file mode 100644 index 0000000..07602e1 --- /dev/null +++ b/cmake/FindLibraryWithDebug.cmake @@ -0,0 +1,113 @@ +# +# FIND_LIBRARY_WITH_DEBUG +# -> enhanced FIND_LIBRARY to allow the search for an +# optional debug library with a WIN32_DEBUG_POSTFIX similar +# to CMAKE_DEBUG_POSTFIX when creating a shared lib +# it has to be the second and third argument + +# Copyright (c) 2007, Christian Ehrlicher, +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +MACRO(FIND_LIBRARY_WITH_DEBUG var_name win32_dbg_postfix_name dgb_postfix libname) + + IF(NOT "${win32_dbg_postfix_name}" STREQUAL "WIN32_DEBUG_POSTFIX") + + # no WIN32_DEBUG_POSTFIX -> simply pass all arguments to FIND_LIBRARY + FIND_LIBRARY(${var_name} + ${win32_dbg_postfix_name} + ${dgb_postfix} + ${libname} + ${ARGN} + ) + + ELSE(NOT "${win32_dbg_postfix_name}" STREQUAL "WIN32_DEBUG_POSTFIX") + + IF(NOT WIN32) + # on non-win32 we don't need to take care about WIN32_DEBUG_POSTFIX + + FIND_LIBRARY(${var_name} ${libname} ${ARGN}) + + ELSE(NOT WIN32) + + # 1. get all possible libnames + SET(args ${ARGN}) + SET(newargs "") + SET(libnames_release "") + SET(libnames_debug "") + + LIST(LENGTH args listCount) + + IF("${libname}" STREQUAL "NAMES") + SET(append_rest 0) + LIST(APPEND args " ") + + FOREACH(i RANGE ${listCount}) + LIST(GET args ${i} val) + + IF(append_rest) + LIST(APPEND newargs ${val}) + ELSE(append_rest) + IF("${val}" STREQUAL "PATHS") + LIST(APPEND newargs ${val}) + SET(append_rest 1) + ELSE("${val}" STREQUAL "PATHS") + LIST(APPEND libnames_release "${val}") + LIST(APPEND libnames_debug "${val}${dgb_postfix}") + ENDIF("${val}" STREQUAL "PATHS") + ENDIF(append_rest) + + ENDFOREACH(i) + + ELSE("${libname}" STREQUAL "NAMES") + + # just one name + LIST(APPEND libnames_release "${libname}") + LIST(APPEND libnames_debug "${libname}${dgb_postfix}") + + SET(newargs ${args}) + + ENDIF("${libname}" STREQUAL "NAMES") + + # search the release lib + FIND_LIBRARY(${var_name}_RELEASE + NAMES ${libnames_release} + ${newargs} + ) + + # search the debug lib + FIND_LIBRARY(${var_name}_DEBUG + NAMES ${libnames_debug} + ${newargs} + ) + + IF(${var_name}_RELEASE AND ${var_name}_DEBUG) + + # both libs found + SET(${var_name} optimized ${${var_name}_RELEASE} + debug ${${var_name}_DEBUG}) + + ELSE(${var_name}_RELEASE AND ${var_name}_DEBUG) + + IF(${var_name}_RELEASE) + + # only release found + SET(${var_name} ${${var_name}_RELEASE}) + + ELSE(${var_name}_RELEASE) + + # only debug (or nothing) found + SET(${var_name} ${${var_name}_DEBUG}) + + ENDIF(${var_name}_RELEASE) + + ENDIF(${var_name}_RELEASE AND ${var_name}_DEBUG) + + MARK_AS_ADVANCED(${var_name}_RELEASE) + MARK_AS_ADVANCED(${var_name}_DEBUG) + + ENDIF(NOT WIN32) + + ENDIF(NOT "${win32_dbg_postfix_name}" STREQUAL "WIN32_DEBUG_POSTFIX") + +ENDMACRO(FIND_LIBRARY_WITH_DEBUG) diff --git a/cmake/FindOpenSSL.cmake b/cmake/FindOpenSSL.cmake new file mode 100644 index 0000000..7c61fb8 --- /dev/null +++ b/cmake/FindOpenSSL.cmake @@ -0,0 +1,63 @@ +# - Try to find the OpenSSL encryption library +# Once done this will define +# +# OPENSSL_FOUND - system has the OpenSSL library +# OPENSSL_INCLUDE_DIR - the OpenSSL include directory +# OPENSSL_LIBRARIES - The libraries needed to use OpenSSL +# OPENSSL_EAY_LIBRARIES - The additional libraries needed to use OpenSSL on windows + +# Copyright (c) 2006, Alexander Neundorf, +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +INCLUDE(FindLibraryWithDebug) + +# on win32 we additional need to link to libeay32.lib +MACRO(OPENSSL_ADD_LIB_EAY_LIBS) + FIND_LIBRARY_WITH_DEBUG(OPENSSL_EAY_LIBRARIES + WIN32_DEBUG_POSTFIX d + NAMES eay crypto libeay libeay32 libeay32MD) +ENDMACRO(OPENSSL_ADD_LIB_EAY_LIBS) + +IF(OPENSSL_LIBRARIES) + SET(OpenSSL_FIND_QUIETLY TRUE) +ENDIF(OPENSSL_LIBRARIES) + +IF(SSL_EAY_DEBUG AND SSL_EAY_RELEASE) + SET(LIB_FOUND 1) +ENDIF(SSL_EAY_DEBUG AND SSL_EAY_RELEASE) + +FIND_PATH(OPENSSL_INCLUDE_DIR openssl/ssl.h ) + +FIND_LIBRARY_WITH_DEBUG(OPENSSL_LIBRARIES + WIN32_DEBUG_POSTFIX d + NAMES ssl libssl libssl32 ssleay ssleay32 libssleay32 ssleay32MD) + +IF(WIN32 OR APPLE) + OPENSSL_ADD_LIB_EAY_LIBS() + IF(OPENSSL_INCLUDE_DIR AND OPENSSL_LIBRARIES AND OPENSSL_EAY_LIBRARIES) + SET(OPENSSL_FOUND TRUE) + ELSE(OPENSSL_INCLUDE_DIR AND OPENSSL_LIBRARIES AND OPENSSL_EAY_LIBRARIES) + SET(OPENSSL_FOUND FALSE) + ENDIF (OPENSSL_INCLUDE_DIR AND OPENSSL_LIBRARIES AND OPENSSL_EAY_LIBRARIES) +ELSE(WIN32 OR APPLE) + IF(OPENSSL_INCLUDE_DIR AND OPENSSL_LIBRARIES) + SET(OPENSSL_FOUND TRUE) + ELSE(OPENSSL_INCLUDE_DIR AND OPENSSL_LIBRARIES) + SET(OPENSSL_FOUND FALSE) + ENDIF (OPENSSL_INCLUDE_DIR AND OPENSSL_LIBRARIES) +ENDIF(WIN32 OR APPLE) + +IF (OPENSSL_FOUND) + IF (NOT OpenSSL_FIND_QUIETLY) + MESSAGE(STATUS "Found OpenSSL: ${OPENSSL_LIBRARIES}") + ENDIF (NOT OpenSSL_FIND_QUIETLY) +ELSE (OPENSSL_FOUND) + IF (OpenSSL_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could NOT find OpenSSL") + ENDIF (OpenSSL_FIND_REQUIRED) +ENDIF (OPENSSL_FOUND) + +MARK_AS_ADVANCED(OPENSSL_INCLUDE_DIR OPENSSL_LIBRARIES) + diff --git a/cmake/Flex.cmake b/cmake/Flex.cmake new file mode 100644 index 0000000..dbcaeb4 --- /dev/null +++ b/cmake/Flex.cmake @@ -0,0 +1,26 @@ +# flex a .ll file + +INCLUDE(FindFlex) + + +MACRO(ADD_FLEX_FILES _sources ) + FIND_PACKAGE(Flex QUIET REQUIRED) + + FOREACH (_current_FILE ${ARGN}) + GET_FILENAME_COMPONENT(_in ${_current_FILE} ABSOLUTE) + GET_FILENAME_COMPONENT(_basename ${_current_FILE} NAME_WE) + + SET(_out ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.cpp) + + ADD_CUSTOM_COMMAND( + OUTPUT ${_out} + COMMAND ${FLEX_EXECUTABLE} + ARGS + -o${_out} + ${_in} + DEPENDS ${_in} + ) + + SET(${_sources} ${${_sources}} ${_out} ) + ENDFOREACH (_current_FILE) +ENDMACRO(ADD_FLEX_FILES) diff --git a/cmake/Jisp.cmake b/cmake/Jisp.cmake new file mode 100644 index 0000000..5f3661c --- /dev/null +++ b/cmake/Jisp.cmake @@ -0,0 +1,49 @@ +# a small macro to create one or more jisp archives +# ADD_JISP_ARCHIVE(jisp-subdir) + +# search zip +MACRO(FIND_ZIP) + IF(NOT ZIP_EXECUTABLE) + FIND_PROGRAM(ZIP_EXECUTABLE zip) + IF (NOT ZIP_EXECUTABLE) + MESSAGE(FATAL_ERROR "zip not found - aborting") + ENDIF (NOT ZIP_EXECUTABLE) + ENDIF(NOT ZIP_EXECUTABLE) +ENDMACRO(FIND_ZIP) + + +MACRO(ADD_JISP_ARCHIVE subdir jisp_name _sources) + FIND_ZIP() + + GET_FILENAME_COMPONENT(_in_dir ${CMAKE_CURRENT_SOURCE_DIR}/${subdir}/icondef.xml PATH) + + IF(EXISTS ${_in_dir}/icondef.xml) + FILE(GLOB _in ${_in_dir}/*.png) + SET(_in ${_in} ${_in_dir}/icondef.xml) + + IF(WIN32) + GET_FILENAME_COMPONENT(_out ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/icons/${jisp_name} ABSOLUTE) + ELSE(WIN32) + IF(APPLE) + GET_FILENAME_COMPONENT(_out ${SIM_ICONS_DIR}/${jisp_name} ABSOLUTE) + ELSE(APPLE) + GET_FILENAME_COMPONENT(_out ${CMAKE_CURRENT_BINARY_DIR}/${jisp_name} ABSOLUTE) + ENDIF(APPLE) + ENDIF(WIN32) + + FILE(WRITE ${_out}.files "") + FOREACH(_file ${_in}) + FILE(APPEND ${_out}.files "${_file}\n") + ENDFOREACH(_file ${_in}) + + ADD_CUSTOM_COMMAND( + OUTPUT ${_out} + COMMAND ${ZIP_EXECUTABLE} + -j -q -9 ${_out} -@ < ${_out}.files + DEPENDS ${_in} + ) + SET(${_sources} ${${_sources}} ${_out}) + + INSTALL(FILES ${_out} DESTINATION ${SIM_ICONS_DIR}) + ENDIF(EXISTS ${_in_dir}/icondef.xml) +ENDMACRO(ADD_JISP_ARCHIVE) diff --git a/cmake/KDE4InstallIcons.cmake b/cmake/KDE4InstallIcons.cmake new file mode 100644 index 0000000..4ea30d6 --- /dev/null +++ b/cmake/KDE4InstallIcons.cmake @@ -0,0 +1,130 @@ +# from /trunk/KDE/kdelibs/cmake/modules/KDE4Macros.cmake + +# Copyright (c) 2006, Alexander Neundorf, +# Copyright (c) 2006, Laurent Montel, +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +# only used internally by KDE4_INSTALL_ICONS +MACRO (_KDE4_ADD_ICON_INSTALL_RULE _install_SCRIPT _install_PATH _group _orig_NAME _install_NAME) + + # if the string doesn't match the pattern, the result is the full string, so all three have the same content + IF (NOT ${_group} STREQUAL ${_install_NAME} ) + SET(_icon_GROUP "actions") + + IF (${_group} STREQUAL "mime") + SET(_icon_GROUP "mimetypes") + ENDIF (${_group} STREQUAL "mime") + + IF (${_group} STREQUAL "filesys") + SET(_icon_GROUP "filesystems") + ENDIF (${_group} STREQUAL "filesys") + + IF (${_group} STREQUAL "device") + SET(_icon_GROUP "devices") + ENDIF (${_group} STREQUAL "device") + + IF (${_group} STREQUAL "app") + SET(_icon_GROUP "apps") + ENDIF (${_group} STREQUAL "app") + + IF (${_group} STREQUAL "action") + SET(_icon_GROUP "actions") + ENDIF (${_group} STREQUAL "action") + +# message(STATUS "icon: ${_current_ICON} size: ${_size} group: ${_group} name: ${_name}" ) + INSTALL(FILES ${_orig_NAME} DESTINATION ${_install_PATH}/${_icon_GROUP}/ RENAME ${_install_NAME} ) + ENDIF (NOT ${_group} STREQUAL ${_install_NAME} ) + +ENDMACRO (_KDE4_ADD_ICON_INSTALL_RULE) + + +macro (KDE4_INSTALL_ICONS _defaultpath ) + + # first the png icons + file(GLOB _icons *.png) + foreach (_current_ICON ${_icons} ) + string(REGEX REPLACE "^.*/([a-zA-Z]+)([0-9]+)\\-([a-z]+)\\-(.+\\.png)$" "\\1" _type "${_current_ICON}") + string(REGEX REPLACE "^.*/([a-zA-Z]+)([0-9]+)\\-([a-z]+)\\-(.+\\.png)$" "\\2" _size "${_current_ICON}") + string(REGEX REPLACE "^.*/([a-zA-Z]+)([0-9]+)\\-([a-z]+)\\-(.+\\.png)$" "\\3" _group "${_current_ICON}") + string(REGEX REPLACE "^.*/([a-zA-Z]+)([0-9]+)\\-([a-z]+)\\-(.+\\.png)$" "\\4" _name "${_current_ICON}") + set(_theme_GROUP "nogroup") + if( ${_type} STREQUAL "cr" ) + set(_theme_GROUP "crystalsvg") + endif(${_type} STREQUAL "cr" ) + + if( ${_type} STREQUAL "lo" ) + set(_theme_GROUP "locolor") + endif(${_type} STREQUAL "lo" ) + + if( ${_type} STREQUAL "hi" ) + set(_theme_GROUP "hicolor") + endif(${_type} STREQUAL "hi" ) + + if( NOT ${_theme_GROUP} STREQUAL "nogroup") + _KDE4_ADD_ICON_INSTALL_RULE(${CMAKE_CURRENT_BINARY_DIR}/install_icons.cmake + ${_defaultpath}/${_theme_GROUP}/${_size}x${_size} + ${_group} ${_current_ICON} ${_name}) + endif( NOT ${_theme_GROUP} STREQUAL "nogroup") + + endforeach (_current_ICON) + + # mng icons + file(GLOB _icons *.mng) + foreach (_current_ICON ${_icons} ) + STRING(REGEX REPLACE "^.*/([a-zA-Z]+)([0-9]+)\\-([a-z]+)\\-(.+\\.mng)$" "\\1" _type "${_current_ICON}") + STRING(REGEX REPLACE "^.*/([a-zA-Z]+)([0-9]+)\\-([a-z]+)\\-(.+\\.mng)$" "\\2" _size "${_current_ICON}") + STRING(REGEX REPLACE "^.*/([a-zA-Z]+)([0-9]+)\\-([a-z]+)\\-(.+\\.mng)$" "\\3" _group "${_current_ICON}") + STRING(REGEX REPLACE "^.*/([a-zA-Z]+)([0-9]+)\\-([a-z]+)\\-(.+\\.mng)$" "\\4" _name "${_current_ICON}") + SET(_theme_GROUP "nogroup") + if( ${_type} STREQUAL "cr" ) + SET(_theme_GROUP "crystalsvg") + endif(${_type} STREQUAL "cr" ) + + if( ${_type} STREQUAL "lo" ) + set(_theme_GROUP "locolor") + endif(${_type} STREQUAL "lo" ) + + if( ${_type} STREQUAL "hi" ) + set(_theme_GROUP "hicolor") + endif(${_type} STREQUAL "hi" ) + + if( NOT ${_theme_GROUP} STREQUAL "nogroup") + _KDE4_ADD_ICON_INSTALL_RULE(${CMAKE_CURRENT_BINARY_DIR}/install_icons.cmake + ${_defaultpath}/${_theme_GROUP}/${_size}x${_size} + ${_group} ${_current_ICON} ${_name}) + endif( NOT ${_theme_GROUP} STREQUAL "nogroup") + + endforeach (_current_ICON) + + + # and now the svg icons + file(GLOB _icons *.svgz) + foreach (_current_ICON ${_icons} ) + STRING(REGEX REPLACE "^.*/([a-zA-Z]+)sc\\-([a-z]+)\\-(.+\\.svgz)$" "\\1" _type "${_current_ICON}") + STRING(REGEX REPLACE "^.*/([a-zA-Z]+)sc\\-([a-z]+)\\-(.+\\.svgz)$" "\\2" _group "${_current_ICON}") + STRING(REGEX REPLACE "^.*/([a-zA-Z]+)sc\\-([a-z]+)\\-(.+\\.svgz)$" "\\3" _name "${_current_ICON}") + SET(_theme_GROUP "nogroup") + + if(${_type} STREQUAL "lo" ) + SET(_theme_GROUP "locolor") + endif(${_type} STREQUAL "lo" ) + + if(${_type} STREQUAL "cr" ) + SET(_theme_GROUP "crystalsvg") + endif(${_type} STREQUAL "cr" ) + + if(${_type} STREQUAL "hi" ) + SET(_theme_GROUP "hicolor") + endif(${_type} STREQUAL "hi" ) + + if( NOT ${_theme_GROUP} STREQUAL "nogroup") + _KDE4_ADD_ICON_INSTALL_RULE(${CMAKE_CURRENT_BINARY_DIR}/install_icons.cmake + ${_defaultpath}/${_theme_GROUP}/scalable + ${_group} ${_current_ICON} ${_name}) + endif( NOT ${_theme_GROUP} STREQUAL "nogroup") + + endforeach (_current_ICON) + +endmacro (KDE4_INSTALL_ICONS) diff --git a/cmake/MacroBoolTo01.cmake b/cmake/MacroBoolTo01.cmake new file mode 100644 index 0000000..9dbbffd --- /dev/null +++ b/cmake/MacroBoolTo01.cmake @@ -0,0 +1,20 @@ +# MACRO_BOOL_TO_01( VAR RESULT0 ... RESULTN ) +# This macro evaluates its first argument +# and sets all the given vaiables either to 0 or 1 +# depending on the value of the first one + +# Copyright (c) 2006, Alexander Neundorf, +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + + +MACRO(MACRO_BOOL_TO_01 FOUND_VAR ) + FOREACH (_current_VAR ${ARGN}) + IF(${FOUND_VAR}) + SET(${_current_VAR} 1) + ELSE(${FOUND_VAR}) + SET(${_current_VAR} 0) + ENDIF(${FOUND_VAR}) + ENDFOREACH(_current_VAR) +ENDMACRO(MACRO_BOOL_TO_01) diff --git a/cmake/MacroEnsureOutOfSourceBuild.cmake b/cmake/MacroEnsureOutOfSourceBuild.cmake new file mode 100644 index 0000000..ef4d525 --- /dev/null +++ b/cmake/MacroEnsureOutOfSourceBuild.cmake @@ -0,0 +1,16 @@ +# - MACRO_ENSURE_OUT_OF_SOURCE_BUILD() +# MACRO_ENSURE_OUT_OF_SOURCE_BUILD() + +# Copyright (c) 2006, Alexander Neundorf, +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +MACRO (MACRO_ENSURE_OUT_OF_SOURCE_BUILD _errorMessage) + + STRING(COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" insource) + IF(insource) + MESSAGE(FATAL_ERROR "${_errorMessage}") + ENDIF(insource) + +ENDMACRO (MACRO_ENSURE_OUT_OF_SOURCE_BUILD) diff --git a/cmake/MacroEnsureVersion.cmake b/cmake/MacroEnsureVersion.cmake new file mode 100644 index 0000000..2d5c1a0 --- /dev/null +++ b/cmake/MacroEnsureVersion.cmake @@ -0,0 +1,35 @@ +# This macro compares version numbers of the form "x.y.z" +# MACRO_ENSURE_VERSION( FOO_MIN_VERSION FOO_VERSION_FOUND FOO_VERSION_OK) +# will set FOO_VERSIN_OK to true if FOO_VERSION_FOUND >= FOO_MIN_VERSION +# where both have to be in a 3-part-version format, leading and trailing +# text is ok, e.g. +# MACRO_ENSURE_VERSION( "2.5.31" "flex 2.5.4a" VERSION_OK) +# which means 2.5.31 is required and "flex 2.5.4a" is what was found on the system + +# Copyright (c) 2006, David Faure, +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +MACRO(MACRO_ENSURE_VERSION requested_version found_version var_too_old) + + # parse the parts of the version string + STRING(REGEX REPLACE "([0-9]+)\\.[0-9]+\\.[0-9]+" "\\1" req_major_vers "${requested_version}") + STRING(REGEX REPLACE "[0-9]+\\.([0-9]+)\\.[0-9]+" "\\1" req_minor_vers "${requested_version}") + STRING(REGEX REPLACE "[0-9]+\\.[0-9]+\\.([0-9]+)" "\\1" req_patch_vers "${requested_version}") + + STRING(REGEX REPLACE "([0-9]+)\\.[0-9]+\\.[0-9]+.*" "\\1" found_major_vers "${found_version}") + STRING(REGEX REPLACE "[0-9]+\\.([0-9]+)\\.[0-9]+.*" "\\1" found_minor_vers "${found_version}") + STRING(REGEX REPLACE "[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" found_patch_vers "${found_version}") + + # compute an overall version number which can be compared at once + MATH(EXPR req_vers_num "${req_major_vers}*10000 + ${req_minor_vers}*100 + ${req_patch_vers}") + MATH(EXPR found_vers_num "${found_major_vers}*10000 + ${found_minor_vers}*100 + ${found_patch_vers}") + + if (found_vers_num LESS req_vers_num) + set( ${var_too_old} FALSE ) + else (found_vers_num LESS req_vers_num) + set( ${var_too_old} TRUE ) + endif (found_vers_num LESS req_vers_num) + +ENDMACRO(MACRO_ENSURE_VERSION) diff --git a/cmake/Po.cmake b/cmake/Po.cmake new file mode 100644 index 0000000..1904163 --- /dev/null +++ b/cmake/Po.cmake @@ -0,0 +1,98 @@ +# a small macro to create mo files out of po's + +MACRO(FIND_MSGFMT) + IF(NOT MSGFMT_EXECUTABLE) + IF(NOT MSGFMT_NOT_FOUND) + IF(WIN32) + SET(MSGFMT_NAME "msg2qm") + ELSE(WIN32) + SET(MSGFMT_NAME "msgfmt") + ENDIF(WIN32) + FIND_PROGRAM(MSGFMT_EXECUTABLE ${MSGFMT_NAME}) + + IF (NOT MSGFMT_EXECUTABLE) + SET(MSGFMT_NAME "msgfmt") + FIND_PROGRAM(MSGFMT_EXECUTABLE ${MSGFMT_NAME}) + ENDIF(NOT MSGFMT_EXECUTABLE) + + IF (NOT MSGFMT_EXECUTABLE) + MESSAGE(FATAL_ERROR "${MSGFMT_NAME} not found - po files can't be processed") + SET(MSGFMT_NOT_FOUND "1") # to avoid double checking in one cmake run + ENDIF (NOT MSGFMT_EXECUTABLE) + + MARK_AS_ADVANCED(MSGFMT_EXECUTABLE) + ENDIF(NOT MSGFMT_NOT_FOUND) + ENDIF(NOT MSGFMT_EXECUTABLE) +ENDMACRO(FIND_MSGFMT) + +MACRO(COMPILE_PO_FILES po_subdir _sources) + FIND_MSGFMT() + + IF(MSGFMT_EXECUTABLE) + FILE(GLOB po_files ${po_subdir}/*.po) + + FOREACH(po_input ${po_files}) + + GET_FILENAME_COMPONENT(_in ${po_input} ABSOLUTE) + GET_FILENAME_COMPONENT(_basename ${po_input} NAME_WE) + + IF(WIN32) + FILE(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/po) + GET_FILENAME_COMPONENT(_out ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/po/${_basename}.qm ABSOLUTE) + FILE(TO_NATIVE_PATH ${_in} _in_native) + FILE(TO_NATIVE_PATH ${_out} _out_native) + GET_FILENAME_COMPONENT(_tmp ${MSGFMT_EXECUTABLE} NAME_WE) + + IF("${_tmp}" STREQUAL "msg2qm") + ADD_CUSTOM_COMMAND( + OUTPUT ${_out} + COMMAND ${CMAKE_COMMAND} + -E echo + "Generating" ${_out_native} "from" ${_in_native} + COMMAND ${MSGFMT_EXECUTABLE} + ${_in_native} + ${_out_native} + DEPENDS ${_in} + ) + ELSE("${_tmp}" STREQUAL "msg2qm") + ADD_CUSTOM_COMMAND( + OUTPUT ${_out} + COMMAND ${CMAKE_COMMAND} + -E echo + "Generating" ${_out_native} "from" ${_in_native} + COMMAND ${MSGFMT_EXECUTABLE} + --qt + ${_in_native} + -o + ${_out_native} + DEPENDS ${_in} + ) + ENDIF("${_tmp}" STREQUAL "msg2qm") + ELSE(WIN32) + FILE(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/po) + GET_FILENAME_COMPONENT(_out ${CMAKE_CURRENT_BINARY_DIR}/po/${_basename}.mo ABSOLUTE) + + ADD_CUSTOM_COMMAND( + OUTPUT ${_out} + COMMAND ${CMAKE_COMMAND} + -E echo + "Generating" ${_out} "from" ${_in} + COMMAND ${MSGFMT_EXECUTABLE} + ${_in} + -o ${_out} + DEPENDS ${_in} + ) + ENDIF(WIN32) + SET(mo_files ${mo_files} ${_out}) + + IF(NOT WIN32) + INSTALL(FILES ${_out} DESTINATION ${SIM_I18N_DIR}/${_basename}/LC_MESSAGES RENAME sim.mo) + ENDIF(NOT WIN32) + ENDFOREACH(po_input ${po_files}) + + IF(WIN32) + INSTALL(FILES ${mo_files} DESTINATION ${SIM_I18N_DIR}) + ENDIF(WIN32) + SET(${_sources} ${${_sources}} ${mo_files}) + ENDIF(MSGFMT_EXECUTABLE) +ENDMACRO(COMPILE_PO_FILES po_subdir) diff --git a/cmake/SimPlugins.cmake b/cmake/SimPlugins.cmake new file mode 100644 index 0000000..2e50bef --- /dev/null +++ b/cmake/SimPlugins.cmake @@ -0,0 +1,76 @@ +# Searching and enabling plugins +MACRO(SIM_ADD_PLUGIN _name) + PROJECT(${_name}) + + SET(_srcs ${${_name}_SRCS}) + SET(_hdrs ${${_name}_HDRS}) + SET(_uics ${${_name}_UICS}) + SET(_libs ${${_name}_LIBS}) + + SET(${_name}_MESSAGE_SOURCES ${_srcs} ${_uics} PARENT_SCOPE) + + QT4_WRAP_CPP(_mocs ${_hdrs}) + QT4_WRAP_UI(_uis ${_uics}) + + SOURCE_GROUP(UI-Files FILES ${_uics}) + SOURCE_GROUP(MOC-Files FILES ${_mocs}) + + ADD_LIBRARY(${_name} SHARED ${_srcs} ${_hdrs} ${_mocs} ${_uis}) + + INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) + + TARGET_LINK_LIBRARIES(${_name} simlib ${_libs}) + + SET_TARGET_PROPERTIES(${_name} PROPERTIES PREFIX "") + + STRING(TOUPPER ${_name} _NAME) + SET_TARGET_PROPERTIES(${_name} PROPERTIES DEFINE_SYMBOL MAKE_${_NAME}_LIB) + + INSTALL(TARGETS ${_name} LIBRARY DESTINATION ${SIM_PLUGIN_DIR} RUNTIME DESTINATION ${SIM_PLUGIN_DIR}) + + IF(APPLE) + SET(LIBRARY_OUTPUT_PATH ${SIM_PLUGIN_DIR}) + ENDIF(APPLE) +ENDMACRO(SIM_ADD_PLUGIN) + +MACRO(SIM_FIND_PLUGINS sim_plugin_dir) + FILE(GLOB plugins_dir ${sim_plugin_dir}/* ) + FOREACH(_cur_dir ${plugins_dir}) + FILE(GLOB cmakefile ${_cur_dir}/CMakeLists.txt) + IF(cmakefile) + GET_FILENAME_COMPONENT(plugin ${_cur_dir} NAME_WE) + + STRING(TOUPPER ${plugin} uc_plugin) + OPTION(ENABLE_PLUGIN_${uc_plugin} "Enable plugin ${plugin}" ON) + + # all plugins starting with _ are *not* optional! + IF(${uc_plugin} MATCHES "^_.*$") + ## prepend + SET(SIM_PLUGINS ${plugin} ${SIM_PLUGINS}) + MARK_AS_ADVANCED(ENABLE_PLUGIN_${uc_plugin}) + ELSE(${uc_plugin} MATCHES "^_.*$") + ## append + SET(SIM_PLUGINS ${SIM_PLUGINS} ${plugin}) + ENDIF(${uc_plugin} MATCHES "^_.*$") + + LIST(SORT SIM_PLUGINS) + ENDIF(cmakefile) + ENDFOREACH(_cur_dir) +ENDMACRO(SIM_FIND_PLUGINS sim_plugin_dir) + +MACRO(SIM_INCLUDE_PLUGINS) + FOREACH(plugin ${SIM_PLUGINS}) + STRING(TOUPPER ${plugin} uc_plugin) + IF(ENABLE_PLUGIN_${uc_plugin}) + MESSAGE(STATUS "Using plugin " ${plugin}) + ADD_SUBDIRECTORY(plugins/${plugin}) + ELSE(ENABLE_PLUGIN_${uc_plugin}) + IF ( ENABLE_TARGET_UPDATE_MESSAGES ) + MESSAGE(STATUS "Using plugin " ${plugin} " for message updating purposes only...") + ADD_SUBDIRECTORY(plugins/${plugin} EXCLUDE_FROM_ALL) + ELSE( ENABLE_TARGET_UPDATE_MESSAGES) + MESSAGE(STATUS "Skipping plugin " ${plugin}) + ENDIF( ENABLE_TARGET_UPDATE_MESSAGES ) + ENDIF(ENABLE_PLUGIN_${uc_plugin}) + ENDFOREACH(plugin ${SIM_PLUGINS}) +ENDMACRO(SIM_INCLUDE_PLUGINS) diff --git a/cmake/XGetText.cmake b/cmake/XGetText.cmake new file mode 100644 index 0000000..cd63e70 --- /dev/null +++ b/cmake/XGetText.cmake @@ -0,0 +1,65 @@ +SET(XGETTEXT_OPTIONS -j --foreign-user -C -ci18n -ki18n -ktr2i18n -kI18N_NOOP -kI18N_NOOP2 -kaliasLocale) + +FIND_PROGRAM(XGETTEXT_EXECUTABLE kde-xgettext) +IF (XGETTEXT_EXECUTABLE) + MESSAGE(STATUS "Found kde-xgettext: ${XGETTEXT_EXECUTABLE}") +ELSE() + MESSAGE(SATUS "kde-xgettext not found") +ENDIF() + +FIND_PROGRAM(MSGMERGE_EXECUTABLE msgmerge) +IF (MSGMERGE_EXECUTABLE) + MESSAGE(STATUS "Found msgmerge: ${MSGMERGE_EXECUTABLE}") +ELSE() + MESSAGE(STATUS "msgmerge not found") +ENDIF() + +MACRO(EXTRACT_MESSAGES src_file po_file) + SET(PROJECT_NAME Sim-IM) # Change this if you move this file to another project + + SET(fake_ui_cpp_root "${CMAKE_CURRENT_BINARY_DIR}/fake_ui_cpp") + + IF(IS_ABSOLUTE ${src_file}) + FILE(RELATIVE_PATH relative_name ${${PROJECT_NAME}_SOURCE_DIR} ${src_file}) + ELSE(IS_ABSOLUTE ${src_file}) + SET(relative_name ${src_file}) + ENDIF(IS_ABSOLUTE ${src_file}) + + GET_FILENAME_COMPONENT(ext ${relative_name} EXT) + IF(ext STREQUAL .ui) + # creatig fake .cpp file where messages are located in the same lines as in .ui file + # and put it with the whole relative path to ${fake_ui_cpp_root} + ADD_CUSTOM_COMMAND(TARGET update-messages + COMMAND echo Extracting messages from UI-file ${relative_name} + COMMAND ${CMAKE_COMMAND} + -D IN_FILE:STRING=${${PROJECT_NAME}_SOURCE_DIR}/${relative_name} + -D OUT_FILE:STRING=${fake_ui_cpp_root}/${relative_name} + -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/UiToFakeCpp.cmake + ) + # parsing fake .cpp file from the ${fake_ui_cpp_root} in order to get the same path as + # path to the real .ui file + FILE(RELATIVE_PATH po_relative ${fake_ui_cpp_root} ${po_file}) # kde-xgettext do not accept full path to po-file + ADD_CUSTOM_COMMAND(TARGET update-messages + COMMAND ${XGETTEXT_EXECUTABLE} ${XGETTEXT_OPTIONS} -d${po_relative} ${relative_name} + WORKING_DIRECTORY ${fake_ui_cpp_root} + ) + ELSEIF(ext STREQUAL .cpp) + # just parse .cpp file + FILE(RELATIVE_PATH po_relative ${${PROJECT_NAME}_SOURCE_DIR} ${po_file}) # kde-xgettext do not accept full path to po-file + ADD_CUSTOM_COMMAND(TARGET update-messages + COMMAND echo Extracting messages from CPP-file ${relative_name} + COMMAND ${XGETTEXT_EXECUTABLE} ${XGETTEXT_OPTIONS} -d${po_relative} ${relative_name} + WORKING_DIRECTORY ${${PROJECT_NAME}_SOURCE_DIR} + ) + ENDIF(ext STREQUAL .ui) +ENDMACRO(EXTRACT_MESSAGES) + +MACRO(EMPTY_PO_FILE po_file) + # creating new po file with correct charset in it + # if this file is created automaticly charset will not be set + # and there would be a lot of warnings while adding new messages in it + ADD_CUSTOM_COMMAND(TARGET update-messages + COMMAND echo \"msgid \\\"\\\"\" > ${po_file}.po + COMMAND echo \"msgstr \\\"Content-Type: text/plain\; charset=UTF-8\\\"\" >> ${po_file}.po + ) +ENDMACRO(EMPTY_PO_FILE) diff --git a/cmake/cmake_uninstall.cmake.in b/cmake/cmake_uninstall.cmake.in new file mode 100644 index 0000000..559d7ce --- /dev/null +++ b/cmake/cmake_uninstall.cmake.in @@ -0,0 +1,23 @@ +# from cmake wiki +IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") +ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + +FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) +STRING(REGEX REPLACE "\n" ";" files "${files}") +FOREACH(file ${files}) + MESSAGE(STATUS "Uninstalling \"${file}\"") + IF(EXISTS "${file}") + EXEC_PROGRAM( + "@CMAKE_COMMAND@" ARGS "-E remove \"${file}\"" + OUTPUT_VARIABLE rm_out + RETURN_VALUE rm_retval + ) + IF("${rm_retval}" STREQUAL 0) + ELSE("${rm_retval}" STREQUAL 0) + MESSAGE(FATAL_ERROR "Problem when removing \"${file}\"") + ENDIF("${rm_retval}" STREQUAL 0) + ELSE(EXISTS "${file}") + MESSAGE(STATUS "File \"${file}\" does not exist.") + ENDIF(EXISTS "${file}") +ENDFOREACH(file) diff --git a/cmake/kde4uic.cmake b/cmake/kde4uic.cmake new file mode 100644 index 0000000..5a4babc --- /dev/null +++ b/cmake/kde4uic.cmake @@ -0,0 +1,53 @@ +# Copyright (c) 2006, Alexander Neundorf, +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +#using a ui3 file with uic3 +if (KDE3_IMPL) + + EXECUTE_PROCESS(COMMAND ${KDE_UIC_EXECUTABLE} + -nounload -tr tr2i18n + -impl ${KDE_UIC_H_FILE} + ${KDE_UIC_FILE} + OUTPUT_VARIABLE _uic_CONTENTS + ERROR_QUIET + ) +endif (KDE3_IMPL) + + +if (KDE3_HEADER) + + EXECUTE_PROCESS(COMMAND ${KDE_UIC_EXECUTABLE} + -nounload -tr tr2i18n + ${KDE_UIC_FILE} + OUTPUT_VARIABLE _uic_CONTENTS + ERROR_QUIET + ) + set(KDE_UIC_CPP_FILE ${KDE_UIC_H_FILE}) +endif (KDE3_HEADER) + +# the kde4 branch +if (KDE4_HEADER) + + EXECUTE_PROCESS(COMMAND ${KDE_UIC_EXECUTABLE} + -tr tr2i18n + ${KDE_UIC_FILE} + OUTPUT_VARIABLE _uic_CONTENTS + ERROR_QUIET + ) + + set(KDE_UIC_CPP_FILE ${KDE_UIC_H_FILE}) +endif (KDE4_HEADER) + + +#replace tr218n("") with QString::null to avoid warning from KLocale +STRING(REGEX REPLACE "tr2i18n\\(\"\"\\)" "QString::null" _uic_CONTENTS "${_uic_CONTENTS}" ) +STRING(REGEX REPLACE "tr2i18n\\(\"\", \"\"\\)" "QString::null" _uic_CONTENTS "${_uic_CONTENTS}" ) +#replace image15_data with img15_filename to make enable_final work +STRING(REGEX REPLACE "image([0-9]+)_data" "img\\1_${KDE_UIC_BASENAME}" _uic_CONTENTS "${_uic_CONTENTS}") +#fixup include guard +STRING(REGEX REPLACE "#ifndef " "#ifndef UI_" _uic_CONTENTS "${_uic_CONTENTS}") +STRING(REGEX REPLACE "#define " "#define UI_" _uic_CONTENTS "${_uic_CONTENTS}") + +FILE(WRITE ${KDE_UIC_CPP_FILE} "#include \"misc.h\"\n\n${_uic_CONTENTS}\n") diff --git a/config.h.cmake b/config.h.cmake new file mode 100644 index 0000000..68e2725 --- /dev/null +++ b/config.h.cmake @@ -0,0 +1,37 @@ +// version +#define PACKAGE "sim" +#define VERSION "0.9.6" +#define PREFIX "${CMAKE_INSTALL_PREFIX}" +#define PLUGIN_PATH "${SIM_PLUGIN_DIR}" + +// header +#cmakedefine HAVE_CARBON_CARBON_H 1 +#cmakedefine HAVE_INTTYPES_H 1 +#cmakedefine HAVE_STDDEF_H 1 +#cmakedefine HAVE_STDINT_H 1 +#cmakedefine HAVE_STDLIB_H 1 +#cmakedefine HAVE_STRING_H 1 +#cmakedefine HAVE_STRCASECMP 1 +#cmakedefine HAVE_SYS_STAT_H 1 +#cmakedefine HAVE_SYS_TYPES_H 1 +#cmakedefine HAVE_UNISTD_H 1 + +// symbols +#cmakedefine HAVE_STRNCASECMP 1 + +// functions +#cmakedefine HAVE_CHMOD 1 +#cmakedefine HAVE_MMAP 1 +#cmakedefine HAVE_MUNMAP 1 +#cmakedefine HAVE_UNAME 1 + +// check for structure member +#cmakedefine HAVE_TM_GMTOFF 1 + +// libraries +#cmakedefine ENABLE_OPENSSL 1 +#cmakedefine HAVE_X 1 +#cmakedefine USE_KDE 1 + +// development builds +#cmakedefine CVS_BUILD 1 diff --git a/configure.in.in b/configure.in.in new file mode 100644 index 0000000..004bb50 --- /dev/null +++ b/configure.in.in @@ -0,0 +1,154 @@ +#MIN_CONFIG +AC_PREREQ(2.50) +AC_LANG_CPLUSPLUS +AC_LANG_C +AM_INIT_AUTOMAKE(sim,0.9.6) +AC_PROG_LIBTOOL +AC_STDC_HEADERS +AC_C_BIGENDIAN +KDE_NEED_FLEX +LFLAGS="-o${LEX_OUTPUT_ROOT}.c" +AC_SUBST(LFLAGS) +if test "$CYGWIN" = "yes"; then + LDFLAGS="$LDFLAGS --enable-auto-import" +fi +if ! echo $CXXFLAGS | fgrep '-fno-strict-aliasing' >/dev/null 2>&1 ; then + old_cxxflags=$CXXFLAGS + CXXFLAGS="$CXXFLAGS -fno-strict-aliasing" + AC_TRY_COMPILE([], [return 0;], , CXXFLAGS=$old_cxxflags) +fi +RELEASE_BUILD="no" +AC_ARG_ENABLE( + release, + [ --enable-release enable release build], + RELEASE_BUILD="$enableval") +if test "$RELEASE_BUILD" != "yes"; then + AC_DEFINE(CVS_BUILD, 1, [CVS build]) +fi + +AC_TYPE_OFF_T +AC_TYPE_PID_T +AC_TYPE_SIZE_T +AC_TYPE_UID_T +AC_STRUCT_TM + +AC_PATH_X +if test $have_x = yes; then + AC_DEFINE(HAVE_X,1,[Have X Window System]) +fi + +AC_HEADER_SYS_WAIT +AC_FUNC_FORK +AC_C_INLINE +AC_C_CONST +KDE_CHECK_SSL +AC_HEADER_STDBOOL +AC_FUNC_ERROR_AT_LINE +AC_FUNC_MMAP +AC_FUNC_MKTIME +AC_FUNC_MEMCMP +AC_FUNC_MALLOC +AC_FUNC_REALLOC +AC_FUNC_STAT + +AC_CACHE_CHECK(for tm_gmtoff in struct tm, ac_cv_struct_tm_gmtoff, + AC_TRY_COMPILE([ + #include + ], [ + struct tm tm; + tm.tm_gmtoff = 1; + ], ac_cv_struct_tm_gmtoff=yes, ac_cv_struct_tm_gmtoff=no)) +if test $ac_cv_struct_tm_gmtoff = yes; then + AC_DEFINE(HAVE_TM_GMTOFF, 1, [Define if you have a tm_gmtoff member in struct tm]) +fi + +AC_CHECK_HEADERS([arpa/inet.h netinet/in.h sys/ioctl.h sys/socket.h]) +AC_CHECK_HEADERS([fcntl.h limits.h netdb.h stddef.h termios.h]) + +AC_CHECK_FUNCS([dup2 gethostbyname gethostname inet_ntoa]) +AC_CHECK_FUNCS([memset mkdir munmap rmdir socket]) +AC_CHECK_FUNCS([strcspn strdup strerror strstr strtol strtoul]) + +AC_CHECK_FUNC(strcasecmp,[AC_DEFINE(HAVE_STRCASECMP,1,[Have strcasecmp])]) +AC_CHECK_FUNC(chmod,[AC_DEFINE(HAVE_CHMOD,1,[Have chmod])]) +AC_CHECK_FUNC(uname,[AC_DEFINE(HAVE_UNAME,1,[Have uname])]) + +AC_EGREP_HEADER(in_addr_t, netinet/in.h,, AC_DEFINE(in_addr_t,int,[defaults in_addr_t to int])) +AC_EGREP_HEADER(socklen_t, sys/socket.h,, AC_DEFINE(socklen_t,int,[defaults socklen_t to int])) + +AC_CHECK_LIB(xnet,inet_addr) +AC_CHECK_LIB(socket, socket) + +AC_MSG_CHECKING([for The Ultimate Answer]) +AC_MSG_RESULT([42]) + +EXTRA_LIBS="" +KDE_CHECK_HEADER(qsyntaxhighlighter.h,[AC_DEFINE(HAVE_QSYNTAXHIGHLIGHTER_H,1,[Have qsyntaxhighlighter.h])]) +AC_DEFINE_UNQUOTED(PREFIX, "$prefix", [Install prefix]) +AC_SUBST(EXTRA_LIBS) +if test "${exec_prefix}" = "NONE" ; then + exec_prefix=$prefix +fi +libdir=`eval echo $libdir` + +sim_plugindir="${libdir}/sim" +sim_stylesdir="\${sim_plugindir}/styles" +AC_SUBST(sim_plugindir) +AC_SUBST(sim_stylesdir) +AC_DEFINE_UNQUOTED(PLUGIN_PATH,"${sim_plugindir}",[Plugins path]) + +LIB_XML2="" +AC_PATH_PROG(XML2_CONFIG, xml2-config, no) +if test "x$XML2_CONFIG" = "xno" ; then + AC_MSG_ERROR([Executable xml2-config not found! +Seems you have no libxml2 devel files installed. +You can download it from http://xmlsoft.org/download.html +]) +fi + +LIB_XML2=`$XML2_CONFIG --libs 2>/dev/null` +CPPFLAGS="$CPPFLAGS `$XML2_CONFIG --cflags`" + +LIB_XSLT="" +AC_PATH_PROG(XSLT_CONFIG, xslt-config, no) +if test "x$XSLT_CONFIG" = "xno" ; then + AC_MSG_ERROR([Executable xslt-config not found! +Seems you have no libxslt devel files installed. +You can download it from http://xmlsoft.org/download.html +]) +fi + +LIB_XSLT=`$XSLT_CONFIG --libs 2>/dev/null` +CPPFLAGS="$CPPFLAGS `$XSLT_CONFIG --cflags`" + +AC_SUBST(LIB_XML2) +AC_SUBST(LIB_XSLT) + +ZIP_FLAGS="-j" +AC_PATH_PROG(ZIP, zip, no) +if test "x$ZIP" = "xno" ; then + AC_MSG_ERROR([Executable zip not found!]) +fi +AC_SUBST(ZIP) +AC_SUBST(ZIP_FLAGS) + +if test "$have_ssl" != "yes" -a "$want_ssl" != "no"; then + AC_MSG_ERROR([SIM requires OpenSSL library. +Please install OpenSSL (libraries and headers). +OpenSSL can be found at http://www.openssl.org +or as RPM from your local distribution site. +]) +fi + +AM_CONDITIONAL(QT_WIN, test "$kde_use_qt_win" = "yes") + +if test "$kde_use_qt_win" = "yes"; then + AC_SUBST(SIM_RC_OBJ, "sim_rc.o") + AC_SUBST(GMSGFMT, "$GMSGFMT --qt") + AC_DEFINE(SIMAPI_EXPORTS, 1, [build libsim.dll]) +fi + +AM_CONDITIONAL(ENABLE_UPDATE, false) +AM_CONDITIONAL(ENABLE_STYLES_WOOD, false) +AM_CONDITIONAL(ENABLE_STYLES_METAL, false) + diff --git a/export_nix.py b/export_nix.py new file mode 100644 index 0000000..b034024 --- /dev/null +++ b/export_nix.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python +# instead of non-working cpack: svn export for *nix systems +# usage: export_nix.py TARGET_DIR +# the scripts excludes windows-specific files + +import os +import sys +import subprocess +import shutil +import fnmatch +from optparse import OptionParser + +PATTERNS = [ "*.vcproj", "*.sln", "install_win32", "win32" ] +GPL_COMPATIBLE_LICENSES = [ "GPL", "LGPL", "Public Domain", "MPL", "PPL", "MIT", "BSD" ] + +parser = OptionParser() +parser.add_option("-g", "--gpl", + action="store_true", dest="gpl", + help="export only GPL files (mostly icons)") +parser.set_defaults( gpl = False ) # should be True +(options, args) = parser.parse_args() +target_dir = args[0] + +print "Exporting to target directory '%s'" % target_dir +subprocess.check_call( ["svn", "export", os.curdir, target_dir ] ) + +def remove_path( path, message ): + if os.path.isdir( relname ): + print "[%s] Deleting dir '%s'" % ( message, relname ) + shutil.rmtree( relname ) + else: + print "[%s] Deleting '%s'" % ( message, relname ) + os.remove( relname ) + +def filter_path( path ): + if not options.gpl: + return True + else: + license_path = None + if os.path.exists( path + ".license" ): + license_path = path + ".license" + elif os.path.exists( os.path.join( path, "license" ) ): + license_path = os.path.join( path, "license" ) + if not license_path: + return True + else: + license_line = open( license_path ).readlines()[0].strip() + if license_line in GPL_COMPATIBLE_LICENSES: + return True + return False + +for root, dirs, files in os.walk( target_dir ): + for relname in [ os.path.join( root, name ) for name in dirs + files ]: + for pattern in PATTERNS: + if not fnmatch.fnmatch( os.path.basename( relname ), pattern ): + continue + remove_path( relname, "pattern" ) + if not filter_path( relname ): + remove_path( relname, "license" ) + +print "Done exporting to target directory '%s'" % target_dir + +basename = os.path.basename( target_dir ) +archivename = basename + ".tar.bz2" +archivedir = os.path.dirname( os.path.abspath( target_dir ) ) +archivepath = os.path.join( archivedir, archivename ) + +print "Packing '%s' to '%s'" % ( target_dir, archivepath ) +subprocess.check_call( ["tar", "--bzip2", "-c", "-f", archivename, basename ], cwd = archivedir ) +print "Done" + diff --git a/fedora.spec b/fedora.spec new file mode 100644 index 0000000..01fb907 --- /dev/null +++ b/fedora.spec @@ -0,0 +1,122 @@ +%define rh_release %(rh_release="`rpm -q --queryformat='%{VERSION}' redhat-release | grep -v install 2>/dev/null`" ; if test $? != 0 ; then rh_release="0" ; fi ; echo "$rh_release") +%define fdr_release %(fdr_release="`rpm -q --queryformat='%{VERSION}' fedora-release | grep -v install 2>/dev/null`" ; if test $? != 0 ; then fdr_release="0" ; fi ; echo "$fdr_release") +%if %{!?_without_KDE:0}%{?_without_KDE:1} +%define with_kde 0 +%else +%define with_kde 1 +%endif +%define release 2 + +Name: sim +Version: 0.9.3 +%if %{rh_release} +Release: %{release}.rh%(dist_release="`echo "%{rh_release} * 10" | bc 2>/dev/null`" ; echo "$dist_release") +Distribution: Red Hat Linux %{rh_release} +%else +Release: %{release}.fdr%(dist_release="`echo "%{fdr_release} * 10" | bc 2>/dev/null`" ; echo "$dist_release") +Distribution: Fedora Core %{fdr_release} +%endif +Vendor: Vladimir Shutoff +Packager: Robert Scheck +Summary: SIM - Multiprotocol Instant Messenger +Summary(de): SIM - Multiprotokoll Instant Messenger +License: GPL +Group: Applications/Internet +URL: http://sim-im.berlios.de/ +Source0: %{name}-%{version}.tar.gz +BuildRequires: autoconf >= 2.52, automake >= 1.5 +BuildRequires: gcc, gcc-c++, XFree86-devel, zlib-devel, libjpeg-devel, expat-devel, flex, libart_lgpl-devel, libpng-devel, gettext +%if %{with_kde} +BuildRequires: kdelibs-devel >= 3.0.0 +Requires: kdebase >= 3.0.0, kdelibs >= 3.0.0 +%endif +BuildRequires: qt-devel >= 3.0.0, openssl-devel, pcre-devel >= 3.9, arts-devel >= 1.0, libxml2-devel, libxslt-devel +Requires: qt >= 3.0.0, openssl, arts >= 1.0, libxml2, libxslt +BuildRoot: %{_tmppath}/%{name}-%{version}-root + +%description -l de +SIM - Multiprotokoll Instant Messenger + +SIM (Simple Instant Messenger) ist ein Plugin-basierender +open-source Instant Messenger, der verschiedene Protokolle +(ICQ, Jabber, AIM, MSN, LiveJournal, Yahoo!) unterstützt. +Dafür wird die QT-Bibliothek und X11 (mit optionaler KDE- +Unterstützung) verwendet. + +SIM hat sehr unzählige Features, viele von diesen sind +aufgelistet unter: http://sim-im.berlios.de/ + +%description +SIM - Multiprotocol Instant Messenger + +SIM (Simple Instant Messenger) is a plugins-based open- +source instant messenger that supports various protocols +(ICQ, Jabber, AIM, MSN, LiveJournal, Yahoo!). It uses the +QT library and works on X11 (with optional KDE support). + +SIM has countless features, many of them are listed at: +http://sim-im.berlios.de/ + +%prep +%setup -q +make -f admin/Makefile.common +CFLAGS="$RPM_OPT_FLAGS" CXXFLAGS="$RPM_OPT_FLAGS" + +%configure \ +%if %{with_kde} + --enable-kde \ +%else + --disable-kde \ +%endif + $LOCALFLAGS + +%build +# Setup for parallel builds +numprocs=`egrep -c ^cpu[0-9]+ /proc/stat || :` +if [ "$numprocs" = "0" ]; then + numprocs=1 +fi + +make -j $numprocs + +%install +make install-strip DESTDIR=$RPM_BUILD_ROOT +%find_lang %{name} + +%clean +rm -rf $RPM_BUILD_ROOT +rm -rf $RPM_BUILD_DIR/%{name}-%{version} + +%files -f %{name}.lang +%defattr(-, root, root) +%doc AUTHORS COPYING ChangeLog README* TODO INSTALL +%{_bindir}/sim* +%{_libdir}/libsim* +%{_libdir}/menu/ +%{_libdir}/sim/ +%{_datadir}/applnk-redhat/Internet/sim.desktop +%{_datadir}/apps/ +%{_datadir}/icons/*/*/*/* +%{_datadir}/mimelnk/ +%{_datadir}/services/ + +%changelog +* Sat Apr 03 2004 - Robert Scheck - 0.9.3-2 +- Upgrade to 0.9.3-2 (second 0.9.3 release) + +* Wed Mar 31 2004 - Robert Scheck - 0.9.3-1 +- Upgrade to 0.9.3 +- Made the KDE support conditional +- Merged Red Hat Linux spec file into Fedora Core spec file + +* Fri Dec 26 2003 - Robert Scheck - 0.9.2-1 +- Upgrade to 0.9.2 +- Added sablotron to requirements + +* Wed Nov 05 2003 - Robert Scheck - 0.9.1-1 +- Upgrade to 0.9.1 + +* Tue Oct 28 2003 - Robert Scheck - 0.9.0-1 +- Upgrade to 0.9.0 +- Adapted spec file from Red Hat Linux + diff --git a/install_win32/VC8_deploy/Microsoft.VC80.CRT.manifest b/install_win32/VC8_deploy/Microsoft.VC80.CRT.manifest new file mode 100644 index 0000000..e949ef8 --- /dev/null +++ b/install_win32/VC8_deploy/Microsoft.VC80.CRT.manifest @@ -0,0 +1,15 @@ + + + + + + + + + \ No newline at end of file diff --git a/install_win32/VC8_deploy/plugins/Microsoft.VC80.CRT.manifest b/install_win32/VC8_deploy/plugins/Microsoft.VC80.CRT.manifest new file mode 100644 index 0000000..cfa53ed --- /dev/null +++ b/install_win32/VC8_deploy/plugins/Microsoft.VC80.CRT.manifest @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/install_win32/VC8_deploy/sim.exe.intermediate.manifest b/install_win32/VC8_deploy/sim.exe.intermediate.manifest new file mode 100644 index 0000000..47be14a --- /dev/null +++ b/install_win32/VC8_deploy/sim.exe.intermediate.manifest @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/install_win32/iconv.dll b/install_win32/iconv.dll new file mode 100644 index 0000000..b448e7d Binary files /dev/null and b/install_win32/iconv.dll differ diff --git a/install_win32/libeay32.dll b/install_win32/libeay32.dll new file mode 100644 index 0000000..a6e4a1f Binary files /dev/null and b/install_win32/libeay32.dll differ diff --git a/install_win32/libxml2.dll b/install_win32/libxml2.dll new file mode 100644 index 0000000..3505fbc Binary files /dev/null and b/install_win32/libxml2.dll differ diff --git a/install_win32/libxslt.dll b/install_win32/libxslt.dll new file mode 100644 index 0000000..61fe010 Binary files /dev/null and b/install_win32/libxslt.dll differ diff --git a/install_win32/mingw/sim.nsi b/install_win32/mingw/sim.nsi new file mode 100644 index 0000000..3cece56 --- /dev/null +++ b/install_win32/mingw/sim.nsi @@ -0,0 +1,364 @@ +;Multilingular NSIS installer script for SIM Instant Messenger with Modern UI +;Written by Serhiy Kachanuk (c) 2006 + +;-------------------------------- +;Includes + + !include "MUI.nsh" + !include "Sections.nsh" + +;-------------------------------- +;Set compression settings + SetCompress auto + SetCompressor /SOLID /FINAL lzma + +;-------------------------------- +;General + + ;Name and file + Name "SIM Instant Messenger" + OutFile "sim-install.exe" + + ;Default installation folder + InstallDir "$PROGRAMFILES\SIM" + + ;Get installation folder from registry if available + InstallDirRegKey HKCU "Software\SIM" "" + +;-------------------------------- +;Interface Settings + + !define MUI_ABORTWARNING + +;-------------------------------- +;Variables + + Var STARTMENU_FOLDER + +;-------------------------------- +;Language Selection Dialog Settings + + ;Remember the installer language + !define MUI_LANGDLL_REGISTRY_ROOT "HKCU" + !define MUI_LANGDLL_REGISTRY_KEY "Software\SIM" + !define MUI_LANGDLL_REGISTRY_VALUENAME "Installer Language" + +;-------------------------------- +;Pages + !insertmacro MUI_PAGE_WELCOME + !insertmacro MUI_PAGE_LICENSE ..\..\COPYING + !insertmacro MUI_PAGE_COMPONENTS + !insertmacro MUI_PAGE_DIRECTORY + +;Start Menu Folder Page Configuration + !define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKCU" + !define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\SIM" + !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder" + + !insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER + + !insertmacro MUI_PAGE_INSTFILES + !define MUI_FINISHPAGE_RUN + !define MUI_FINISHPAGE_RUN_TEXT "Run SIM on Windows startup" + !define MUI_FINISHPAGE_RUN_FUNCTION RegStartOnBoot + !define MUI_FINISHPAGE_BUTTON "Next >" + !insertmacro MUI_PAGE_FINISH + !define MUI_FINISHPAGE_RUN "$INSTDIR\sim.exe" + !insertmacro MUI_PAGE_FINISH + + !insertmacro MUI_UNPAGE_CONFIRM + !insertmacro MUI_UNPAGE_INSTFILES + +;-------------------------------- +;Languages + + !insertmacro MUI_LANGUAGE "English" # first language is the default language + !insertmacro MUI_LANGUAGE "French" + !insertmacro MUI_LANGUAGE "German" + !insertmacro MUI_LANGUAGE "Spanish" + !insertmacro MUI_LANGUAGE "SimpChinese" + !insertmacro MUI_LANGUAGE "TradChinese" + !insertmacro MUI_LANGUAGE "Japanese" + !insertmacro MUI_LANGUAGE "Korean" + !insertmacro MUI_LANGUAGE "Italian" + !insertmacro MUI_LANGUAGE "Dutch" + !insertmacro MUI_LANGUAGE "Danish" + !insertmacro MUI_LANGUAGE "Swedish" + !insertmacro MUI_LANGUAGE "Norwegian" + !insertmacro MUI_LANGUAGE "Finnish" + !insertmacro MUI_LANGUAGE "Greek" + !insertmacro MUI_LANGUAGE "Russian" + !insertmacro MUI_LANGUAGE "Portuguese" + !insertmacro MUI_LANGUAGE "PortugueseBR" + !insertmacro MUI_LANGUAGE "Polish" + !insertmacro MUI_LANGUAGE "Ukrainian" + !insertmacro MUI_LANGUAGE "Czech" + !insertmacro MUI_LANGUAGE "Slovak" + !insertmacro MUI_LANGUAGE "Croatian" + !insertmacro MUI_LANGUAGE "Bulgarian" + !insertmacro MUI_LANGUAGE "Hungarian" + !insertmacro MUI_LANGUAGE "Thai" + !insertmacro MUI_LANGUAGE "Romanian" + !insertmacro MUI_LANGUAGE "Latvian" + !insertmacro MUI_LANGUAGE "Macedonian" + !insertmacro MUI_LANGUAGE "Estonian" + !insertmacro MUI_LANGUAGE "Turkish" + !insertmacro MUI_LANGUAGE "Lithuanian" + !insertmacro MUI_LANGUAGE "Catalan" + !insertmacro MUI_LANGUAGE "Slovenian" + !insertmacro MUI_LANGUAGE "Serbian" + !insertmacro MUI_LANGUAGE "SerbianLatin" + !insertmacro MUI_LANGUAGE "Arabic" + !insertmacro MUI_LANGUAGE "Farsi" + !insertmacro MUI_LANGUAGE "Hebrew" + !insertmacro MUI_LANGUAGE "Indonesian" + !insertmacro MUI_LANGUAGE "Mongolian" + !insertmacro MUI_LANGUAGE "Luxembourgish" + !insertmacro MUI_LANGUAGE "Albanian" + !insertmacro MUI_LANGUAGE "Breton" + !insertmacro MUI_LANGUAGE "Belarusian" + !insertmacro MUI_LANGUAGE "Icelandic" + !insertmacro MUI_LANGUAGE "Malay" + !insertmacro MUI_LANGUAGE "Bosnian" + !insertmacro MUI_LANGUAGE "Kurdish" + +;-------------------------------- +;Reserve Files + + ;These files should be inserted before other files in the data block + ;Keep these lines before any File command + ;Only for solid compression (by default, solid compression is enabled for BZIP2 and LZMA) + + !insertmacro MUI_RESERVEFILE_LANGDLL + +;-------------------------------- +;Installer Sections + +Section "!SIM program files" SecSIM + SectionIn RO + + ;SIM program + SetOutPath "$INSTDIR" + File ..\..\sim\.libs\sim.exe + File ..\..\sim\.libs\libsim-0.dll + + ;Plugins + SetOutPath "$INSTDIR\plugins" + File ..\..\plugins\__homedir\.libs\__homedir.dll + File ..\..\plugins\__migrate\.libs\__migrate.dll + File ..\..\plugins\_core\.libs\_core.dll + File ..\..\plugins\about\.libs\about.dll + File ..\..\plugins\action\.libs\action.dll + File ..\..\plugins\autoaway\.libs\autoaway.dll + File ..\..\plugins\background\.libs\background.dll + File ..\..\plugins\dock\.libs\dock.dll + File ..\..\plugins\filter\.libs\filter.dll + File ..\..\plugins\floaty\.libs\floaty.dll + File ..\..\plugins\forward\.libs\forward.dll + File ..\..\plugins\gpg\.libs\gpg.dll + File ..\..\plugins\icons\.libs\icons.dll + File ..\..\plugins\icq\.libs\icq.dll + File ..\..\plugins\jabber\.libs\jabber.dll + File ..\..\plugins\livejournal\.libs\livejournal.dll + File ..\..\plugins\logger\.libs\logger.dll + File ..\..\plugins\msn\.libs\msn.dll + File ..\..\plugins\navigate\.libs\navigate.dll + File ..\..\plugins\netmonitor\.libs\netmonitor.dll + File ..\..\plugins\ontop\.libs\ontop.dll + File ..\..\plugins\osd\.libs\osd.dll + File ..\..\plugins\proxy\.libs\proxy.dll + File ..\..\plugins\replace\.libs\replace.dll + File ..\..\plugins\shortcuts\.libs\shortcuts.dll + File ..\..\plugins\sms\.libs\sms.dll + File ..\..\plugins\sound\.libs\sound.dll + File ..\..\plugins\spell\.libs\spell.dll + File ..\..\plugins\splash\.libs\splash.dll + File ..\..\plugins\styles\.libs\styles.dll + File ..\..\plugins\transparent\.libs\transparent.dll + File ..\..\plugins\weather\.libs\weather.dll + File ..\..\plugins\windock\.libs\windock.dll + File ..\..\plugins\yahoo\.libs\yahoo.dll + File ..\..\plugins\zodiak\.libs\zodiak.dll + + ;Icons + SetOutPath "$INSTDIR\icons" + File ..\..\plugins\_core\additional\additional.jisp + File ..\..\plugins\_core\icq5\icq5.jisp + File ..\..\plugins\_core\icq5.1\icq5.1.jisp + File ..\..\plugins\_core\icqlite\icqlite.jisp + File ..\..\plugins\_core\jisp\sim.jisp + File ..\..\plugins\_core\smiles\smiles.jisp + File ..\..\plugins\weather\jisp\weather.jisp + + ;Pictures + SetOutPath "$INSTDIR\pict" + File ..\..\plugins\_core\pict\*.gif + + ;Locales + SetOutPath "$INSTDIR\po" + File /oname=bg.qm ..\..\po\bg.gmo + File /oname=ca.qm ..\..\po\ca.gmo + File /oname=cs.qm ..\..\po\cs.gmo + File /oname=de.qm ..\..\po\de.gmo + File /oname=el.qm ..\..\po\el.gmo + File /oname=es.qm ..\..\po\es.gmo + File /oname=fr.qm ..\..\po\fr.gmo + File /oname=he.qm ..\..\po\he.gmo + File /oname=hu.qm ..\..\po\hu.gmo + File /oname=it.qm ..\..\po\it.gmo + File /oname=nl.qm ..\..\po\nl.gmo + File /oname=pl.qm ..\..\po\pl.gmo + File /oname=pt_BR.qm ..\..\po\pt_BR.gmo + File /oname=ru.qm ..\..\po\ru.gmo + File /oname=sk.qm ..\..\po\sk.gmo + File /oname=sw.qm ..\..\po\sw.gmo + File /oname=th.qm ..\..\po\th.gmo + File /oname=tr.qm ..\..\po\tr.gmo + File /oname=uk.qm ..\..\po\uk.gmo + File /oname=zh_TW.qm ..\..\po\zh_TW.gmo + + ;Sounds + SetOutPath "$INSTDIR\sounds" + File ..\..\plugins\sound\sounds\*.wav + File ..\..\plugins\jabber\sounds\*.wav + File ..\..\plugins\icq\sounds\*.wav + File ..\..\plugins\sms\sounds\*.wav + + ;Styles + SetOutPath "$INSTDIR\styles" + File ..\..\plugins\_core\styles\*.xsl + + ;Store installation folder + WriteRegStr HKCU "Software\SIM" "" $INSTDIR + + ;Create uninstaller + WriteUninstaller "$INSTDIR\Uninstall.exe" + + ; write uninstall strings + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\SIM" "DisplayName" "SIM Instant messenger" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\SIM" "UninstallString" '"$INSTDIR\Uninstall.exe"' + + !insertmacro MUI_STARTMENU_WRITE_BEGIN Application + + ;Create shortcuts + CreateDirectory "$SMPROGRAMS\$STARTMENU_FOLDER" + CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\Uninstall.exe" + CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\SIM.lnk" "$INSTDIR\sim.exe" + + !insertmacro MUI_STARTMENU_WRITE_END + +SectionEnd + +SectionGroup /e "Runtime libraries" + + Section "Qt library files" SecQt + + SetOutPath "$INSTDIR" + File "$%QTDIR%\bin\qt-mt3.dll" + + SectionEnd + + Section "Xml2 library files" SecXml + + SetOutPath "$INSTDIR" + File "$%MINGW%\bin\libxml2-2.dll" + + SectionEnd + + Section "Xslt library files" SecXslt + + SetOutPath "$INSTDIR" + File "$%MINGW%\bin\libxslt-1.dll" + + SectionEnd + + Section "OpenSSL library files" SecSSL + + SetOutPath "$INSTDIR" + File "$%MINGW%\bin\libeay32.dll" + File "$%MINGW%\bin\libssl32.dll" + + SectionEnd + + Section "Mingw runtime" SecMingw + + SetOutPath "$INSTDIR" + File "$%MINGW%\bin\mingwm10.dll" + + SectionEnd + +SectionGroupEnd + +;-------------------------------- +;Installer Functions + +Function .onInit + + !insertmacro MUI_LANGDLL_DISPLAY + +FunctionEnd + +;-------------------------------- +;Descriptions + ;Assign language strings to sections + !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN + !insertmacro MUI_DESCRIPTION_TEXT ${SecSIM} "Main program, plugins and needed data files." + !insertmacro MUI_DESCRIPTION_TEXT ${SecQt} "Qt library. You can disable its installation if you have already installed it somewhere in yor system." + !insertmacro MUI_DESCRIPTION_TEXT ${SecXml} "Xml processing library. You can disable its installation if you have already installed it somewhere in yor system." + !insertmacro MUI_DESCRIPTION_TEXT ${SecXslt} "Xslt transfornation library. You can disable its installation if you have already installed it somewhere in yor system." + !insertmacro MUI_DESCRIPTION_TEXT ${SecSSL} "OpenSSL library. You can disable its installation if you have already installed it somewhere in yor system." + !insertmacro MUI_DESCRIPTION_TEXT ${SecMingw} "Mingw runtime. You can disable its installation if you have already installed Mingw somewhere in yor system." + !insertmacro MUI_FUNCTION_DESCRIPTION_END + +;-------------------------------- +;Uninstaller Section + +Section "Uninstall" + + Delete "$INSTDIR\plugins\*" + RMDir "$INSTDIR\plugins" + + Delete "$INSTDIR\icons\*" + RMDir "$INSTDIR\icons" + + Delete "$INSTDIR\pict\*" + RMDir "$INSTDIR\pict" + Delete "$INSTDIR\po\*" + RMDir "$INSTDIR\po" + + Delete "$INSTDIR\sounds\*" + RMDir "$INSTDIR\sounds" + + Delete "$INSTDIR\styles\*" + RMDir "$INSTDIR\styles" + + Delete "$INSTDIR\*.exe" + Delete "$INSTDIR\*.dll" + Delete "$INSTDIR\Uninstall.exe" + + RMDir "$INSTDIR" + + !insertmacro MUI_STARTMENU_WRITE_BEGIN Application + Delete "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" + Delete "$SMPROGRAMS\$STARTMENU_FOLDER\SIM.lnk" + RMDir "$SMPROGRAMS\$STARTMENU_FOLDER" + !insertmacro MUI_STARTMENU_WRITE_END + + DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\SIM" + DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\SIM" + DeleteRegKey /ifempty HKCU "Software\SIM" + +SectionEnd + +;-------------------------------- +;Uninstaller Functions +Function un.onInit + + !insertmacro MUI_UNGETLANGUAGE + +FunctionEnd + +;Function to register startup on boot +Function RegStartOnBoot + WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Run" "SIM" '"$INSTDIR\sim.exe"' +FunctionEnd diff --git a/install_win32/nsis_installer_full.nsi b/install_win32/nsis_installer_full.nsi new file mode 100644 index 0000000..67e0086 --- /dev/null +++ b/install_win32/nsis_installer_full.nsi @@ -0,0 +1,268 @@ +; SIMINSTALL.nsi +; +; Installer written by Tobias Franz (noragen@gmx.net), 2002 - 2006 +; +; SetCompressing Options: +SetCompress auto +SetCompressor lzma + +BGGradient topc + +!include "MUI.nsh" +!include "LogicLib.nsh" +!include "WordFunc.nsh" + +!macro BIMAGE IMAGE PARMS + Push $0 + GetTempFileName $0 + File /oname=$0 "${IMAGE}" + SetBrandingImage ${PARMS} $0 + Delete $0 + Pop $0 +!macroend + +!macro Print text + DetailPrint "${text}" +!macroend + +;Languages + + !insertmacro MUI_LANGUAGE "English" + !insertmacro MUI_LANGUAGE "German" + !insertmacro MUI_LANGUAGE "Russian" + ;!insertmacro MUI_LANGUAGE "French" + ;!insertmacro MUI_LANGUAGE "French" + ;!insertmacro MUI_LANGUAGE "Spanish" + ;!insertmacro MUI_LANGUAGE "SimpChinese" + ;!insertmacro MUI_LANGUAGE "TradChinese" + ;!insertmacro MUI_LANGUAGE "Japanese" + ;!insertmacro MUI_LANGUAGE "Korean" + ;!insertmacro MUI_LANGUAGE "Italian" + ;!insertmacro MUI_LANGUAGE "Dutch" + ;!insertmacro MUI_LANGUAGE "Danish" + ;!insertmacro MUI_LANGUAGE "Swedish" + ;!insertmacro MUI_LANGUAGE "Norwegian" + ;!insertmacro MUI_LANGUAGE "Finnish" + ;!insertmacro MUI_LANGUAGE "Greek" + ;!insertmacro MUI_LANGUAGE "Portuguese" + ;!insertmacro MUI_LANGUAGE "PortugueseBR" + ;!insertmacro MUI_LANGUAGE "Polish" + ;!insertmacro MUI_LANGUAGE "Ukrainian" + ;!insertmacro MUI_LANGUAGE "Czech" + ;!insertmacro MUI_LANGUAGE "Slovak" + ;!insertmacro MUI_LANGUAGE "Croatian" + ;!insertmacro MUI_LANGUAGE "Bulgarian" + ;!insertmacro MUI_LANGUAGE "Hungarian" + ;!insertmacro MUI_LANGUAGE "Thai" + ;!insertmacro MUI_LANGUAGE "Romanian" + ;!insertmacro MUI_LANGUAGE "Latvian" + ;!insertmacro MUI_LANGUAGE "Macedonian" + ;!insertmacro MUI_LANGUAGE "Estonian" + ;!insertmacro MUI_LANGUAGE "Turkish" + ;!insertmacro MUI_LANGUAGE "Lithuanian" + ;!insertmacro MUI_LANGUAGE "Catalan" + ;!insertmacro MUI_LANGUAGE "Slovenian" + ;!insertmacro MUI_LANGUAGE "Serbian" + ;!insertmacro MUI_LANGUAGE "SerbianLatin" + ;!insertmacro MUI_LANGUAGE "Arabic" + ;!insertmacro MUI_LANGUAGE "Farsi" + ;!insertmacro MUI_LANGUAGE "Hebrew" + ;!insertmacro MUI_LANGUAGE "Indonesian" + ;!insertmacro MUI_LANGUAGE "Mongolian" + ;!insertmacro MUI_LANGUAGE "Luxembourgish" + + +; The name of the installer +Name "SIM CVS/SVN VC8 FULL-Version ${__DATE__}, ${__TIME__}" + + +Function .onInit + + SetSilent silent + !insertmacro MUI_LANGDLL_DISPLAY + SetSilent normal + +FunctionEnd + +; The file to write +OutFile "SIM-IM_SVN_${__DATE__}.exe" + +; The default installation directory +InstallDir $PROGRAMFILES\SIM + +; The text to prompt the user to enter a directory +LangString welcome ${LANG_ENGLISH} "SIM-ICQ - Simple Instant Messenger, written by Vladimir Shutoff, continued by SIM-IM Development Team, is licensed under the Terms of the GPL.$\nThis SIM-IM - SVN Setup was created by Tobias Franz.$\nIt is a full-functional setup and it should contain all you need to run SIM-IM.$\n$\nPlease choose your SIM-IM - Rootdirectory now, where your sim.exe is stored:" +LangString welcome ${LANG_GERMAN} "SIM-ICQ - Simple Instant Messenger, geschrieben von Vladimir Shutoff, weitergeführt vom SIM-IM Development Team, wird unter den Bedingungen der GPL lizensiert.$\nDieses SIM-IM - SVN Setup wurde von Tobias Franz erstellt.$\nEs handelt sich um ein vollständig funktionsfähiges Setup und es sollte alles Nötige enthalten, um SIM-IM auszuführen$\n$\nBitte wählen Sie jetzt das SIM-IM-Installationsverzeichnis aus, wo die sim.exe liegen soll:" +LangString welcome ${LANG_RUSSIAN} "SIM-ICQ - Simple Instant Messenger, ñîçäàí Âëàäèìèðîì Øóòîâûì è ðàçâèâàåìûé SIM-IM Development Team ïîä ëèöåíçèåé GNU GPL.$\nÄàííàÿ ñáîðêà SIM - SVN Setup âûïîëíåíà Tobias Franz.$\nÝòî âåðñèÿ ñîäåðæèò âñ¸ íåîáõîäèìîå äëÿ èñïîëüçîâàíèÿ SIM-IM.$\n$\nÏîæàëóéñòà, âûáåðèòå ïàïêó, êóäà ñëåäóåò óñòàíîâèòü SIM:" +DirText "$(welcome)" + +; SetXP Style +XPStyle On +;BGGradient 000000 8000A0 FFFFFF +BGGradient 000000 B400E1 FFFFFF +InstallColors FF8080 000030 +AddBrandingImage left 100 +Page directory dirImage +Page instfiles + +LangString message ${LANG_ENGLISH} "I can run SIM for you now.$\nShould I do this for you?" +LangString message ${LANG_GERMAN} "Ich kann SIM für Sie ausführen.$\nSoll ich das für Sie übernehmen?" +LangString message ${LANG_RUSSIAN} "SIM-IM óñòàíîâëåí è ãîòîâ ê ðàáîòe.$\nÇàïóñòèòü SIM-IM?" +; The stuff to install + + +Section "Install" + ;Page instfiles instImage + + ;SetBrandingImage /RESIZETOFIT ..\Release\sim-window-small.bmp + ; Set output path to the installation directory. + SetOutPath $INSTDIR + ; Put file there + SetOverwrite on + + File ..\Release\sim.exe + File ..\Release\simctrl.exe + File VC8_deploy\Microsoft.VC80.CRT.manifest + File VC8_deploy\sim.exe.intermediate.manifest + + ;VC8DLL's + File $%WINDIR%\system32\msvcm80.dll + File $%WINDIR%\system32\msvcp80.dll + File $%WINDIR%\system32\msvcr80.dll + + UnRegDLL $INSTDIR\simremote.dll + UnRegDLL $INSTDIR\simext.dll + + File ..\Release\*.dll + + SetOutPath $INSTDIR\po + File ..\Release\po\*.qm + + SetOutPath $INSTDIR\plugins + + File ..\Release\plugins\*.dll + File VC8_deploy\plugins\Microsoft.VC80.CRT.manifest + + SetOutPath $INSTDIR\plugins\styles + + ;File ..\Release\plugins\styles\*.dll + + SetOutPath $INSTDIR\styles + File ..\Release\styles\*.xsl + + SetOutPath $INSTDIR\icons + File ..\Release\icons\*.jisp + + SetOutPath $INSTDIR\pict + File ..\Release\pict\*.gif + File ..\Release\pict\*.png + + SetOutPath $INSTDIR\copyright + File ..\Release\copyright\COPYING + + SetOutPath $INSTDIR\sounds + + File ..\Release\sounds\*.wav + +;Currently not working: + Delete $INSTDIR\plugins\styles\wood.dll + Delete $INSTDIR\plugins\styles\metal.dll + ;Delete $INSTDIR\plugins\styles.dll + Delete $INSTDIR\simremote.dll + Delete $INSTDIR\simext.dll + Delete $INSTDIR\sounds\*.dll + ;RegDLL ..\Release\simremote.dll + ;RegDLL ..\Release\simext.dll + +;System: +SetOutPath $SYSDIR + +File $%QTDIR%\lib\$%DLLQT% + +File $%WINDIR%\system32\libeay32.dll +File $%WINDIR%\system32\ssleay32.dll + + +SectionEnd ; end the section + +Section "Verknüpfungen" +CreateDirectory "$SMPROGRAMS\SIM" + WriteIniStr "$INSTDIR\SIM.url" "InternetShortcut" "URL" "http://sim-im.org" + WriteIniStr "$INSTDIR\Updates.url" "InternetShortcut" "URL" "http://www.sim-icq.de" + CreateShortCut "$SMPROGRAMS\SIM\SIM-IM.lnk" "$INSTDIR\SIM.url" "" "$INSTDIR\SIM.url" 0 + CreateShortCut "$SMPROGRAMS\SIM\Updates.lnk" "$INSTDIR\Updates.url" "" "$INSTDIR\Updates.url" 0 + + CreateShortCut "$SMPROGRAMS\SIM\SIM.lnk" "$INSTDIR\sim.exe" \ + "" "$INSTDIR\sim.exe" 0 SW_SHOWNORMAL + ;CreateShortCut "$SMPROGRAMS\RERSVC\Readme.lnk" "$INSTDIR\Readme.txt" \ + ; "" "%SystemRoot%\notepad.exe" 1 SW_SHOWMAXIMIZED + CreateShortCut "$SMPROGRAMS\SIM\Uninstaller.lnk" "$INSTDIR\uninst.exe" \ + "" "$INSTDIR\uninst.exe" 0 SW_SHOWNORMAL + +WriteUninstaller "$INSTDIR\Uninst.exe" +SectionEnd ; end the section + + +Function un.onUninstSuccess + HideWindow + MessageBox MB_ICONINFORMATION|MB_OK "$(^Name) wurde erfolgreich deinstalliert.." +FunctionEnd + +Function un.onInit + MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 "Möchten Sie $(^Name) und alle seinen Komponenten deinstallieren?" IDYES +2 + Abort +FunctionEnd + +Section "Uninstall" + +Delete $INSTDIR\Uninst.exe ; delete self (temporarily copying in temp directory ;)) +Delete "$INSTDIR\sim.exe" +Delete "$INSTDIR\simctrl.exe" + +UnRegDLL "$INSTDIR\simremote.dll" +UnRegDLL "$INSTDIR\simext.dll" + +Delete "$INSTDIR\*.dll" +Delete "$INSTDIR\po\*.qm" +Delete "$INSTDIR\plugins\*.dll" +Delete "$INSTDIR\plugins\styles\*.dll" +Delete "$INSTDIR\styles\*.xsl" +Delete "$INSTDIR\icons\*.jisp" +Delete "$INSTDIR\copyright\COPYING" +Delete "$INSTDIR\SIM.url" +Delete "$INSTDIR\Updates.url" +Delete "$INSTDIR\pict\*.gif" +Delete "$INSTDIR\pict\*.png" +Delete "$INSTDIR\sounds\*.wav" + +Delete "$SMPROGRAMS\SIM\SIM.lnk" +Delete "$SMPROGRAMS\SIM\SIM-IM.lnk" +Delete "$SMPROGRAMS\SIM\Updates.lnk" +Delete "$SMPROGRAMS\SIM\Uninstaller.lnk" +Delete "$SMPROGRAMS\SIM" + +RMDir $INSTDIR\po +RMDir $INSTDIR\plugins\styles +RMDir $INSTDIR\plugins +RMDir $INSTDIR\styles +RMDir $INSTDIR\icons +RMDir $INSTDIR\copyright +RMDir $INSTDIR\sounds +RMDir $INSTDIR\pict +RMDir $INSTDIR + +Quit +SectionEnd + +Section Start + MessageBox MB_YESNO "$(message)" IDNO done + Exec '"$INSTDIR\sim.exe"' + + done: + Quit +SectionEnd ; end the section + +Function dirImage + !insertmacro BIMAGE "sim-window-small.bmp" /RESIZETOFIT +FunctionEnd +; eof \ No newline at end of file diff --git a/install_win32/sim-window-small.bmp b/install_win32/sim-window-small.bmp new file mode 100644 index 0000000..71419c3 Binary files /dev/null and b/install_win32/sim-window-small.bmp differ diff --git a/install_win32/ssleay32.dll b/install_win32/ssleay32.dll new file mode 100644 index 0000000..af8a91e Binary files /dev/null and b/install_win32/ssleay32.dll differ diff --git a/install_win32/zlib1.dll b/install_win32/zlib1.dll new file mode 100644 index 0000000..1cf8a47 Binary files /dev/null and b/install_win32/zlib1.dll differ diff --git a/jisp-resources.txt b/jisp-resources.txt new file mode 100644 index 0000000..483c337 --- /dev/null +++ b/jisp-resources.txt @@ -0,0 +1,7 @@ +http://tsrh.crackz.ws/nitro/gants.jisp +http://www.cs.kuleuven.ac.be/~remko/psi/crystal/ +http://ftp.roedu.net/pub/mirrors/gentoo.org/distfiles/amibulb.jisp +http://www.kde-look.org/content/download.php?content=18306&id=1 +http://www.kde-look.org/content/download.php?content=18309&id=1 +http://www.kde-look.org/content/download.php?content=18310&id=1 + diff --git a/ltdl.m4 b/ltdl.m4 new file mode 100644 index 0000000..c5e2082 --- /dev/null +++ b/ltdl.m4 @@ -0,0 +1,421 @@ +## ltdl.m4 - Configure ltdl for the target system. -*-Autoconf-*- +## Copyright (C) 1999-2000 Free Software Foundation, Inc. +## +## This file is free software; the Free Software Foundation gives +## unlimited permission to copy and/or distribute it, with or without +## modifications, as long as this notice is preserved. + +# serial 7 AC_LIB_LTDL + +# AC_WITH_LTDL +# ------------ +# Clients of libltdl can use this macro to allow the installer to +# choose between a shipped copy of the ltdl sources or a preinstalled +# version of the library. +AC_DEFUN([AC_WITH_LTDL], +[AC_REQUIRE([AC_LIB_LTDL]) +AC_SUBST([LIBLTDL]) +AC_SUBST([INCLTDL]) + +# Unless the user asks us to check, assume no installed ltdl exists. +use_installed_libltdl=no + +AC_ARG_WITH([included_ltdl], + [ --with-included-ltdl use the GNU ltdl sources included here]) + +if test "x$with_included_ltdl" != xyes; then + # We are not being forced to use the included libltdl sources, so + # decide whether there is a useful installed version we can use. + AC_CHECK_HEADER([ltdl.h], + [AC_CHECK_LIB([ltdl], [lt_dlcaller_register], + [with_included_ltdl=no], + [with_included_ltdl=yes]) + ]) +fi + +if test "x$enable_ltdl_install" != xyes; then + # If the user did not specify an installable libltdl, then default + # to a convenience lib. + AC_LIBLTDL_CONVENIENCE +fi + +if test "x$with_included_ltdl" = xno; then + # If the included ltdl is not to be used. then Use the + # preinstalled libltdl we found. + AC_DEFINE([HAVE_LTDL], [1], + [Define this if a modern libltdl is already installed]) + LIBLTDL=-lltdl +fi + +# Report our decision... +AC_MSG_CHECKING([whether to use included libltdl]) +AC_MSG_RESULT([$with_included_ltdl]) + +AC_CONFIG_SUBDIRS([libltdl]) +])# AC_WITH_LTDL + + +# AC_LIB_LTDL +# ----------- +# Perform all the checks necessary for compilation of the ltdl objects +# -- including compiler checks and header checks. +AC_DEFUN([AC_LIB_LTDL], +[AC_PREREQ(2.50) +AC_REQUIRE([AC_PROG_CC]) +AC_REQUIRE([AC_C_CONST]) +AC_REQUIRE([AC_HEADER_STDC]) +AC_REQUIRE([AC_HEADER_DIRENT]) +AC_REQUIRE([_LT_AC_CHECK_DLFCN]) +AC_REQUIRE([AC_LTDL_ENABLE_INSTALL]) +AC_REQUIRE([AC_LTDL_SHLIBEXT]) +AC_REQUIRE([AC_LTDL_SHLIBPATH]) +AC_REQUIRE([AC_LTDL_SYSSEARCHPATH]) +AC_REQUIRE([AC_LTDL_OBJDIR]) +AC_REQUIRE([AC_LTDL_DLPREOPEN]) +AC_REQUIRE([AC_LTDL_DLLIB]) +AC_REQUIRE([AC_LTDL_SYMBOL_USCORE]) +AC_REQUIRE([AC_LTDL_DLSYM_USCORE]) +AC_REQUIRE([AC_LTDL_SYS_DLOPEN_DEPLIBS]) +AC_REQUIRE([AC_LTDL_FUNC_ARGZ]) + +AC_CHECK_HEADERS([assert.h ctype.h errno.h malloc.h memory.h stdlib.h \ + stdio.h unistd.h]) +AC_CHECK_HEADERS([dl.h sys/dl.h dld.h mach-o/dyld.h]) +AC_CHECK_HEADERS([string.h strings.h], [break]) + +AC_CHECK_FUNCS([strchr index], [break]) +AC_CHECK_FUNCS([strrchr rindex], [break]) +AC_CHECK_FUNCS([memcpy bcopy], [break]) +AC_CHECK_FUNCS([memmove strcmp]) +AC_CHECK_FUNCS([closedir opendir readdir]) +])# AC_LIB_LTDL + + +# AC_LTDL_ENABLE_INSTALL +# ---------------------- +AC_DEFUN([AC_LTDL_ENABLE_INSTALL], +[AC_ARG_ENABLE([ltdl-install], + [AC_HELP_STRING([--enable-ltdl-install], [install libltdl])]) + +AM_CONDITIONAL(INSTALL_LTDL, test x"${enable_ltdl_install-no}" != xno) +AM_CONDITIONAL(CONVENIENCE_LTDL, test x"${enable_ltdl_convenience-no}" != xno) +])# AC_LTDL_ENABLE_INSTALL + + +# AC_LTDL_SYS_DLOPEN_DEPLIBS +# -------------------------- +AC_DEFUN([AC_LTDL_SYS_DLOPEN_DEPLIBS], +[AC_REQUIRE([AC_CANONICAL_HOST]) +AC_CACHE_CHECK([whether deplibs are loaded by dlopen], + [libltdl_cv_sys_dlopen_deplibs], + [# PORTME does your system automatically load deplibs for dlopen? + # or its logical equivalent (e.g. shl_load for HP-UX < 11) + # For now, we just catch OSes we know something about -- in the + # future, we'll try test this programmatically. + libltdl_cv_sys_dlopen_deplibs=unknown + case "$host_os" in + aix3*|aix4.1.*|aix4.2.*) + # Unknown whether this is true for these versions of AIX, but + # we want this `case' here to explicitly catch those versions. + libltdl_cv_sys_dlopen_deplibs=unknown + ;; + aix[[45]]*) + libltdl_cv_sys_dlopen_deplibs=yes + ;; + darwin*) + # Assuming the user has installed a libdl from somewhere, this is true + # If you are looking for one http://www.opendarwin.org/projects/dlcompat + libltdl_cv_sys_dlopen_deplibs=yes + ;; + gnu* | linux* | kfreebsd*-gnu | knetbsd*-gnu) + # GNU and its variants, using gnu ld.so (Glibc) + libltdl_cv_sys_dlopen_deplibs=yes + ;; + hpux10*|hpux11*) + libltdl_cv_sys_dlopen_deplibs=yes + ;; + interix*) + libltdl_cv_sys_dlopen_deplibs=yes + ;; + irix[[12345]]*|irix6.[[01]]*) + # Catch all versions of IRIX before 6.2, and indicate that we don't + # know how it worked for any of those versions. + libltdl_cv_sys_dlopen_deplibs=unknown + ;; + irix*) + # The case above catches anything before 6.2, and it's known that + # at 6.2 and later dlopen does load deplibs. + libltdl_cv_sys_dlopen_deplibs=yes + ;; + netbsd*) + libltdl_cv_sys_dlopen_deplibs=yes + ;; + openbsd*) + libltdl_cv_sys_dlopen_deplibs=yes + ;; + osf[[1234]]*) + # dlopen did load deplibs (at least at 4.x), but until the 5.x series, + # it did *not* use an RPATH in a shared library to find objects the + # library depends on, so we explictly say `no'. + libltdl_cv_sys_dlopen_deplibs=no + ;; + osf5.0|osf5.0a|osf5.1) + # dlopen *does* load deplibs and with the right loader patch applied + # it even uses RPATH in a shared library to search for shared objects + # that the library depends on, but there's no easy way to know if that + # patch is installed. Since this is the case, all we can really + # say is unknown -- it depends on the patch being installed. If + # it is, this changes to `yes'. Without it, it would be `no'. + libltdl_cv_sys_dlopen_deplibs=unknown + ;; + osf*) + # the two cases above should catch all versions of osf <= 5.1. Read + # the comments above for what we know about them. + # At > 5.1, deplibs are loaded *and* any RPATH in a shared library + # is used to find them so we can finally say `yes'. + libltdl_cv_sys_dlopen_deplibs=yes + ;; + solaris*) + libltdl_cv_sys_dlopen_deplibs=yes + ;; + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + libltdl_cv_sys_dlopen_deplibs=yes + ;; + esac + ]) +if test "$libltdl_cv_sys_dlopen_deplibs" != yes; then + AC_DEFINE([LTDL_DLOPEN_DEPLIBS], [1], + [Define if the OS needs help to load dependent libraries for dlopen().]) +fi +])# AC_LTDL_SYS_DLOPEN_DEPLIBS + + +# AC_LTDL_SHLIBEXT +# ---------------- +AC_DEFUN([AC_LTDL_SHLIBEXT], +[AC_REQUIRE([AC_LIBTOOL_SYS_DYNAMIC_LINKER]) +AC_CACHE_CHECK([which extension is used for loadable modules], + [libltdl_cv_shlibext], +[ +module=yes +eval libltdl_cv_shlibext=$shrext_cmds + ]) +if test -n "$libltdl_cv_shlibext"; then + AC_DEFINE_UNQUOTED([LTDL_SHLIB_EXT], ["$libltdl_cv_shlibext"], + [Define to the extension used for shared libraries, say, ".so".]) +fi +])# AC_LTDL_SHLIBEXT + + +# AC_LTDL_SHLIBPATH +# ----------------- +AC_DEFUN([AC_LTDL_SHLIBPATH], +[AC_REQUIRE([AC_LIBTOOL_SYS_DYNAMIC_LINKER]) +AC_CACHE_CHECK([which variable specifies run-time library path], + [libltdl_cv_shlibpath_var], [libltdl_cv_shlibpath_var="$shlibpath_var"]) +if test -n "$libltdl_cv_shlibpath_var"; then + AC_DEFINE_UNQUOTED([LTDL_SHLIBPATH_VAR], ["$libltdl_cv_shlibpath_var"], + [Define to the name of the environment variable that determines the dynamic library search path.]) +fi +])# AC_LTDL_SHLIBPATH + + +# AC_LTDL_SYSSEARCHPATH +# --------------------- +AC_DEFUN([AC_LTDL_SYSSEARCHPATH], +[AC_REQUIRE([AC_LIBTOOL_SYS_DYNAMIC_LINKER]) +AC_CACHE_CHECK([for the default library search path], + [libltdl_cv_sys_search_path], + [libltdl_cv_sys_search_path="$sys_lib_dlsearch_path_spec"]) +if test -n "$libltdl_cv_sys_search_path"; then + sys_search_path= + for dir in $libltdl_cv_sys_search_path; do + if test -z "$sys_search_path"; then + sys_search_path="$dir" + else + sys_search_path="$sys_search_path$PATH_SEPARATOR$dir" + fi + done + AC_DEFINE_UNQUOTED([LTDL_SYSSEARCHPATH], ["$sys_search_path"], + [Define to the system default library search path.]) +fi +])# AC_LTDL_SYSSEARCHPATH + + +# AC_LTDL_OBJDIR +# -------------- +AC_DEFUN([AC_LTDL_OBJDIR], +[AC_CACHE_CHECK([for objdir], + [libltdl_cv_objdir], + [libltdl_cv_objdir="$objdir" + if test -n "$objdir"; then + : + else + rm -f .libs 2>/dev/null + mkdir .libs 2>/dev/null + if test -d .libs; then + libltdl_cv_objdir=.libs + else + # MS-DOS does not allow filenames that begin with a dot. + libltdl_cv_objdir=_libs + fi + rmdir .libs 2>/dev/null + fi + ]) +AC_DEFINE_UNQUOTED([LTDL_OBJDIR], ["$libltdl_cv_objdir/"], + [Define to the sub-directory in which libtool stores uninstalled libraries.]) +])# AC_LTDL_OBJDIR + + +# AC_LTDL_DLPREOPEN +# ----------------- +AC_DEFUN([AC_LTDL_DLPREOPEN], +[AC_REQUIRE([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE]) +AC_CACHE_CHECK([whether libtool supports -dlopen/-dlpreopen], + [libltdl_cv_preloaded_symbols], + [if test -n "$lt_cv_sys_global_symbol_pipe"; then + libltdl_cv_preloaded_symbols=yes + else + libltdl_cv_preloaded_symbols=no + fi + ]) +if test x"$libltdl_cv_preloaded_symbols" = xyes; then + AC_DEFINE([HAVE_PRELOADED_SYMBOLS], [1], + [Define if libtool can extract symbol lists from object files.]) +fi +])# AC_LTDL_DLPREOPEN + + +# AC_LTDL_DLLIB +# ------------- +AC_DEFUN([AC_LTDL_DLLIB], +[LIBADD_DL= +AC_SUBST(LIBADD_DL) +AC_LANG_PUSH([C]) + +AC_CHECK_FUNC([shl_load], + [AC_DEFINE([HAVE_SHL_LOAD], [1], + [Define if you have the shl_load function.])], + [AC_CHECK_LIB([dld], [shl_load], + [AC_DEFINE([HAVE_SHL_LOAD], [1], + [Define if you have the shl_load function.]) + LIBADD_DL="$LIBADD_DL -ldld"], + [AC_CHECK_LIB([dl], [dlopen], + [AC_DEFINE([HAVE_LIBDL], [1], + [Define if you have the libdl library or equivalent.]) + LIBADD_DL="-ldl" libltdl_cv_lib_dl_dlopen="yes"], + [AC_TRY_LINK([#if HAVE_DLFCN_H +# include +#endif + ], + [dlopen(0, 0);], + [AC_DEFINE([HAVE_LIBDL], [1], + [Define if you have the libdl library or equivalent.]) libltdl_cv_func_dlopen="yes"], + [AC_CHECK_LIB([svld], [dlopen], + [AC_DEFINE([HAVE_LIBDL], [1], + [Define if you have the libdl library or equivalent.]) + LIBADD_DL="-lsvld" libltdl_cv_func_dlopen="yes"], + [AC_CHECK_LIB([dld], [dld_link], + [AC_DEFINE([HAVE_DLD], [1], + [Define if you have the GNU dld library.]) + LIBADD_DL="$LIBADD_DL -ldld"], + [AC_CHECK_FUNC([_dyld_func_lookup], + [AC_DEFINE([HAVE_DYLD], [1], + [Define if you have the _dyld_func_lookup function.])]) + ]) + ]) + ]) + ]) + ]) +]) + +if test x"$libltdl_cv_func_dlopen" = xyes || test x"$libltdl_cv_lib_dl_dlopen" = xyes +then + lt_save_LIBS="$LIBS" + LIBS="$LIBS $LIBADD_DL" + AC_CHECK_FUNCS([dlerror]) + LIBS="$lt_save_LIBS" +fi +AC_LANG_POP +])# AC_LTDL_DLLIB + + +# AC_LTDL_SYMBOL_USCORE +# --------------------- +# does the compiler prefix global symbols with an underscore? +AC_DEFUN([AC_LTDL_SYMBOL_USCORE], +[AC_REQUIRE([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE]) +AC_CACHE_CHECK([for _ prefix in compiled symbols], + [ac_cv_sys_symbol_underscore], + [ac_cv_sys_symbol_underscore=no + cat > conftest.$ac_ext < $ac_nlist) && test -s "$ac_nlist"; then + # See whether the symbols have a leading underscore. + if grep '^. _nm_test_func' "$ac_nlist" >/dev/null; then + ac_cv_sys_symbol_underscore=yes + else + if grep '^. nm_test_func ' "$ac_nlist" >/dev/null; then + : + else + echo "configure: cannot find nm_test_func in $ac_nlist" >&AC_FD_CC + fi + fi + else + echo "configure: cannot run $lt_cv_sys_global_symbol_pipe" >&AC_FD_CC + fi + else + echo "configure: failed program was:" >&AC_FD_CC + cat conftest.c >&AC_FD_CC + fi + rm -rf conftest* + ]) +])# AC_LTDL_SYMBOL_USCORE + + +# AC_LTDL_DLSYM_USCORE +# -------------------- +AC_DEFUN([AC_LTDL_DLSYM_USCORE], +[AC_REQUIRE([AC_LTDL_SYMBOL_USCORE]) +if test x"$ac_cv_sys_symbol_underscore" = xyes; then + if test x"$libltdl_cv_func_dlopen" = xyes || + test x"$libltdl_cv_lib_dl_dlopen" = xyes ; then + AC_CACHE_CHECK([whether we have to add an underscore for dlsym], + [libltdl_cv_need_uscore], + [libltdl_cv_need_uscore=unknown + save_LIBS="$LIBS" + LIBS="$LIBS $LIBADD_DL" + _LT_AC_TRY_DLOPEN_SELF( + [libltdl_cv_need_uscore=no], [libltdl_cv_need_uscore=yes], + [], [libltdl_cv_need_uscore=cross]) + LIBS="$save_LIBS" + ]) + fi +fi + +if test x"$libltdl_cv_need_uscore" = xyes; then + AC_DEFINE([NEED_USCORE], [1], + [Define if dlsym() requires a leading underscore in symbol names.]) +fi +])# AC_LTDL_DLSYM_USCORE + +# AC_LTDL_FUNC_ARGZ +# ----------------- +AC_DEFUN([AC_LTDL_FUNC_ARGZ], +[AC_CHECK_HEADERS([argz.h]) + +AC_CHECK_TYPES([error_t], + [], + [AC_DEFINE([error_t], [int], + [Define to a type to use for `error_t' if it is not otherwise available.])], + [#if HAVE_ARGZ_H +# include +#endif]) + +AC_CHECK_FUNCS([argz_append argz_create_sep argz_insert argz_next argz_stringify]) +])# AC_LTDL_FUNC_ARGZ diff --git a/mandrake.spec b/mandrake.spec new file mode 100644 index 0000000..1edec69 --- /dev/null +++ b/mandrake.spec @@ -0,0 +1,133 @@ +%define name sim +%define version 0.9.3 +%define release 1mdk + +%define major 0 +%define libname %mklibname %name %major +%define libnamedev %mklibname %name %major -d + +Name: %name +Summary: SIM - Multiprotocol Instant Messenger +Version: %version +Release: %release +Source: %{name}-%{version}.tar.bz2 +License: GPL +Group: Networking/Instant messaging +Url: http://sim-im.berlios.de/ +BuildRoot: %{_tmppath}/%{name}-buildroot +Requires: libqt3 > 3.0.4, kdelibs > 3.0, sablotron +BuildRequires: kdelibs-devel > 3.0 +BuildRequires: autoconf2.5, automake1.7 +BuildRequires: libfam-devel +BuildRequires: flex, sablotron-devel + +%description +SIM - Multiprotocol Instant Messenger + +SIM (Simple Instant Messenger) is a plugins-based open- +source instant messenger that supports various protocols +(ICQ, Jabber, AIM, MSN). It uses the QT library and works +on X11 (with optional KDE-support). + +SIM has a lot of features, many of them are listed +at: http://sim-im.berlios.de/ + +%package -n %libname +Summary: SIM library +Group: System/Libraries + +%description -n %libname +SIM (Simple Instant Messenger) is a plugins-based open- +source instant messenger that supports various protocols +(ICQ, Jabber, AIM, MSN). It uses the QT library and works +on X11 (with optional KDE-support). + +Libraries + +%package -n %libnamedev +Summary: SIM library +Group: System/Libraries +Requires: %libname = %version +Provides: libsim-devel + +%description -n %libnamedev +SIM (Simple Instant Messenger) is a plugins-based open- +source instant messenger that supports various protocols +(ICQ, Jabber, AIM, MSN). It uses the QT library and works +on X11 (with optional KDE-support). + +Devel files + +%prep +rm -rf $RPM_BUILD_ROOT + +%setup -q + +%build +WANT_AUTOCONF_2_5=1 gmake -f admin/Makefile.common + +# mdk libtool doesn't know the --tag option :-( +for i in `find sim/ -name Makefile.in`; do perl -pi -e 's/^(LTCXXCOMPILE.*?)\s*--tag=CXX/$1/' "$i"; done +for i in `find sim/ -name Makefile.in`; do perl -pi -e 's/^(CXXLINK.*?)\s*--tag=CXX/$1/' "$i"; done +for i in `find plugins/ -name Makefile.in`; do perl -pi -e 's/^(LTCXXCOMPILE.*?)\s*--tag=CXX/$1/' "$i"; done +for i in `find plugins/ -name Makefile.in`; do perl -pi -e 's/^(CXXLINK.*?)\s*--tag=CXX/$1/' "$i"; done + +%configure --disable-rpath +%make + +%install +%makeinstall + +# Menu +mkdir -p %buildroot/%_menudir +cat > %buildroot/%_menudir/%name < 0.9.3-1mdk +- Upgrade to 0.9.3 +- Added sablotron and flex to requirements + +* Sun Nov 23 2003 Robert Scheck 0.9.2-1mdk +- Upgrade to 0.9.2 + +* Wed Nov 05 2003 Robert Scheck 0.9.1-1mdk +- Upgrade to 0.9.1 +- Initial spec file based on the official one from Mandrake diff --git a/plugins/__homedir/CMakeLists.txt b/plugins/__homedir/CMakeLists.txt new file mode 100644 index 0000000..b316fab --- /dev/null +++ b/plugins/__homedir/CMakeLists.txt @@ -0,0 +1,25 @@ +##################### +# __homedir library # +##################### + +#conditional sources +IF(WIN32) + SET (__homedir_SRCS homedircfg.cpp) + SET (__homedir_HDRS homedircfg.h) + SET (__homedir_UICS homedircfgbase.ui) +ENDIF(WIN32) + +SET(__homedir_SRCS + homedir.cpp + ${__homedir_SRCS} +) + +SET(__homedir_HDRS + homedir.h + ${__homedir_HDRS} +) + +REMOVE_DEFINITIONS(-DQT3_SUPPORT) +REMOVE_DEFINITIONS(-DQT_3SUPPORT_LIB) +REMOVE_DEFINITIONS(-DQT3_SUPPORT_WARNINGS) +SIM_ADD_PLUGIN(__homedir) diff --git a/plugins/__homedir/__homedir.vcproj b/plugins/__homedir/__homedir.vcproj new file mode 100644 index 0000000..edc4700 --- /dev/null +++ b/plugins/__homedir/__homedir.vcproj @@ -0,0 +1,369 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/__homedir/configure.in.in b/plugins/__homedir/configure.in.in new file mode 100644 index 0000000..27c8e1f --- /dev/null +++ b/plugins/__homedir/configure.in.in @@ -0,0 +1,5 @@ +if test "$kde_use_qt_win" = "yes"; then + __HOMEDIR_OBJ=homedircfg.lo + AC_SUBST([__HOMEDIR_OBJ]) +fi + diff --git a/plugins/__homedir/homedir.cpp b/plugins/__homedir/homedir.cpp new file mode 100644 index 0000000..91c7d00 --- /dev/null +++ b/plugins/__homedir/homedir.cpp @@ -0,0 +1,249 @@ +/*************************************************************************** + homedir.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "simapi.h" + +#include "homedir.h" + +#ifdef WIN32 +#include +#include + +#include +#include + +#include "homedircfg.h" + +static BOOL (WINAPI *_SHGetSpecialFolderPathA)(HWND hwndOwner, LPSTR lpszPath, int nFolder, BOOL fCreate) = NULL; +static BOOL (WINAPI *_SHGetSpecialFolderPathW)(HWND hwndOwner, LPSTR lpszPath, int nFolder, BOOL fCreate) = NULL; + +#else +#include +#include +#include +#endif + +#include +#include + +#include "log.h" +#include "misc.h" + +using namespace std; +using namespace SIM; + +Plugin *createHomeDirPlugin(unsigned base, bool, Buffer*) +{ + Plugin *plugin = new HomeDirPlugin(base); + return plugin; +} + +static PluginInfo info = + { +#ifdef WIN32 + I18N_NOOP("Home directory"), + I18N_NOOP("Plugin provides select directory for store config files"), +#else + NULL, + NULL, +#endif + VERSION, + createHomeDirPlugin, + PLUGIN_NO_CONFIG_PATH | PLUGIN_NODISABLE + }; + +EXPORT_PROC PluginInfo* GetPluginInfo() +{ + return &info; +} + +#ifdef WIN32 + +static const char key_name[] = "SIM"; +static const char path_value[] = "Path"; + +#endif + +HomeDirPlugin::HomeDirPlugin(unsigned base) + : Plugin(base) +{ +#ifdef WIN32 + m_bSave = true; + QSettings setting( QSettings::NativeFormat, QSettings::UserScope, key_name ); + m_homeDir = setting.value( path_value, QString("%APPDATA%") ).toString(); + m_bDefault = m_homeDir.isNull(); +#endif + QString d; + EventArg e("-b:", I18N_NOOP("Set home directory")); + if (e.process() && !e.value().isEmpty()){ + d = e.value(); +#ifdef WIN32 + m_bSave = false; +#endif + } else { + d = m_homeDir; + } + QDir dir( d ); + if ( d.isEmpty() || !dir.exists() ) { + m_homeDir = defaultPath(); +#ifdef WIN32 + m_bDefault = true; + m_bSave = false; +#endif + } +} + +QString HomeDirPlugin::defaultPath() +{ + QString s; +#ifndef WIN32 + struct passwd *pwd = getpwuid(getuid()); + if (pwd){ + s = QFile::decodeName(pwd->pw_dir); + }else{ + log(L_ERROR, "Can't get pwd"); + } + if (!s.endsWith("/")) + s += '/'; +#ifdef USE_KDE + char *kdehome = getenv("KDEHOME"); + if (kdehome){ + s = kdehome; + }else{ + s += ".kde/"; + } + if (!s.endsWith("/")) + s += '/'; + s += "share/apps/sim"; +#else // USE_KDE + +#ifdef __OS2__ + char *os2home = getenv("HOME"); + if (os2home) { + s = os2home; + s += "\\"; + } + s += ".sim-qt4"; + if ( access( s, F_OK ) != 0 ) { + mkdir( s, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH ); + } +#else // __OS2__ + +#ifdef Q_OS_MAC + s += "Library/Sim-IM"; +#else // Q_OS_MAC + s += ".sim-qt4"; +#endif // Q_OS_MAC + +#endif // __OS2__ + +#endif // USE_KDE +#else + char szPath[1024]; + szPath[0] = 0; + QString defPath; + + //Fixme: + //FOLDERID_RoamingAppData <<== this is used in Vista.. should be fixed + //otherwise the config is stored in "Downloads" per default :-/ + //Windows 2008 Server tested, simply works... + + (DWORD&)_SHGetSpecialFolderPathW = (DWORD)QLibrary::resolve("Shell32.dll","SHGetSpecialFolderPathW"); + (DWORD&)_SHGetSpecialFolderPathA = (DWORD)QLibrary::resolve("Shell32.dll","SHGetSpecialFolderPathA"); + //(DWORD&)_SHGetKnownFolderPath = (DWORD)QLibrary::resolve("Shell32.dll","SHGetKnownFolderPath"); //for Vista :-/ + + if (_SHGetSpecialFolderPathW && _SHGetSpecialFolderPathW(NULL, szPath, CSIDL_APPDATA, true)){ + defPath = QString::fromUtf16((unsigned short*)szPath); + }else if (_SHGetSpecialFolderPathA && _SHGetSpecialFolderPathA(NULL, szPath, CSIDL_APPDATA, true)){ + defPath = QFile::decodeName(szPath); + } + //}else if (_SHGetKnownFolderPath && _SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0x00008000, NULL, szPath)){ + // defPath = QFile::decodeName(szPath); + + /*HRESULT SHGetKnownFolderPath( REFKNOWNFOLDERID rfid, + DWORD dwFlags, + HANDLE hToken, + PWSTR *ppszPath );*/ + + if (!defPath.isEmpty()){ + if (!defPath.endsWith("\\")) + defPath += '\\'; + defPath += "sim"; + makedir(defPath + '\\'); + QString lockTest = defPath + "\\.lock"; + QFile f(lockTest); + if (!f.open(QIODevice::ReadWrite|QIODevice::Truncate)) + defPath.clear(); + f.close(); + QFile::remove(lockTest); + } + if (!defPath.isEmpty()){ + s = defPath; + }else{ + s = app_file(QString()); + } +#endif +#ifdef HAVE_CHMOD + chmod(QFile::encodeName(s), 0700); +#endif + return QDir::convertSeparators(s); +} + +#ifdef WIN32 + +QWidget *HomeDirPlugin::createConfigWindow(QWidget *parent) +{ + return new HomeDirConfig(parent, this); +} + +QByteArray HomeDirPlugin::getConfig() +{ + if (!m_bSave) + return QByteArray(); + QSettings setting( QSettings::NativeFormat, QSettings::UserScope, key_name ); + + if (!m_bDefault){ + setting.setValue( path_value, m_homeDir ); + }else{ + setting.remove( path_value ); + } + return QByteArray(); +} + +#endif + +QString HomeDirPlugin::buildFileName(const QString &name) +{ + QString s; + QString fname = name; + if(QDir(fname).isRelative()) { + s += m_homeDir; + s += '/'; + } + s += fname; + return QDir::convertSeparators(s); +} + +bool HomeDirPlugin::processEvent(Event *e) +{ + if (e->type() == eEventHomeDir){ + EventHomeDir *homedir = static_cast(e); + homedir->setHomeDir(buildFileName(homedir->homeDir())); + return true; + } + return false; +} diff --git a/plugins/__homedir/homedir.h b/plugins/__homedir/homedir.h new file mode 100644 index 0000000..3bbcaac --- /dev/null +++ b/plugins/__homedir/homedir.h @@ -0,0 +1,44 @@ +/*************************************************************************** + homedir.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _HOMEDIR_H +#define _HOMEDIR_H + +#include "event.h" +#include "plugins.h" + +class HomeDirPlugin : public SIM::Plugin, public SIM::EventReceiver +{ +public: + HomeDirPlugin(unsigned base); + QString defaultPath(); +protected: + bool processEvent(SIM::Event *e); + QString buildFileName(const QString &name); +#ifdef WIN32 + virtual QWidget *createConfigWindow(QWidget *parent); + virtual QByteArray getConfig(); + friend class HomeDirConfig; + + bool m_bDefault; + bool m_bSave; +#endif + QString m_homeDir; +}; + +#endif + diff --git a/plugins/__homedir/homedir.rc b/plugins/__homedir/homedir.rc new file mode 100644 index 0000000..4a77162 --- /dev/null +++ b/plugins/__homedir/homedir.rc @@ -0,0 +1,97 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,9,6,0 + PRODUCTVERSION 0,9,6,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Vladimir Shutoff\0" + VALUE "FileDescription", "Home directory plugin\0" + VALUE "FileVersion", "0, 9, 6, 0\0" + VALUE "InternalName", "__homedir\0" + VALUE "LegalCopyright", "Copyright © 2002-2003\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "__homedir.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "SIM\0" + VALUE "ProductVersion", "0, 9, 6, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/__homedir/homedircfg.cpp b/plugins/__homedir/homedircfg.cpp new file mode 100644 index 0000000..c164652 --- /dev/null +++ b/plugins/__homedir/homedircfg.cpp @@ -0,0 +1,81 @@ +/*************************************************************************** + homedircfg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "homedircfg.h" +#include "homedir.h" + +#include "simgui/editfile.h" + +#include +#include +#include + +HomeDirConfig::HomeDirConfig(QWidget *parent, HomeDirPlugin *plugin) + : QWidget(parent) + , m_plugin(plugin) +{ + setupUi(this); +#ifdef WIN32 // ER + chkDefault->setChecked(plugin->m_bDefault); +#endif + connect(chkDefault, SIGNAL(toggled(bool)), this, SLOT(defaultToggled(bool))); + defaultToggled(chkDefault->isChecked()); + edtPath->setText(QDir::convertSeparators(plugin->m_homeDir)); + edtPath->setDirMode(true); +#ifdef WIN32 // ER + chkDefault->setChecked(m_plugin->m_bDefault); +#endif +} + +void HomeDirConfig::apply() +{ + bool bDefault; + QString d; + QString defPath = m_plugin->defaultPath(); + + if (chkDefault->isChecked()){ + bDefault = true; + d = defPath; + }else{ + bDefault = false; + d = edtPath->text(); + } + if (d.isEmpty()) { + d = defPath; + } + QDir dir(d); + if (!dir.exists()) { + d = defPath; + bDefault = true; + } + + if (d.endsWith("/") || d.endsWith("\\")) + d = d.left(d.length() - 1); + + edtPath->setText(QDir::convertSeparators(d)); + m_plugin->m_bDefault = bDefault; + m_plugin->m_homeDir = d; + m_plugin->m_bSave = true; +} + +void HomeDirConfig::defaultToggled(bool bState) +{ + edtPath->setEnabled(!bState); + if (bState) + edtPath->setText(m_plugin->defaultPath()); +} + diff --git a/plugins/__homedir/homedircfg.h b/plugins/__homedir/homedircfg.h new file mode 100644 index 0000000..57eae32 --- /dev/null +++ b/plugins/__homedir/homedircfg.h @@ -0,0 +1,39 @@ +/*************************************************************************** + homedircfg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _HOMEDIRCFG_H +#define _HOMEDIRCFG_H + +#include "ui_homedircfgbase.h" + +class HomeDirPlugin; + +class HomeDirConfig : public QWidget, public Ui::HomeDirConfigBase +{ + Q_OBJECT +public: + HomeDirConfig(QWidget *parent, HomeDirPlugin *plugin); +public slots: + void apply(); +protected slots: + void defaultToggled(bool); +protected: + HomeDirPlugin *m_plugin; +}; + +#endif + diff --git a/plugins/__homedir/homedircfgbase.ui b/plugins/__homedir/homedircfgbase.ui new file mode 100644 index 0000000..bb8c0a9 --- /dev/null +++ b/plugins/__homedir/homedircfgbase.ui @@ -0,0 +1,70 @@ + + + HomeDirConfigBase + + + + 0 + 0 + 213 + 134 + + + + Form1 + + + + 6 + + + 11 + + + + + Use &default path + + + + + + + Path for config files: + + + false + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + EditFile + QWidget +
simgui/editfile.h
+
+
+ + +
diff --git a/plugins/__migrate/CMakeLists.txt b/plugins/__migrate/CMakeLists.txt new file mode 100644 index 0000000..2a35378 --- /dev/null +++ b/plugins/__migrate/CMakeLists.txt @@ -0,0 +1,23 @@ +##################### +# __migrate library # +##################### +IF(BUILD_DROPPED) +SET(__migrate_SRCS + migrate.cpp + migratedlg.cpp +) + +SET(__migrate_HDRS + migrate.h + migratedlg.h +) + +SET(__migrate_UICS + migratedlgbase.ui +) + +REMOVE_DEFINITIONS(-DQT3_SUPPORT) +REMOVE_DEFINITIONS(-DQT_3SUPPORT_LIB) +REMOVE_DEFINITIONS(-DQT3_SUPPORT_WARNINGS) +SIM_ADD_PLUGIN(__migrate) +ENDIF(BUILD_DROPPED) diff --git a/plugins/__migrate/__migrate.vcproj b/plugins/__migrate/__migrate.vcproj new file mode 100644 index 0000000..ddf96d5 --- /dev/null +++ b/plugins/__migrate/__migrate.vcproj @@ -0,0 +1,404 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/__migrate/migrate.cpp b/plugins/__migrate/migrate.cpp new file mode 100644 index 0000000..0562c60 --- /dev/null +++ b/plugins/__migrate/migrate.cpp @@ -0,0 +1,86 @@ +/*************************************************************************** + migrate.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include + +#include "misc.h" + +#include "migrate.h" +#include "migratedlg.h" + +using namespace SIM; + +Plugin *createMigratePlugin(unsigned base, bool, Buffer*) +{ + MigratePlugin *plugin = new MigratePlugin(base); + if (!plugin->init()){ + delete plugin; + return NULL; + } + return plugin; +} + +static PluginInfo info = + { + I18N_NOOP("Migrate"), + I18N_NOOP("Plugin provides convert configuration and history from SIM 0.8"), + VERSION, + createMigratePlugin, + PLUGIN_DEFAULT + }; + +EXPORT_PROC PluginInfo* GetPluginInfo() +{ + return &info; +} + +MigratePlugin::MigratePlugin(unsigned base) + : Plugin(base) +{ +} + +MigratePlugin::~MigratePlugin() +{ +} + +bool MigratePlugin::init() +{ + QString dir = user_file(QString::null); + QDir d(dir); + if (!d.exists()) + return false; + QStringList cnvDirs; + QStringList dirs = d.entryList(QDir::Dirs); + QStringList::Iterator it; + for (it = dirs.begin(); it != dirs.end(); ++it){ + if ((*it)[0] == '.') + continue; + QString p = dir + (*it); + p += '/'; + QFile icqConf(p + "icq.conf"); + QFile clientsConf(p + "clients.conf"); + if (icqConf.exists() && !clientsConf.exists()){ + cnvDirs.append(*it); + } + } + if (cnvDirs.count() == 0) + return false; + MigrateDialog dlg(dir, cnvDirs); + dlg.exec(); + return true; +} + diff --git a/plugins/__migrate/migrate.h b/plugins/__migrate/migrate.h new file mode 100644 index 0000000..a81f764 --- /dev/null +++ b/plugins/__migrate/migrate.h @@ -0,0 +1,32 @@ +/*************************************************************************** + migrate.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _MIGRATE_H +#define _MIGRATE_H + +#include "plugins.h" + +class MigratePlugin : public SIM::Plugin +{ +public: + MigratePlugin(unsigned); + ~MigratePlugin(); + bool init(); +}; + +#endif + diff --git a/plugins/__migrate/migrate.rc b/plugins/__migrate/migrate.rc new file mode 100644 index 0000000..7dbca9b --- /dev/null +++ b/plugins/__migrate/migrate.rc @@ -0,0 +1,97 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,9,6,0 + PRODUCTVERSION 0,9,6,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Vladimir Shutoff\0" + VALUE "FileDescription", "Migrate plugin\0" + VALUE "FileVersion", "0, 9, 6, 0\0" + VALUE "InternalName", "__migrate\0" + VALUE "LegalCopyright", "Copyright © 2002-2003\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "__migrate.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "SIM\0" + VALUE "ProductVersion", "0, 9, 6, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/__migrate/migratedlg.cpp b/plugins/__migrate/migratedlg.cpp new file mode 100644 index 0000000..ad4d60c --- /dev/null +++ b/plugins/__migrate/migratedlg.cpp @@ -0,0 +1,401 @@ +/*************************************************************************** + migratedlg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "buffer.h" +#include "unquot.h" +#include "misc.h" + +#include "migratedlg.h" + +#include "simgui/ballonmsg.h" + + + +using namespace std; +using namespace SIM; + +MigrateDialog::MigrateDialog(const QString &dir, const QStringList &cnvDirs) : QWizard(NULL) + //: MigrateDialogBase(NULL, "migrate", true) +{ + setupUi(this); + m_dir = dir; + m_cnvDirs = cnvDirs; + m_bProcess = false; + QVBoxLayout *lay = (QVBoxLayout*)(page1->layout()); + for (QStringList::Iterator it = m_cnvDirs.begin(); it != m_cnvDirs.end(); ++it){ + QCheckBox *chk = new QCheckBox(*it, page1); + lay->insertWidget(1, chk); + chk->show(); + chk->setChecked(true); + m_boxes.push_back(chk); + } + chkRemove->setChecked(true); + connect(this, SIGNAL(selected(const QString&)), this, SLOT(pageSelected(const QString&))); + button( QWizard::HelpButton )->hide(); +} + +void MigrateDialog::closeEvent(QCloseEvent *e) +{ + if (!m_bProcess){ + QWizard::closeEvent(e); + return; + } + e->ignore(); + ask(); +} + +void MigrateDialog::reject() +{ + if (!m_bProcess){ + QWizard::reject(); + return; + } + ask(); +} + +void MigrateDialog::ask() +{ + QAbstractButton *btn = button( QWizard::CancelButton ); + QPoint p = btn->mapToGlobal(QPoint(0, 0)); + QRect rc(p.x(), p.y(), btn->width(), btn->height()); + BalloonMsg::ask(NULL, i18n("Cancel convert?"), this, SLOT(cancel(void*)), NULL, &rc); +} + +void MigrateDialog::cancel(void*) +{ + m_bProcess = false; + reject(); +} + +void MigrateDialog::pageSelected(const QString&) +{ + if (currentPage() != page2) + return; + button( QWizard::BackButton )->hide(); + button( QWizard::FinishButton )->setEnabled(false); + list::iterator it; + for (it = m_boxes.begin(); it != m_boxes.end(); ++it){ + if ((*it)->isChecked()){ + m_bProcess = true; + break; + } + } + if (!m_bProcess){ + reject(); + return; + } + unsigned totalSize = 0; + for (it = m_boxes.begin(); it != m_boxes.end(); ++it){ + if (!(*it)->isChecked()) + continue; + QString path = user_file((*it)->text()); + path += '/'; + QFile icq_conf(path + "icq.conf"); + totalSize += icq_conf.size(); + QString history_path = path + "history"; + history_path += '/'; + QDir history(history_path); + QStringList l = history.entryList(QStringList("*.history"), QDir::Files); + for (QStringList::Iterator it = l.begin(); it != l.end(); ++it){ + QFile hf(history_path + (*it)); + totalSize += hf.size(); + } + } + barCnv->setMaximum(totalSize); + QTimer::singleShot(0, this, SLOT(process())); +} + +void MigrateDialog::error(const QString &str) +{ + lblStatus->setText(str); + barCnv->hide(); + button( QWizard::FinishButton )->setEnabled(true); + m_bProcess = false; +} + +void MigrateDialog::process() +{ + unsigned size = 0; + for (list::iterator it = m_boxes.begin(); it != m_boxes.end(); ++it){ + if (!(*it)->isChecked()) + continue; + QString path = user_file((*it)->text()); + path += '/'; + icqConf.close(); + clientsConf.close(); + contactsConf.close(); + icqConf.setFileName(path + "icq.conf"); + clientsConf.setFileName(path + "clients.conf"); + contactsConf.setFileName(path + "contacts.conf"); + lblStatus->setText(path + "icq.conf"); + if (!icqConf.open(QIODevice::ReadOnly)){ + error(i18n("Can't open %1") .arg(path + "icq.conf")); + return; + } + if (!clientsConf.open(QIODevice::WriteOnly | QIODevice::Truncate)){ + error(i18n("Can't open %1") .arg(path + "clients.conf")); + return; + } + if (!contactsConf.open(QIODevice::WriteOnly | QIODevice::Truncate)){ + error(i18n("Can't open %1") .arg(path + "contacts.conf")); + return; + } + m_uin = 0; + m_passwd = ""; + m_state = 0; + m_grpId = 0; + m_contactId = 0; + Buffer cfg; + cfg.init(icqConf.size()); + icqConf.read(cfg.data(), icqConf.size()); + for (;;){ + QByteArray section = cfg.getSection(); + if (section.isEmpty()) + break; + m_state = 3; + if (section == "Group") + m_state = 1; + if (section == "User") + m_state = 2; + if (!m_bProcess) + return; + for (;;){ + QByteArray l = cfg.getLine(); + if (l.isEmpty()) + break; + QByteArray line = l; + QByteArray name = getToken(line, '='); + if (name == "UIN") + m_uin = line.toUInt(); + if (name == "EncryptPassword") + m_passwd = line; + if (name == "Name") + m_name = line; + if (name == "Alias") + m_name = line; + } + flush(); + barCnv->setValue(cfg.readPos()); + qApp->processEvents(); + } + icqConf.close(); + clientsConf.close(); + contactsConf.close(); + m_state = 3; + size += icqConf.size(); + if (!m_bProcess) + return; + barCnv->setValue(size); + qApp->processEvents(); + QString h_path = path; +#ifdef WIN32 + h_path += "history\\"; +#else + h_path += "history/"; +#endif + QDir history(h_path); + QStringList l = history.entryList(QStringList("*.history"), QDir::Files); + for (QStringList::Iterator it = l.begin(); it != l.end(); ++it){ + hFrom.close(); + hTo.close(); + hFrom.setFileName(h_path + (*it)); + lblStatus->setText(h_path + (*it)); + hTo.setFileName(h_path + QString(m_owner) + '.' + it->left(it->indexOf('.'))); + if (!hFrom.open(QIODevice::ReadOnly)){ + error(i18n("Can't open %1") .arg(hFrom.fileName())); + return; + } + if (!hTo.open(QIODevice::WriteOnly | QIODevice::Truncate)){ + error(i18n("Can't open %1") .arg(hTo.fileName())); + return; + } + cfg.init(hFrom.size()); + hFrom.read(cfg.data(), hFrom.size()); + for (;;){ + QByteArray section = cfg.getSection(); + if (section.isEmpty()) + break; + m_state = 3; + if (section == "Message") + m_state = 4; + if (!m_bProcess) + return; + for (;;){ + QByteArray l = cfg.getLine(); + if (l.isEmpty()) + break; + QByteArray line = l; + QByteArray name = getToken(line, '='); + if (name == "Message") + m_message = line; + if (name == "Time") + m_time = line; + if (name == "Direction") + m_direction = line; + if (name == "Charset") + m_charset = line; + } + flush(); + barCnv->setValue(cfg.readPos()); + qApp->processEvents(); + } + hFrom.close(); + hTo.close(); + m_state = 3; + size += hFrom.size(); + if (!m_bProcess) + return; + barCnv->setValue(size); + qApp->processEvents(); + } + if (chkRemove->isChecked()){ + icqConf.remove(); + icqConf.setFileName(path + "sim.conf"); + icqConf.remove(); + for (QStringList::Iterator it = l.begin(); it != l.end(); ++it){ + hFrom.setFileName(h_path + (*it)); + hFrom.remove(); + } + } + } + m_bProcess = false; + accept(); +} + +void MigrateDialog::flush() +{ + QByteArray output; + switch (m_state){ + case 0: + output = "[icq/ICQ]\n"; + clientsConf.write(output, output.length()); + output = "Uin="; + output += QByteArray::number(m_uin); + output += "\n"; + if (!m_passwd.isEmpty()){ + m_passwd = unquoteString(m_passwd).toUtf8(); + unsigned char xor_table[] = + { + 0xf3, 0x26, 0x81, 0xc4, 0x39, 0x86, 0xdb, 0x92, + 0x71, 0xa3, 0xb9, 0xe6, 0x53, 0x7a, 0x95, 0x7c + }; + for (int i = 0; i < (int)m_passwd.length(); i++) + m_passwd[i] = (char)(m_passwd[i] ^ xor_table[i]); + QByteArray new_passwd; + unsigned short temp = 0x4345; + for (int i = 0; i < (int)m_passwd.length(); i++) { + temp ^= m_passwd[i]; + new_passwd += '$'; + char buff[8]; + sprintf(buff, "%x", temp); + new_passwd += buff; + } + output += "Password=\""; + output += new_passwd; + output += "\"\n"; + } + clientsConf.write(output, output.length()); + m_owner = "ICQ."; + m_owner += QByteArray::number(m_uin); + break; + case 1: + if (!m_name.isEmpty()){ + output = "[Group="; + output += QByteArray::number(++m_grpId); + output += "]\n"; + output += "Name=\""; + output += m_name; + output += "\"\n"; + contactsConf.write(output, output.length()); + } + break; + case 2: + output = "[Contact="; + output += QByteArray::number(++m_contactId); + output += "]\n"; + if (m_uin >= 0x80000000) + m_uin = 0; + if (m_name.isEmpty()) + m_name = QByteArray::number(m_uin); + if (!m_name.isEmpty()){ + output += "Name=\""; + output += m_name; + output += "\"\n"; + } + if (m_uin){ + output += "["; + output += m_owner; + output += "]\n"; + output += "Uin="; + output += QByteArray::number(m_uin); + output += "\n"; + } + contactsConf.write(output, output.length()); + break; + case 4: + if (!m_message.isEmpty()){ + QString msg = QString::fromLocal8Bit(m_message); + if (!m_charset.isEmpty()){ + QTextCodec *codec = QTextCodec::codecForName(m_charset); + if (codec) + msg = codec->toUnicode(m_message); + } + output = "[Message]\n"; + output += "Text=\""; + output += quoteChars(msg, "\"", false).toLocal8Bit(); + output += "\"\n"; + if (m_direction.isEmpty()){ + output += "Flags=2\n"; + }else{ + output += "Flags=3\n"; + } + output += "Time="; + output += m_time; + output += "\n"; + hTo.write(output, output.length()); + } + break; + } + m_uin = 0; + m_passwd = ""; + m_name = ""; + m_message = ""; + m_time = ""; + m_direction = ""; + m_charset = ""; +} + +/* +#ifndef NO_MOC_INCLUDES +#include "migratedlg.moc" +#endif +*/ + diff --git a/plugins/__migrate/migratedlg.h b/plugins/__migrate/migratedlg.h new file mode 100644 index 0000000..0ac2369 --- /dev/null +++ b/plugins/__migrate/migratedlg.h @@ -0,0 +1,72 @@ +/*************************************************************************** + migratedlg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _MIGRATEDLG_H +#define _MIGRATEDLG_H + +#include "ui_migratedlgbase.h" + +#include +#include +#include +#include +#include "simapi.h" + +class MigrateDialog : public QWizard, public Ui::MigrateDialogBase +{ + Q_OBJECT +public: + MigrateDialog(const QString &dir, const QStringList &cnvDirs); +protected slots: + void cancel(void*); + void pageSelected(const QString&); + void process(); +protected: + void closeEvent(QCloseEvent *e); + void reject(); + void ask(); + void error(const QString&); + void flush(); + + QByteArray m_owner; + + unsigned m_uin; + QByteArray m_passwd; + QByteArray m_name; + int m_state; + QByteArray m_message; + QByteArray m_time; + QByteArray m_direction; + QByteArray m_charset; + + unsigned m_grpId; + unsigned m_contactId; + + QFile icqConf; + QFile clientsConf; + QFile contactsConf; + QFile hFrom; + QFile hTo; + + bool m_bProcess; + std::list m_boxes; + QString m_dir; + QStringList m_cnvDirs; +}; + +#endif + diff --git a/plugins/__migrate/migratedlgbase.ui b/plugins/__migrate/migratedlgbase.ui new file mode 100644 index 0000000..474b6c6 --- /dev/null +++ b/plugins/__migrate/migratedlgbase.ui @@ -0,0 +1,142 @@ + + + MigrateDialogBase + + + + 0 + 0 + 507 + 316 + + + + Convert configuration from old version + + + + Select directories for convert + + + + 11 + + + + + Directories for convert: + + + false + + + + + + + + 0 + 0 + + + + + + + + &Remove old files + + + + + + + Note! +If you select an option " Remove old files ", you can not use the old version + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + true + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + Convert configuration + + + + 11 + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + + + false + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + qPixmapFromMimeSource + + + diff --git a/plugins/_core/CMakeLists.txt b/plugins/_core/CMakeLists.txt new file mode 100644 index 0000000..40e8c0a --- /dev/null +++ b/plugins/_core/CMakeLists.txt @@ -0,0 +1,203 @@ +################# +# _core library # +################# +ADD_SUBDIRECTORY(pict) +ADD_SUBDIRECTORY(styles) + +SET(_core_SRCS + arcfg.cpp + autoreply.cpp + cfgdlg.cpp + cmenu.cpp + commands.cpp + connectionsettings.cpp + connectwnd.cpp + container.cpp + core.cpp + declinedlg.cpp + editmail.cpp + editphone.cpp + filecfg.cpp + filetransfer.cpp + history.cpp + historycfg.cpp + historywnd.cpp + interfacecfg.cpp + logindlg.cpp + maininfo.cpp + mainwin.cpp + manager.cpp + msgauth.cpp + msgcfg.cpp + msgcontacts.cpp + msgedit.cpp + msgfile.cpp + msggen.cpp + msgrecv.cpp + msgsms.cpp + msgurl.cpp + msgview.cpp + msgview_menu.cpp + newprotocol.cpp + nonim.cpp + pagerdetails.cpp + phonedetails.cpp + plugincfg.cpp + prefcfg.cpp + search.cpp + searchall.cpp + smscfg.cpp + status.cpp + statuswnd.cpp + textedit_menu.cpp + tmpl.cpp + toolbar_container.cpp + toolbar_history.cpp + toolbar_main.cpp + toolbar_msgedit.cpp + toolbar_textedit.cpp + toolbarcfg.cpp + toolsetup.cpp + usercfg.cpp + userhistorycfg.cpp + userlist.cpp + userview.cpp + userviewcfg.cpp + userviewdelegate.cpp + userwnd.cpp +) + +# is this really needed? +IF(NOT WIN32) +SET(_core_SRCS + ${_core_SRCS} + libintl.cpp + ) +ENDIF(NOT WIN32) + +SET(_core_HDRS + arcfg.h + autoreply.h + cfgdlg.h + cmenu.h + commands.h + connectionsettings.h + connectwnd.h + container.h + core.h + core_consts.h + core_events.h + declinedlg.h + editmail.h + editphone.h + filecfg.h + filetransfer.h + history.h + historycfg.h + historywnd.h + interfacecfg.h + logindlg.h + maininfo.h + mainwin.h + manager.h + msgauth.h + msgcfg.h + msgcontacts.h + msgedit.h + msgfile.h + msggen.h + msgrecv.h + msgsms.h + msgurl.h + msgview.h + newprotocol.h + nonim.h + pagerdetails.h + phonedetails.h + plugincfg.h + prefcfg.h + search.h + searchall.h + smscfg.h + status.h + statuswnd.h + tmpl.h + toolbarcfg.h + toolsetup.h + usercfg.h + userhistorycfg.h + userlist.h + userview.h + userviewcfg.h + userviewdelegate.h + userwnd.h +) + +SET(_core_UICS + arcfgbase.ui + autoreplybase.ui + cfgdlgbase.ui + connectionsettingsbase.ui + connectwndbase.ui + declinedlgbase.ui + editmailbase.ui + editphonebase.ui + filecfgbase.ui + filetransferbase.ui + fontconfigbase.ui + historycfgbase.ui + interfacecfgbase.ui + logindlgbase.ui + maininfobase.ui + managerbase.ui + msgcfgbase.ui + newprotocolbase.ui + nonimbase.ui + pagerbase.ui + phonebase.ui + plugincfgbase.ui + prefcfgbase.ui + searchallbase.ui + searchbase.ui + smscfgbase.ui + toolsetupbase.ui + userhistorycfgbase.ui + userviewcfgbase.ui +) + +# so we don't need an extra CMakeLists.txt in every subdirectory +ADD_JISP_ARCHIVE(jisp sim.jisp _core_SRCS) + +IF (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/jisp/icondef.xml) + message( "Using non-GPL icons" ) + ADD_JISP_ARCHIVE(GPL-Icons GPL-Icons.jisp _core_SRCS) +ELSE (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/jisp/icondef.xml) + message( "Using GPL icons" ) + # substitute with gpl icons + ADD_JISP_ARCHIVE(GPL-Icons sim.jisp _core_SRCS) +ENDIF (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/jisp/icondef.xml) + +ADD_JISP_ARCHIVE(smiles smiles.jisp _core_SRCS) +ADD_JISP_ARCHIVE(additional additional.jisp _core_SRCS) +ADD_JISP_ARCHIVE(icq5 icq5.jisp _core_SRCS) +ADD_JISP_ARCHIVE(icq5.1 icq5.1.jisp _core_SRCS) +ADD_JISP_ARCHIVE(icqlite icqlite.jisp _core_SRCS) +ADD_JISP_ARCHIVE(qip-icons qip-icons.jisp _core_SRCS) +ADD_JISP_ARCHIVE(lovenmoney lovenmoney.jisp _core_SRCS) +ADD_JISP_ARCHIVE(yahoo yahoo.jisp _core_SRCS) +ADD_JISP_ARCHIVE(msn msn.jisp _core_SRCS) + +FILE(GLOB _prebuilt emoticons_prebuilt/*.jisp) + +IF(APPLE) + FOREACH(FILE ${_prebuilt}) + GET_FILENAME_COMPONENT(FILENAME ${FILE} NAME) + CONFIGURE_FILE(${FILE} ${SIM_ICONS_DIR}/${NAME} COPYONLY) + ENDFOREACH(FILE) +ENDIF(APPLE) + +INSTALL(FILES ${_prebuilt} DESTINATION ${SIM_ICONS_DIR}) + +SIM_ADD_PLUGIN(_core) + +SET_TARGET_PROPERTIES(_core PROPERTIES DEFINE_SYMBOL CORE_EXPORTS) diff --git a/plugins/_core/GPL-Icons/1downarrow.png b/plugins/_core/GPL-Icons/1downarrow.png new file mode 100644 index 0000000..a966b09 Binary files /dev/null and b/plugins/_core/GPL-Icons/1downarrow.png differ diff --git a/plugins/_core/GPL-Icons/1leftarrow.png b/plugins/_core/GPL-Icons/1leftarrow.png new file mode 100644 index 0000000..31d2cc1 Binary files /dev/null and b/plugins/_core/GPL-Icons/1leftarrow.png differ diff --git a/plugins/_core/GPL-Icons/1rightarrow.png b/plugins/_core/GPL-Icons/1rightarrow.png new file mode 100644 index 0000000..644d5b2 Binary files /dev/null and b/plugins/_core/GPL-Icons/1rightarrow.png differ diff --git a/plugins/_core/GPL-Icons/1uparrow.png b/plugins/_core/GPL-Icons/1uparrow.png new file mode 100644 index 0000000..fe5cc3d Binary files /dev/null and b/plugins/_core/GPL-Icons/1uparrow.png differ diff --git a/plugins/_core/GPL-Icons/SMS-protocol.png b/plugins/_core/GPL-Icons/SMS-protocol.png new file mode 100644 index 0000000..9de696e Binary files /dev/null and b/plugins/_core/GPL-Icons/SMS-protocol.png differ diff --git a/plugins/_core/GPL-Icons/aim_online.png b/plugins/_core/GPL-Icons/aim_online.png new file mode 100644 index 0000000..e766311 Binary files /dev/null and b/plugins/_core/GPL-Icons/aim_online.png differ diff --git a/plugins/_core/GPL-Icons/auth.png b/plugins/_core/GPL-Icons/auth.png new file mode 100644 index 0000000..96a0650 Binary files /dev/null and b/plugins/_core/GPL-Icons/auth.png differ diff --git a/plugins/_core/GPL-Icons/birthday.png b/plugins/_core/GPL-Icons/birthday.png new file mode 100644 index 0000000..5567dff Binary files /dev/null and b/plugins/_core/GPL-Icons/birthday.png differ diff --git a/plugins/_core/GPL-Icons/button_cancel.png b/plugins/_core/GPL-Icons/button_cancel.png new file mode 100644 index 0000000..62c742b Binary files /dev/null and b/plugins/_core/GPL-Icons/button_cancel.png differ diff --git a/plugins/_core/GPL-Icons/button_ok.png b/plugins/_core/GPL-Icons/button_ok.png new file mode 100644 index 0000000..ed26e51 Binary files /dev/null and b/plugins/_core/GPL-Icons/button_ok.png differ diff --git a/plugins/_core/GPL-Icons/cell.png b/plugins/_core/GPL-Icons/cell.png new file mode 100644 index 0000000..d46981f Binary files /dev/null and b/plugins/_core/GPL-Icons/cell.png differ diff --git a/plugins/_core/GPL-Icons/collapsed.png b/plugins/_core/GPL-Icons/collapsed.png new file mode 100644 index 0000000..28012f0 Binary files /dev/null and b/plugins/_core/GPL-Icons/collapsed.png differ diff --git a/plugins/_core/GPL-Icons/configure.png b/plugins/_core/GPL-Icons/configure.png new file mode 100644 index 0000000..ec60f61 Binary files /dev/null and b/plugins/_core/GPL-Icons/configure.png differ diff --git a/plugins/_core/GPL-Icons/contacts.png b/plugins/_core/GPL-Icons/contacts.png new file mode 100644 index 0000000..d0ea475 Binary files /dev/null and b/plugins/_core/GPL-Icons/contacts.png differ diff --git a/plugins/_core/GPL-Icons/def_status_away.png b/plugins/_core/GPL-Icons/def_status_away.png new file mode 100644 index 0000000..9f45788 Binary files /dev/null and b/plugins/_core/GPL-Icons/def_status_away.png differ diff --git a/plugins/_core/GPL-Icons/def_status_dnd.png b/plugins/_core/GPL-Icons/def_status_dnd.png new file mode 100644 index 0000000..c741e8a Binary files /dev/null and b/plugins/_core/GPL-Icons/def_status_dnd.png differ diff --git a/plugins/_core/GPL-Icons/def_status_ffc.png b/plugins/_core/GPL-Icons/def_status_ffc.png new file mode 100644 index 0000000..17fad22 Binary files /dev/null and b/plugins/_core/GPL-Icons/def_status_ffc.png differ diff --git a/plugins/_core/GPL-Icons/def_status_na.png b/plugins/_core/GPL-Icons/def_status_na.png new file mode 100644 index 0000000..5039a30 Binary files /dev/null and b/plugins/_core/GPL-Icons/def_status_na.png differ diff --git a/plugins/_core/GPL-Icons/def_status_occupied.png b/plugins/_core/GPL-Icons/def_status_occupied.png new file mode 100644 index 0000000..b75ad80 Binary files /dev/null and b/plugins/_core/GPL-Icons/def_status_occupied.png differ diff --git a/plugins/_core/GPL-Icons/empty.png b/plugins/_core/GPL-Icons/empty.png new file mode 100644 index 0000000..f144576 Binary files /dev/null and b/plugins/_core/GPL-Icons/empty.png differ diff --git a/plugins/_core/GPL-Icons/error.png b/plugins/_core/GPL-Icons/error.png new file mode 100644 index 0000000..55b10d9 Binary files /dev/null and b/plugins/_core/GPL-Icons/error.png differ diff --git a/plugins/_core/GPL-Icons/exit.png b/plugins/_core/GPL-Icons/exit.png new file mode 100644 index 0000000..0a6ee21 Binary files /dev/null and b/plugins/_core/GPL-Icons/exit.png differ diff --git a/plugins/_core/GPL-Icons/expanded.png b/plugins/_core/GPL-Icons/expanded.png new file mode 100644 index 0000000..eb2d94a Binary files /dev/null and b/plugins/_core/GPL-Icons/expanded.png differ diff --git a/plugins/_core/GPL-Icons/fax.png b/plugins/_core/GPL-Icons/fax.png new file mode 100644 index 0000000..8d94651 Binary files /dev/null and b/plugins/_core/GPL-Icons/fax.png differ diff --git a/plugins/_core/GPL-Icons/file.png b/plugins/_core/GPL-Icons/file.png new file mode 100644 index 0000000..f6e3175 Binary files /dev/null and b/plugins/_core/GPL-Icons/file.png differ diff --git a/plugins/_core/GPL-Icons/fileopen.png b/plugins/_core/GPL-Icons/fileopen.png new file mode 100644 index 0000000..a7b926a Binary files /dev/null and b/plugins/_core/GPL-Icons/fileopen.png differ diff --git a/plugins/_core/GPL-Icons/filesave.png b/plugins/_core/GPL-Icons/filesave.png new file mode 100644 index 0000000..9a2c1e8 Binary files /dev/null and b/plugins/_core/GPL-Icons/filesave.png differ diff --git a/plugins/_core/GPL-Icons/find_user.png b/plugins/_core/GPL-Icons/find_user.png new file mode 100644 index 0000000..41c791f Binary files /dev/null and b/plugins/_core/GPL-Icons/find_user.png differ diff --git a/plugins/_core/GPL-Icons/floating.png b/plugins/_core/GPL-Icons/floating.png new file mode 100644 index 0000000..e85c587 Binary files /dev/null and b/plugins/_core/GPL-Icons/floating.png differ diff --git a/plugins/_core/GPL-Icons/fonts.png b/plugins/_core/GPL-Icons/fonts.png new file mode 100644 index 0000000..41deec9 Binary files /dev/null and b/plugins/_core/GPL-Icons/fonts.png differ diff --git a/plugins/_core/GPL-Icons/gadu_away.png b/plugins/_core/GPL-Icons/gadu_away.png new file mode 100644 index 0000000..a3ecf05 Binary files /dev/null and b/plugins/_core/GPL-Icons/gadu_away.png differ diff --git a/plugins/_core/GPL-Icons/gadu_dnd.png b/plugins/_core/GPL-Icons/gadu_dnd.png new file mode 100644 index 0000000..78f481c Binary files /dev/null and b/plugins/_core/GPL-Icons/gadu_dnd.png differ diff --git a/plugins/_core/GPL-Icons/gadu_invisible.png b/plugins/_core/GPL-Icons/gadu_invisible.png new file mode 100644 index 0000000..6be766e Binary files /dev/null and b/plugins/_core/GPL-Icons/gadu_invisible.png differ diff --git a/plugins/_core/GPL-Icons/gadu_offline.png b/plugins/_core/GPL-Icons/gadu_offline.png new file mode 100644 index 0000000..08b1bf5 Binary files /dev/null and b/plugins/_core/GPL-Icons/gadu_offline.png differ diff --git a/plugins/_core/GPL-Icons/gadu_online.png b/plugins/_core/GPL-Icons/gadu_online.png new file mode 100644 index 0000000..46f062c Binary files /dev/null and b/plugins/_core/GPL-Icons/gadu_online.png differ diff --git a/plugins/_core/GPL-Icons/group_collapsed.png b/plugins/_core/GPL-Icons/group_collapsed.png new file mode 100644 index 0000000..aa81ce5 Binary files /dev/null and b/plugins/_core/GPL-Icons/group_collapsed.png differ diff --git a/plugins/_core/GPL-Icons/group_expanded.png b/plugins/_core/GPL-Icons/group_expanded.png new file mode 100644 index 0000000..149d8d5 Binary files /dev/null and b/plugins/_core/GPL-Icons/group_expanded.png differ diff --git a/plugins/_core/GPL-Icons/grp_create.png b/plugins/_core/GPL-Icons/grp_create.png new file mode 100644 index 0000000..4396d4b Binary files /dev/null and b/plugins/_core/GPL-Icons/grp_create.png differ diff --git a/plugins/_core/GPL-Icons/grp_off.png b/plugins/_core/GPL-Icons/grp_off.png new file mode 100644 index 0000000..9a49365 Binary files /dev/null and b/plugins/_core/GPL-Icons/grp_off.png differ diff --git a/plugins/_core/GPL-Icons/grp_on.png b/plugins/_core/GPL-Icons/grp_on.png new file mode 100644 index 0000000..66a9fe8 Binary files /dev/null and b/plugins/_core/GPL-Icons/grp_on.png differ diff --git a/plugins/_core/GPL-Icons/grp_rename.png b/plugins/_core/GPL-Icons/grp_rename.png new file mode 100644 index 0000000..d11a1c9 Binary files /dev/null and b/plugins/_core/GPL-Icons/grp_rename.png differ diff --git a/plugins/_core/GPL-Icons/home.png b/plugins/_core/GPL-Icons/home.png new file mode 100644 index 0000000..611b814 Binary files /dev/null and b/plugins/_core/GPL-Icons/home.png differ diff --git a/plugins/_core/GPL-Icons/icondef.xml b/plugins/_core/GPL-Icons/icondef.xml new file mode 100644 index 0000000..c0393c0 --- /dev/null +++ b/plugins/_core/GPL-Icons/icondef.xml @@ -0,0 +1,437 @@ + + + + SIM smiles + 0.9.6 + GPL Sim-IM icons + Nikolay Shplov + 2004-06-11 + http://www.sim-im.org + + + + sim.png + + + + + + jabber.png + + + + + jabber_offline.png + + + + + + icq_online.png + + + + + + msn_online.png + + + + + + aim_online.png + + + + + + yahoo_online.png + + + + + yahoo_offline.png + + + + + + yahoo_away.png + + + + + + + yahoo_na.png + + + + + + + yahoo_dnd.png + + + + + + + yahoo_invisible.png + + + + + + + + gadu_online.png + + + + + gadu_away.png + + + + + + gadu_dnd.png + + + + + + + gadu_invisible.png + + + + + + + gadu_offline.png + + + + + + def_status_away.png + + + + + + def_status_na.png + + + + + def_status_dnd.png + + + + + def_status_occupied.png + + + + + def_status_ffc.png + + + + + + exit.png + + + + + + button_ok.png + + + + + button_cancel.png + + + + + + + 1downarrow.png + + + + + 1uparrow.png + + + + + 1leftarrow.png + + + + + 1rightarrow.png + + + + + + configure.png + + + + + + fileopen.png + + + + + filesave.png + + + + + + remove.png + + + + + error.png + + + + + + + group_collapsed.png + + + + + group_expanded.png + + + + + + mail_generic.png + + + + + info.png + + + + + fonts.png + + + + + + phone.png + + + + + + fax.png + + + + + cell.png + + + + + pager.png + + + + + + + no_phone.png + + + + + + webpress.png + + + + + + find_user.png + + + + + + + + non-im-contact.png + + + + + + online_on.png + + + + + online_off.png + + + + + + grp_on.png + + + + + grp_off.png + + + + + + + grp_create.png + + + + + + + + grp_rename.png + + + + + + + + home.png + + + + + work.png + + + + + security.png + + + + + run.png + + + + + + + + network.png + + + + + + + message.png + + + + + file.png + + + + + + sms.png + + + + + + + + url.png + + + + + contacts.png + + + + + + + auth.png + + + + + + + empty.png + + + + + + floating.png + + + + + + + unknown_icon_1.png + + + + + + + SMS-protocol.png + + + + + birthday.png + + + + + + + + + + + + diff --git a/plugins/_core/GPL-Icons/icq_online.png b/plugins/_core/GPL-Icons/icq_online.png new file mode 100644 index 0000000..8a9dac2 Binary files /dev/null and b/plugins/_core/GPL-Icons/icq_online.png differ diff --git a/plugins/_core/GPL-Icons/jabber.png b/plugins/_core/GPL-Icons/jabber.png new file mode 100644 index 0000000..4395d5d Binary files /dev/null and b/plugins/_core/GPL-Icons/jabber.png differ diff --git a/plugins/_core/GPL-Icons/jabber_offline.png b/plugins/_core/GPL-Icons/jabber_offline.png new file mode 100644 index 0000000..c5a7e31 Binary files /dev/null and b/plugins/_core/GPL-Icons/jabber_offline.png differ diff --git a/plugins/_core/GPL-Icons/mail_generic.png b/plugins/_core/GPL-Icons/mail_generic.png new file mode 100644 index 0000000..27187d7 Binary files /dev/null and b/plugins/_core/GPL-Icons/mail_generic.png differ diff --git a/plugins/_core/GPL-Icons/message.png b/plugins/_core/GPL-Icons/message.png new file mode 100644 index 0000000..631d4e3 Binary files /dev/null and b/plugins/_core/GPL-Icons/message.png differ diff --git a/plugins/_core/GPL-Icons/msn_online.png b/plugins/_core/GPL-Icons/msn_online.png new file mode 100644 index 0000000..a6dcfe9 Binary files /dev/null and b/plugins/_core/GPL-Icons/msn_online.png differ diff --git a/plugins/_core/GPL-Icons/network.png b/plugins/_core/GPL-Icons/network.png new file mode 100644 index 0000000..a457ee2 Binary files /dev/null and b/plugins/_core/GPL-Icons/network.png differ diff --git a/plugins/_core/GPL-Icons/no_phone.png b/plugins/_core/GPL-Icons/no_phone.png new file mode 100644 index 0000000..b357f2a Binary files /dev/null and b/plugins/_core/GPL-Icons/no_phone.png differ diff --git a/plugins/_core/GPL-Icons/non-im-contact.png b/plugins/_core/GPL-Icons/non-im-contact.png new file mode 100644 index 0000000..d31e63f Binary files /dev/null and b/plugins/_core/GPL-Icons/non-im-contact.png differ diff --git a/plugins/_core/GPL-Icons/online_off.png b/plugins/_core/GPL-Icons/online_off.png new file mode 100644 index 0000000..1d95664 Binary files /dev/null and b/plugins/_core/GPL-Icons/online_off.png differ diff --git a/plugins/_core/GPL-Icons/online_on.png b/plugins/_core/GPL-Icons/online_on.png new file mode 100644 index 0000000..846c8ca Binary files /dev/null and b/plugins/_core/GPL-Icons/online_on.png differ diff --git a/plugins/_core/GPL-Icons/pager.png b/plugins/_core/GPL-Icons/pager.png new file mode 100644 index 0000000..b6e7555 Binary files /dev/null and b/plugins/_core/GPL-Icons/pager.png differ diff --git a/plugins/_core/GPL-Icons/phone.png b/plugins/_core/GPL-Icons/phone.png new file mode 100644 index 0000000..9e07c27 Binary files /dev/null and b/plugins/_core/GPL-Icons/phone.png differ diff --git a/plugins/_core/GPL-Icons/remove.png b/plugins/_core/GPL-Icons/remove.png new file mode 100644 index 0000000..5eb5af6 Binary files /dev/null and b/plugins/_core/GPL-Icons/remove.png differ diff --git a/plugins/_core/GPL-Icons/run.png b/plugins/_core/GPL-Icons/run.png new file mode 100644 index 0000000..b1ed6e0 Binary files /dev/null and b/plugins/_core/GPL-Icons/run.png differ diff --git a/plugins/_core/GPL-Icons/security.png b/plugins/_core/GPL-Icons/security.png new file mode 100644 index 0000000..5294896 Binary files /dev/null and b/plugins/_core/GPL-Icons/security.png differ diff --git a/plugins/_core/GPL-Icons/sim.png b/plugins/_core/GPL-Icons/sim.png new file mode 100644 index 0000000..d774a63 Binary files /dev/null and b/plugins/_core/GPL-Icons/sim.png differ diff --git a/plugins/_core/GPL-Icons/sms.png b/plugins/_core/GPL-Icons/sms.png new file mode 100644 index 0000000..a6623f4 Binary files /dev/null and b/plugins/_core/GPL-Icons/sms.png differ diff --git a/plugins/_core/GPL-Icons/unknown_icon_1.png b/plugins/_core/GPL-Icons/unknown_icon_1.png new file mode 100644 index 0000000..74518da Binary files /dev/null and b/plugins/_core/GPL-Icons/unknown_icon_1.png differ diff --git a/plugins/_core/GPL-Icons/url.png b/plugins/_core/GPL-Icons/url.png new file mode 100644 index 0000000..9b67db4 Binary files /dev/null and b/plugins/_core/GPL-Icons/url.png differ diff --git a/plugins/_core/GPL-Icons/webpress.png b/plugins/_core/GPL-Icons/webpress.png new file mode 100644 index 0000000..dfb9feb Binary files /dev/null and b/plugins/_core/GPL-Icons/webpress.png differ diff --git a/plugins/_core/GPL-Icons/work.png b/plugins/_core/GPL-Icons/work.png new file mode 100644 index 0000000..6bd1403 Binary files /dev/null and b/plugins/_core/GPL-Icons/work.png differ diff --git a/plugins/_core/GPL-Icons/yahoo_away.png b/plugins/_core/GPL-Icons/yahoo_away.png new file mode 100644 index 0000000..310b3ca Binary files /dev/null and b/plugins/_core/GPL-Icons/yahoo_away.png differ diff --git a/plugins/_core/GPL-Icons/yahoo_dnd.png b/plugins/_core/GPL-Icons/yahoo_dnd.png new file mode 100644 index 0000000..36c3a83 Binary files /dev/null and b/plugins/_core/GPL-Icons/yahoo_dnd.png differ diff --git a/plugins/_core/GPL-Icons/yahoo_invisible.png b/plugins/_core/GPL-Icons/yahoo_invisible.png new file mode 100644 index 0000000..d3248b2 Binary files /dev/null and b/plugins/_core/GPL-Icons/yahoo_invisible.png differ diff --git a/plugins/_core/GPL-Icons/yahoo_na.png b/plugins/_core/GPL-Icons/yahoo_na.png new file mode 100644 index 0000000..7a47c70 Binary files /dev/null and b/plugins/_core/GPL-Icons/yahoo_na.png differ diff --git a/plugins/_core/GPL-Icons/yahoo_offline.png b/plugins/_core/GPL-Icons/yahoo_offline.png new file mode 100644 index 0000000..043db7c Binary files /dev/null and b/plugins/_core/GPL-Icons/yahoo_offline.png differ diff --git a/plugins/_core/GPL-Icons/yahoo_online.png b/plugins/_core/GPL-Icons/yahoo_online.png new file mode 100644 index 0000000..d144cab Binary files /dev/null and b/plugins/_core/GPL-Icons/yahoo_online.png differ diff --git a/plugins/_core/_core.vcproj b/plugins/_core/_core.vcproj new file mode 100644 index 0000000..3ae6853 --- /dev/null +++ b/plugins/_core/_core.vcproj @@ -0,0 +1,4408 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/_core/additional/0.png b/plugins/_core/additional/0.png new file mode 100644 index 0000000..5993786 Binary files /dev/null and b/plugins/_core/additional/0.png differ diff --git a/plugins/_core/additional/1.png b/plugins/_core/additional/1.png new file mode 100644 index 0000000..9034cc0 Binary files /dev/null and b/plugins/_core/additional/1.png differ diff --git a/plugins/_core/additional/icondef.xml b/plugins/_core/additional/icondef.xml new file mode 100644 index 0000000..15b291e --- /dev/null +++ b/plugins/_core/additional/icondef.xml @@ -0,0 +1,19 @@ + + + + SIM smiles + 0.9.6 + SIM smiles. + Vladimir Shutoff + 2004-06-11 + http://sim-im.berlios.de/ + + + *EYES OPEN* + 0.png + + + *UGLY* + 1.png + + diff --git a/plugins/_core/arcfg.cpp b/plugins/_core/arcfg.cpp new file mode 100644 index 0000000..41329c9 --- /dev/null +++ b/plugins/_core/arcfg.cpp @@ -0,0 +1,121 @@ +/*************************************************************************** + arcfg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "arcfg.h" +#include "core.h" +#include "simgui/ballonmsg.h" +#include "simgui/editfile.h" +#include "contacts/contact.h" +#include "contacts/group.h" + +#include +#include + +using namespace SIM; + +ARConfig::ARConfig(QWidget *p, unsigned status, const QString &name, Contact *contact) + : QWidget(p) + , m_status(status) + , m_contact(contact) +{ + setupUi(this); + setButtonsPict(this); + tabAR->setTabText(tabAR->indexOf(tab), name); + SIM::PropertyHubPtr ar; + QString text; + SIM::PropertyHubPtr core = CorePlugin::instance()->propertyHub(); + QString noShow = core->stringMapValue("NoShowAutoReply", m_status); + if (m_contact) + { + chkNoShow->hide(); + connect(chkOverride, SIGNAL(toggled(bool)), this, SLOT(toggled(bool))); + ar = m_contact->getUserData()->getUserData("AR"); + if (ar) + text = ar->stringMapValue("AutoReply", m_status); + if (!text.isEmpty()) + chkOverride->setChecked(true); + else + { + ar.clear(); + Group *grp = getContacts()->group(m_contact->getGroup()); + if (grp) + ar = grp->getUserData()->getUserData("AR"); + if (!ar.isNull()) + text = ar->stringMapValue("AutoReply", m_status); + } + toggled(chkOverride->isChecked()); + } + else + chkOverride->hide(); + if (text.isEmpty()) + { + ar = getContacts()->getUserData("AR"); + if (!noShow.isEmpty()) + chkNoShow->setChecked(true); + text = ar->stringMapValue("AutoReply", m_status); + if (text.isEmpty()) + text = ar->stringMapValue("AutoReply", STATUS_AWAY); + } + edtAutoReply->setText(text); + EventTmplHelpList e; + e.process(); + edtAutoReply->setHelpList(e.helpList()); + connect(btnHelp, SIGNAL(clicked()), this, SLOT(help())); +} + +void ARConfig::apply() +{ + if (m_contact) + applyForSpecialUser(); + else + applyGlobal(); +} + +void ARConfig::applyForSpecialUser() +{ + SIM::PropertyHubPtr ar = m_contact->getUserData()->getUserData("AR"); + if (chkOverride->isChecked()) + { + if(ar.isNull()) + ar = m_contact->getUserData()->createUserData("AR"); + ar->setStringMapValue("AutoReply", m_status, edtAutoReply->toPlainText()); + } + else if (!ar.isNull()) + ar->setStringMapValue("AutoReply", m_status, QString::null); +} +void ARConfig::applyGlobal() +{ + SIM::PropertyHubPtr ar = getContacts()->getUserData("AR"); + ar->setStringMapValue("AutoReply", m_status, edtAutoReply->toPlainText()); + SIM::PropertyHubPtr core = CorePlugin::instance()->propertyHub(); + core->setStringMapValue("NoShowAutoReply", m_status, chkNoShow->isChecked() ? "1" : ""); +} +void ARConfig::toggled(bool bState) +{ + edtAutoReply->setEnabled(bState); +} + +void ARConfig::help() +{ + QString helpString = i18n("In text you can use:") + '\n'; + EventTmplHelp e(helpString); + e.process(); + BalloonMsg::message(e.help(), btnHelp, false, 400); +} + +// vim: set expandtab: + diff --git a/plugins/_core/arcfg.h b/plugins/_core/arcfg.h new file mode 100644 index 0000000..6b07243 --- /dev/null +++ b/plugins/_core/arcfg.h @@ -0,0 +1,45 @@ +/*************************************************************************** + arcfg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _ARCFG_H +#define _ARCFG_H + +#include +#include "contacts.h" + +#include "ui_arcfgbase.h" + +class ARConfig : public QWidget, public Ui::ARConfigBase +{ + Q_OBJECT +public: + ARConfig(QWidget *parent, unsigned status, const QString &name, SIM::Contact *contact); +public slots: + void apply(); + void applyGlobal(); + + void applyForSpecialUser(); + + void toggled(bool); + void help(); +protected: + unsigned m_status; + SIM::Contact *m_contact; +}; + +#endif + diff --git a/plugins/_core/arcfgbase.ui b/plugins/_core/arcfgbase.ui new file mode 100644 index 0000000..8d5156e --- /dev/null +++ b/plugins/_core/arcfgbase.ui @@ -0,0 +1,133 @@ + + + + + ARConfigBase + + + + 0 + 0 + 421 + 314 + + + + Form1 + + + + 11 + + + 6 + + + + + + + + + + 11 + + + 6 + + + + + &Override global settings + + + + + + + &Help + + + + + + + + 7 + 0 + + + + Don't show autoreply dialog + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Horizontal + + + + + + + + + + + + + + + QWidget + QWidget +
QWidget
+ + -1 + -1 + + 0 + + 5 + 5 + + image0 + + text + +
+ + MultiLineEdit + QWidget +
simgui/editfile.h
+ + -1 + -1 + + 0 + + 7 + 7 + + image1 +
+
+ + + 789c6dd2c10ac2300c00d07bbf2234b7229d1be245fc04c5a3201e4615f430059d0711ff5ddb2e6bb236ec90eed134cb5a19d8ef36602af5ecdbfeeac05dda0798d3abebde87e3faa374d3807fa0d633a52d38d8de6f679fe33fc776e196f53cd010188256a3600a292882096246517815ca99884606e18044a3a40d91824820924265a7923a2e8bcd05f33db1173e002913175f2a6be6d3294871a2d95fa00e8a94ee017b69d339d90df1e77c57ea072ede6758 + + + 789c6dd2c10ac2300c00d07bbf2234b7229d1ddec44f503c0ae2a154410f53d0ed20e2bf6bdb656dd6861dd23d9a66591b0587fd1654235ebded6f0edcd53e419d87ae7b1f4f9b8f906d0bfe012317426a70b07bdc2f3ec77f8ed6b89559061a0343d06a124cc105596482585094bc0ae599b04646c9018926491b2205e140c485cace25755c175d0a967b622ff900b8cc9c7d29af594ea722d589167f813aa852ba07d94b9dce296e883fe7bb163f23896753 + + +
diff --git a/plugins/_core/autoreply.cpp b/plugins/_core/autoreply.cpp new file mode 100644 index 0000000..340987a --- /dev/null +++ b/plugins/_core/autoreply.cpp @@ -0,0 +1,204 @@ +/*************************************************************************** + autoreply.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "icons.h" + +#include "autoreply.h" +#include "core.h" +#include "simgui/ballonmsg.h" +#include "simgui/editfile.h" +#include "contacts/client.h" + +#include +#include +#include +#include + +using namespace SIM; + +AutoReplyDialog::AutoReplyDialog(unsigned status) + : QDialog(NULL) + , m_status(status) + , m_time(15) + , m_timer(new QTimer(this)) +{ + setupUi(this); + SET_WNDPROC("mainwnd"); + QString text, icon; + if (!loadIconAndIconText(status, text, icon)) + return; + setWindowTitle(i18n("Autoreply message") + ' ' + i18n(text)); + setWindowIcon(Icon(icon)); + lblTime->setText(i18n("Close after %n second", "Close after %n seconds", m_time)); + connect(m_timer, SIGNAL(timeout()), this, SLOT(timeout())); + m_timer->start(1000); + SIM::PropertyHubPtr ar = getContacts()->getUserData("AR"); + text = ar->stringMapValue("AutoReply", m_status); + edtAutoResponse->setText(text); + connect(edtAutoResponse, SIGNAL(textChanged()), this, SLOT(textChanged())); + connect(chkNoShow, SIGNAL(toggled(bool)), this, SLOT(toggled(bool))); + connect(btnHelp, SIGNAL(clicked()), this, SLOT(help())); + EventTmplHelpList e; + e.process(); + edtAutoResponse->setHelpList(e.helpList()); +} + +AutoReplyDialog::AutoReplyDialog(const SIM::IMStatusPtr& status) + : QDialog(NULL) + , m_time(15) + , m_timer(new QTimer(this)) + , m_imstatus(status) +{ + setupUi(this); + initIconMap(); + QString text = status->text(); + QIcon icon = Icon(statusIcon(status)); + setWindowTitle(i18n("Autoreply message") + ' ' + i18n(text)); + setWindowIcon(icon); + lblTime->setText(i18n("Close after %n second", "Close after %n seconds", m_time)); + connect(m_timer, SIGNAL(timeout()), this, SLOT(timeout())); + m_timer->start(1000); + SIM::PropertyHubPtr ar = getContacts()->getUserData("AR"); + text = ar->value("AutoReply" + m_imstatus->id()).toString(); + edtAutoResponse->setText(text); + connect(edtAutoResponse, SIGNAL(textChanged()), this, SLOT(textChanged())); + connect(chkNoShow, SIGNAL(toggled(bool)), this, SLOT(toggled(bool))); + connect(btnHelp, SIGNAL(clicked()), this, SLOT(help())); + EventTmplHelpList e; + e.process(); + edtAutoResponse->setHelpList(e.helpList()); +} + +AutoReplyDialog::~AutoReplyDialog() +{ +} + +void AutoReplyDialog::initIconMap() +{ + m_iconmap.insert("online", "SIM_online"); + m_iconmap.insert("away", "SIM_away"); + m_iconmap.insert("n/a", "SIM_na"); + m_iconmap.insert("dnd", "SIM_dnd"); + m_iconmap.insert("occupied", "SIM_occupied"); + m_iconmap.insert("free_for_chat", "SIM_ffc"); + m_iconmap.insert("offline", "SIM_offline"); +} + +QString AutoReplyDialog::statusIcon(const SIM::IMStatusPtr& status) +{ + return m_iconmap.value(status->id()); +} + +bool AutoReplyDialog::loadIconAndIconText(unsigned status, QString &text, QString &icon) +{ + bool btextFound = true; + for (unsigned i = 0; i < getContacts()->nClients(); i++) + { + for (const CommandDef *d = getContacts()->getClient(i)->protocol()->statusList(); !d->text.isEmpty(); d++) + { + if (d->id == status) + { + text = d->text; + switch (d->id){ + case STATUS_ONLINE: + icon="SIM_online"; + break; + case STATUS_AWAY: + icon="SIM_away"; + break; + case STATUS_NA: + icon="SIM_na"; + break; + case STATUS_DND: + icon="SIM_dnd"; + break; + case STATUS_OCCUPIED: + icon="SIM_occupied"; + break; + case STATUS_FFC: + icon="SIM_ffc"; + break; + case STATUS_OFFLINE: + icon="SIM_offline"; + break; + default: + icon=d->icon; + break; + } + break; + } + } + if (!text.isEmpty()) + break; + } + if (text.isEmpty()) + return !btextFound; + return btextFound; +} + +void AutoReplyDialog::textChanged() +{ + stopTimer(); +} + +void AutoReplyDialog::toggled(bool) +{ + stopTimer(); +} + +void AutoReplyDialog::stopTimer() +{ + if (m_timer == NULL) + return; + delete m_timer; + m_timer = NULL; + lblTime->hide(); +} + +void AutoReplyDialog::timeout() +{ + if (--m_time <= 0) + { + accept(); + return; + } + lblTime->setText(i18n("Close after %n second", "Close after %n seconds", m_time)); +} + +void AutoReplyDialog::accept() +{ + SIM::PropertyHubPtr core = CorePlugin::instance()->propertyHub(); + core->setStringMapValue("NoShowAutoReply", m_status, chkNoShow->isChecked() ? "1" : ""); + core->setValue("NoShowAutoReply" + m_imstatus->id(), chkNoShow->isChecked()); + + SIM::PropertyHubPtr ar = getContacts()->getUserData("AR"); + ar->setStringMapValue("AutoReply", m_status, edtAutoResponse->toPlainText()); + core->setValue("AutoReply" + m_imstatus->id(), edtAutoResponse->toPlainText()); + m_imstatus->setText(edtAutoResponse->toPlainText()); + QDialog::accept(); +} + +void AutoReplyDialog::help() +{ + stopTimer(); + QString helpString = i18n("In text you can use:") + '\n'; + EventTmplHelp e(helpString); + e.process(); + BalloonMsg::message(e.help(), btnHelp, false, 400); +} + + diff --git a/plugins/_core/autoreply.h b/plugins/_core/autoreply.h new file mode 100644 index 0000000..64871fe --- /dev/null +++ b/plugins/_core/autoreply.h @@ -0,0 +1,55 @@ +/*************************************************************************** + autoreply.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _AUTOREPLY_H +#define _AUTOREPLY_H + +#include "contacts/imstatus.h" +#include "ui_autoreplybase.h" + +class AutoReplyDialog : public QDialog, public Ui::AutoReplyBase +{ + Q_OBJECT +public: + AutoReplyDialog(unsigned status); + AutoReplyDialog(const SIM::IMStatusPtr& status); + ~AutoReplyDialog(); + +protected slots: + void timeout(); + void textChanged(); + void toggled(bool); + void help(); + +protected: + void accept(); + void stopTimer(); + bool loadIconAndIconText(unsigned status, QString &text, QString &icon); + +private: + void initIconMap(); + QString statusIcon(const SIM::IMStatusPtr& status); + + unsigned m_status; + unsigned m_time; + QTimer *m_timer; + SIM::IMStatusPtr m_imstatus; + QMap m_iconmap; +}; + +#endif + diff --git a/plugins/_core/autoreplybase.ui b/plugins/_core/autoreplybase.ui new file mode 100644 index 0000000..c2cec07 --- /dev/null +++ b/plugins/_core/autoreplybase.ui @@ -0,0 +1,151 @@ + + + + + AutoReplyBase + + + + 0 + 0 + 351 + 247 + + + + MyDialog + + + true + + + + 11 + + + 6 + + + + + + + + Don't show this dialog + + + + + + + 0 + + + 6 + + + + + &Help + + + 4144 + + + + + + + + 7 + 1 + + + + + + + false + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Horizontal + + + + + + + &OK + + + true + + + true + + + + + + + &Cancel + + + true + + + + + + + + + + MultiLineEdit + QWidget +
simgui/editfile.h
+ + -1 + -1 + + 0 + + 7 + 7 + + image0 +
+
+ + + 789c6dd2c10ac2300c00d07bbf2234b7229d1ddec44f503c0ae2a154410f53d0ed20e2bf6bdb656dd6861dd23d9a66591b0587fd1654235ebded6f0edcd53e419d87ae7b1f4f9b8f906d0bfe012317426a70b07bdc2f3ec77f8ed6b89559061a0343d06a124cc105596482585094bc0ae599b04646c9018926491b2205e140c485cace25755c175d0a967b622ff900b8cc9c7d29af594ea722d589167f813aa852ba07d94b9dce296e883fe7bb163f23896753 + + + + + buttonOk + clicked() + AutoReply + accept() + + + buttonCancel + clicked() + AutoReply + reject() + + +
diff --git a/plugins/_core/cfgdlg.cpp b/plugins/_core/cfgdlg.cpp new file mode 100644 index 0000000..54f6042 --- /dev/null +++ b/plugins/_core/cfgdlg.cpp @@ -0,0 +1,642 @@ +/*************************************************************************** + cfgdlg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "icons.h" +#include "cfgdlg.h" +#include "plugincfg.h" +#include "maininfo.h" +#include "arcfg.h" +#include "buffer.h" +#include "core.h" +#include "contacts/client.h" +#include "profilemanager.h" +#include "log.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + + + + +using namespace ConfigDlg; + +//unsigned ConfigItem::defId = 0x10000; //obsoleted? +unsigned ConfigItem::curIndex; + +ConfigItem::ConfigItem(QTreeWidget *view, unsigned id) + : QTreeWidgetItem(view) +{ + init(id); +} + +ConfigItem::ConfigItem(QTreeWidgetItem *item, unsigned id) + : QTreeWidgetItem(item) +{ + init(id); +} + +ConfigItem::~ConfigItem() +{ + //deleteWidget(); //obsolete? +} + + +void ConfigItem::deleteWidget()//obsolete? +{ + /*if (m_widget){ + delete m_widget; + m_widget = NULL; + }*/ +} + +void ConfigItem::init(unsigned id) +{ + m_widget = NULL; + m_id = id; + QString key = QString::number(++curIndex); + while (key.length() < 4) + key = '0' + key; + setText(1, key); +} + +bool ConfigItem::raisePage(QWidget *w) +{ + if (m_widget == w) + { + treeWidget()->setCurrentItem(this); + return true; + } + for(int i = 0; i < childCount(); i++) + { + QTreeWidgetItem* item = child(i); + if (static_cast(item)->raisePage(w)) + return true; + } + return false; +} + +void ConfigItem::show() +{ + ConfigureDialog *dlg = static_cast(treeWidget()->topLevelWidget()); + if (m_widget == NULL) + { + m_widget = getWidget(dlg); + if (m_widget == NULL) + return; + m_id = dlg->wnd->addWidget(m_widget/*, id() ? id() : defId++*/); + dlg->wnd->setMinimumSize(dlg->wnd->sizeHint()); + QObject::connect(dlg, SIGNAL(applyChanges()), m_widget, SLOT(apply())); + QTimer::singleShot(50, dlg, SLOT(repaintCurrent())); + } + dlg->showUpdate(type() == CLIENT_ITEM); + dlg->wnd->setCurrentWidget(m_widget); +} + +void ConfigItem::apply() +{ +} + +QWidget *ConfigItem::getWidget(ConfigureDialog*) +{ + return NULL; +} + +class PluginItem : public ConfigItem +{ +public: + PluginItem(QTreeWidgetItem *view, const QString& name, const QString& title, unsigned id); + virtual void apply(); + virtual unsigned type() { return PLUGIN_ITEM; } +private: + virtual QWidget *getWidget(ConfigureDialog *dlg); + QString m_name; +}; + +PluginItem::PluginItem(QTreeWidgetItem *item, const QString& name, const QString& title, unsigned id) + : ConfigItem(item, id), m_name(name) +{ + setText(0, title); + setText(1, title); +} + +void PluginItem::apply() +{ + if (getPluginManager()->isPluginAlwaysEnabled(m_name)) + return; + if (m_widget) { + PluginCfg *w = static_cast(m_widget); + if (w->chkEnable->isChecked()) + ProfileManager::instance()->currentProfile()->enablePlugin(m_name); + else + ProfileManager::instance()->currentProfile()->disablePlugin(m_name); + delete m_widget; + m_widget = 0; + } +} + +QWidget *PluginItem::getWidget(ConfigureDialog *dlg) +{ + return new PluginCfg(dlg->wnd, m_name); +} + +class ClientItem : public ConfigItem +{ +public: + ClientItem(QTreeWidgetItem *item, Client *client, CommandDef *cmd); + ClientItem(QTreeWidget *view, Client *client, CommandDef *cmd); + Client *client() { return m_client; } + virtual unsigned type() { return CLIENT_ITEM; } +private: + void init(); + virtual QWidget *getWidget(ConfigureDialog *dlg); + CommandDef *m_cmd; + Client *m_client; +}; + +ClientItem::ClientItem(QTreeWidgetItem *item, Client *client, CommandDef *cmd) + : ConfigItem(item, 0) +{ + m_client = client; + m_cmd = cmd; + init(); +} + +ClientItem::ClientItem(QTreeWidget *view, Client *client, CommandDef *cmd) + : ConfigItem(view, 0) +{ + m_client = client; + m_cmd = cmd; + init(); +} + +void ClientItem::init() +{ + if (!m_cmd->text_wrk.isEmpty()){ + setText(0, m_cmd->text_wrk); + m_cmd->text_wrk = QString::null; + }else{ + setText(0, i18n(m_cmd->text)); + } + if (!m_cmd->icon.isEmpty()) + setIcon(0, Pict(m_cmd->icon)); +} + +QWidget *ClientItem::getWidget(ConfigureDialog *dlg) +{ + QWidget *res = m_client->configWindow(dlg, m_cmd->id); + if (res) + QObject::connect(dlg, SIGNAL(applyChanges(SIM::Client*, void*)), res, SLOT(apply(SIM::Client*, void*))); + return res; +} + +ARItem::ARItem(QTreeWidgetItem *item, const CommandDef *d) + : ConfigItem(item, 0) +{ + QString icon; + + m_status = d->id; + setText(0, i18n(d->text)); + switch (d->id){ + case STATUS_ONLINE: + icon="SIM_online"; + break; + case STATUS_AWAY: + icon="SIM_away"; + break; + case STATUS_NA: + icon="SIM_na"; + break; + case STATUS_DND: + icon="SIM_dnd"; + break; + case STATUS_OCCUPIED: + icon="SIM_occupied"; + break; + case STATUS_FFC: + icon="SIM_ffc"; + break; + case STATUS_OFFLINE: + icon="SIM_offline"; + break; + default: + icon=d->icon; + break; + } + setIcon(0, Pict(icon)); +} + +QWidget *ARItem::getWidget(ConfigureDialog *dlg) +{ + return new ARConfig(dlg, m_status, text(0), NULL); +} + +MainInfoItem::MainInfoItem(QTreeWidget *view, unsigned id) + : ConfigItem(view, id) +{ + setText(0, i18n("User info")); + setIcon(0, Pict("info")); +} + +QWidget *MainInfoItem::getWidget(ConfigureDialog *dlg) +{ + return new MainInfo(dlg, NULL); +} + + +using namespace ConfigDlg; + +ConfigureDialog::ConfigureDialog() + : QDialog(NULL) + , m_nUpdates(0) + , m_parentItem(NULL) +{ + setupUi(this); + setWindowIcon(Icon("configure")); + setButtonsPict(this); + setTitle(); + lstBox->header()->hide(); + QIcon iconSet = Icon("webpress"); + if (!iconSet.pixmap(QSize(16,16), QIcon::Normal).isNull()) + btnUpdate->setIcon(iconSet); + btnUpdate->hide(); + lstBox->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + fill(0); + connect(buttonApply, SIGNAL(clicked()), this, SLOT(apply())); + connect(btnUpdate, SIGNAL(clicked()), this, SLOT(updateInfo())); + connect(lstBox, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)), + this, SLOT(itemSelected(QTreeWidgetItem*, QTreeWidgetItem*))); + lstBox->setCurrentItem(lstBox->topLevelItem(0)); + itemSelected(lstBox->topLevelItem(0), 0); +} + +ConfigureDialog::~ConfigureDialog() +{ + lstBox->clear(); +} + +static unsigned itemWidth(QTreeWidgetItem *item, QFontMetrics &fm) +{ + unsigned w = fm.width(item->text(0)) + 64; + for(int i = 0; i < item->childCount(); i++) + { + QTreeWidgetItem *child = item->child(i); + w = qMax(w, itemWidth(child, fm)); + } + return w; +} + +void ConfigureDialog::fill(unsigned id) +{ + lstBox->clear(); + lstBox->sortItems(1, Qt::AscendingOrder); + + m_parentItem = new MainInfoItem(lstBox, 0); + for (unsigned i = 0; i < getContacts()->nClients(); i++){ + Client *client = getContacts()->getClient(i); + CommandDef *cmds = client->configWindows(); + if (cmds){ + m_parentItem = NULL; + for (; !cmds->text.isEmpty(); cmds++){ + if (m_parentItem){ + new ClientItem(m_parentItem, client, cmds); + }else{ + m_parentItem = new ClientItem(lstBox, client, cmds); + m_parentItem->setExpanded(true); + } + } + } + } + + unsigned long n; + m_parentItem = NULL; + list st; + for (n = 0; n < getContacts()->nClients(); n++){ + Protocol *protocol = getContacts()->getClient(n)->protocol(); + if ((protocol->description()->flags & (PROTOCOL_AR | PROTOCOL_AR_USER)) == 0) + continue; + if (m_parentItem == NULL){ + m_parentItem = new ConfigItem(lstBox, 0); + m_parentItem->setText(0, i18n("Autoreply")); + m_parentItem->setExpanded(true); + } + for (const CommandDef *d = protocol->statusList(); !d->text.isEmpty(); d++){ + if (((protocol->description()->flags & PROTOCOL_AR_OFFLINE) == 0) && + ((d->id == STATUS_ONLINE) || (d->id == STATUS_OFFLINE))) + continue; + list::iterator it; + for (it = st.begin(); it != st.end(); ++it) + if ((*it) == d->id) + break; + if (it != st.end()) + continue; + st.push_back(d->id); + new ARItem(m_parentItem, d); + } + } + + m_parentItem = new ConfigItem(lstBox, 0); + m_parentItem->setText(0, i18n("Plugins")); + m_parentItem->setIcon(0, Pict("run")); + m_parentItem->setExpanded(true); + + QStringList plugins = getPluginManager()->enumPlugins(); + foreach(QString plugin, plugins) + { + log(L_DEBUG, "plugin: %s", qPrintable(plugin)); + QString title = getPluginManager()->pluginTitle(plugin); + if(title.isEmpty()) + continue; + new PluginItem(m_parentItem, plugin, title, n); + } + + QFontMetrics fm(lstBox->font()); + unsigned w = 0; + for(int i = 0; i < lstBox->topLevelItemCount(); i++) + { + QTreeWidgetItem *item = lstBox->topLevelItem(i); + w = qMax(w, itemWidth(item, fm)); + } + lstBox->setFixedWidth(w); + lstBox->setColumnWidth(0, w - 2); + + if (id) + { + for(int i = 0; i < lstBox->topLevelItemCount(); i++) + { + QTreeWidgetItem *item = lstBox->topLevelItem(i); + if (setCurrentItem(item, id)) + return; + } + } + lstBox->setCurrentItem(lstBox->topLevelItem(0)); +} + +bool ConfigureDialog::setCurrentItem(QTreeWidgetItem *parent, unsigned id) +{ + if (static_cast(parent)->id() == id){ + lstBox->setCurrentItem(parent); + return true; + } + for(int i = 0; i < parent->childCount(); i++) + { + QTreeWidgetItem *item = parent->child(i); + if (setCurrentItem(item, id)) + return true; + } + return false; +} + +void ConfigureDialog::closeEvent(QCloseEvent *e) +{ + QDialog::closeEvent(e); + emit finished(); +} + +void ConfigureDialog::itemSelected(QTreeWidgetItem *item, QTreeWidgetItem* /* previous */) +{ + if (item) + { + static_cast(item)->show(); + lstBox->setCurrentItem(item); + } +} + +void ConfigureDialog::apply(QTreeWidgetItem *item) +{ + static_cast(item)->apply(); + for(int i = 0; i < item->childCount(); i++) + { + QTreeWidgetItem* it = item->child(i); + apply(it); + } +} + +void ConfigureDialog::reject() +{ + QDialog::reject(); + emit finished(); +} + +void ConfigureDialog::apply() +{ + bLanguageChanged = false; + m_bAccept = true; + emit applyChanges(); + if (!m_bAccept) + return; + for (unsigned i = 0; i < getContacts()->nClients(); i++){ + Client *client = getContacts()->getClient(i); + const DataDef *def = client->protocol()->userDataDef(); + if (def == NULL) + continue; + size_t size = 0; + for (const DataDef *d = def; d->name; ++d) + size += d->n_values; + Data *data = new Data[size]; + QByteArray cfg = client->getConfig(); + if (cfg.isEmpty()){ + load_data(def, data, NULL); + }else{ + Buffer config; + config = "[Title]\n" + cfg; + config.setWritePos(0); + config.getSection(); + load_data(def, data, &config); + } + emit applyChanges(client, data); + client->setClientInfo(data); + free_data(def, data); + delete[] data; + } + for(int i = 0; i < lstBox->topLevelItemCount(); i++) + { + QTreeWidgetItem *item = lstBox->topLevelItem(i); + apply(item); + } + if (bLanguageChanged){ + unsigned id = 0; + if (lstBox->currentItem()) + id = static_cast(lstBox->currentItem())->id(); + disconnect(lstBox, SIGNAL(currentChanged(QTreeWidgetItem*)), this, SLOT(itemSelected(QTreeWidgetItem*))); + fill(id); + connect(lstBox, SIGNAL(currentChanged(QTreeWidgetItem*)), this, SLOT(itemSelected(QTreeWidgetItem*))); + itemSelected(lstBox->currentItem(), 0); + buttonApply->setText(i18n("&Apply")); + buttonOk->setText(i18n("&OK")); + buttonCancel->setText(i18n("&Cancel")); + setWindowTitle(i18n("Setup")); + } + if (lstBox->currentItem()) + static_cast(lstBox->currentItem())->show(); + EventSaveState e; + e.process(); +} + +bool ConfigureDialog::processEvent(Event *e) +{ + if (e->type() == eEventLanguageChanged) + bLanguageChanged = true; + if (e->type() == eEventClientsChanged){ + unsigned id = 0; + if (lstBox->currentItem()) + id = static_cast(lstBox->currentItem())->id(); + fill(id); + } + if (e->type() == eEventClientChanged){ + if (m_nUpdates){ + if (--m_nUpdates == 0){ + setTitle(); + btnUpdate->setEnabled(true); + } + } + } + return false; +} + +void ConfigureDialog::setTitle() +{ + QString title = i18n("Configure"); + if (m_nUpdates){ + title += " ["; + title += i18n("Update info"); + title += ']'; + } + setWindowTitle(title); +} + +void ConfigureDialog::accept() +{ + apply(); + if (m_bAccept){ + QDialog::accept(); + emit finished(); + } +} + +void ConfigureDialog::showUpdate(bool bShow) +{ + if (bShow){ + btnUpdate->show(); + }else{ + btnUpdate->hide(); + } +} + +void ConfigureDialog::updateInfo() +{ + if (m_nUpdates) + return; + for (unsigned i = 0; i < getContacts()->nClients(); i++){ + m_nUpdates++; + getContacts()->getClient(i)->updateInfo(NULL, NULL); + } + btnUpdate->setEnabled(!m_nUpdates); + setTitle(); +} + +void ConfigureDialog::raisePage(Client *client) +{ + for(int i = 0; i < lstBox->topLevelItemCount(); i++) + { + QTreeWidgetItem *item = lstBox->topLevelItem(i); + if (static_cast(item)->type() != CLIENT_ITEM) + continue; + if (static_cast(item)->client() == client){ + lstBox->setCurrentItem(item); + //lstBox->ensureItemVisible(item); //FIXME + return; + } + } +} + +void ConfigureDialog::raisePage(QWidget *widget) +{ + if (!m_bAccept) + return; + for(int i = 0; i < lstBox->topLevelItemCount(); i++) + { + QTreeWidgetItem *item = lstBox->topLevelItem(i); + if (static_cast(item)->raisePage(widget)){ + m_bAccept = false; + break; + } + } +} + +void ConfigureDialog::raisePhoneBook() +{ + lstBox->setCurrentItem(lstBox->topLevelItem(0)); + QWidget *w = static_cast(lstBox->currentItem())->widget(); + if (w == NULL) + return; + QList l = topLevelWidget()->findChildren(); + if(l.isEmpty()) + return; + QTabWidget *tab = l.first(); + if(tab == NULL) + return; + tab->setCurrentIndex(2); +} + +void ConfigureDialog::repaintCurrent() +{ + QWidget *active = wnd->currentWidget(); + if (active == NULL) + return; + active->repaint(); + QTreeWidgetItem *item = findItem(active); + if (item) + lstBox->setCurrentItem(item); + lstBox->repaint(); +} + +QTreeWidgetItem *ConfigureDialog::findItem(QWidget *w) +{ + for(int i = 0; i < lstBox->topLevelItemCount(); i++) + { + QTreeWidgetItem *item = lstBox->topLevelItem(0); + QTreeWidgetItem *res = findItem(w, item); + if (res) + return res; + } + return NULL; +} + +QTreeWidgetItem *ConfigureDialog::findItem(QWidget *w, QTreeWidgetItem *parent) +{ + if (static_cast(parent)->m_widget == w) + return parent; + for(int i = 0; i < parent->childCount(); i++) + { + QTreeWidgetItem *item = parent->child(i); + QTreeWidgetItem *res = findItem(w, item); + if (res) + return res; + } + return NULL; +} + +// vim: set expandtab: diff --git a/plugins/_core/cfgdlg.h b/plugins/_core/cfgdlg.h new file mode 100644 index 0000000..865e7f1 --- /dev/null +++ b/plugins/_core/cfgdlg.h @@ -0,0 +1,120 @@ +/*************************************************************************** + cfgdlg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _CFGDLG_H +#define _CFGDLG_H + +#include "ui_cfgdlgbase.h" +#include +#include "event.h" + +namespace ConfigDlg +{ + +using namespace std; +using namespace SIM; + +const unsigned CONFIG_ITEM = 1; +const unsigned PLUGIN_ITEM = 2; +const unsigned CLIENT_ITEM = 3; +const unsigned MAIN_ITEM = 4; +const unsigned AR_ITEM = 5; + +class ConfigItem; + +class ConfigureDialog : public QDialog, public Ui::ConfigureDialogBase, public SIM::EventReceiver +{ + Q_OBJECT +public: + ConfigureDialog(); + ~ConfigureDialog(); + void raisePage(SIM::Client *client); + void raisePhoneBook(); + void showUpdate(bool bShow); +signals: + void applyChanges(); + void applyChanges(SIM::Client*, void*); + void finished(); +protected slots: + void apply(); + void updateInfo(); + void itemSelected(QTreeWidgetItem*, QTreeWidgetItem*); + void raisePage(QWidget*); + void repaintCurrent(); +protected: + void accept(); + void reject(); + void apply(QTreeWidgetItem *item); + virtual bool processEvent(SIM::Event*); + void fill(unsigned id); + void setTitle(); + bool setCurrentItem(QTreeWidgetItem *parent, unsigned id); + QTreeWidgetItem *findItem(QWidget *w); + QTreeWidgetItem *findItem(QWidget *w, QTreeWidgetItem *parent); + unsigned m_nUpdates; + bool m_bAccept; + void closeEvent(QCloseEvent*); + bool bLanguageChanged; +private: + ConfigItem *m_parentItem; +}; + +class ConfigItem : public QTreeWidgetItem +{ +public: + ConfigItem(QTreeWidgetItem *item, unsigned id); + ConfigItem(QTreeWidget *view, unsigned id); + ~ConfigItem(); + void show(); + void deleteWidget(); + virtual void apply(); + virtual unsigned type() { return CONFIG_ITEM; } + unsigned id() { return m_id; } + static unsigned curIndex; + bool raisePage(QWidget *w); + QWidget *widget() { return m_widget; } + QWidget *m_widget; +protected: + unsigned m_id; + static unsigned defId; + void init(unsigned id); + virtual QWidget *getWidget(ConfigureDialog *dlg); +}; + +class MainInfoItem : public ConfigItem +{ +public: + MainInfoItem(QTreeWidget *view, unsigned id); + unsigned type() { return MAIN_ITEM; } +protected: + virtual QWidget *getWidget(ConfigureDialog *dlg); +}; + +class ARItem : public ConfigItem +{ +public: + ARItem(QTreeWidgetItem *view, const CommandDef *d); + virtual unsigned type() { return AR_ITEM; } +private: + virtual QWidget *getWidget(ConfigureDialog *dlg); + unsigned m_status; +}; + + +} +#endif + diff --git a/plugins/_core/cfgdlgbase.ui b/plugins/_core/cfgdlgbase.ui new file mode 100644 index 0000000..7ea144a --- /dev/null +++ b/plugins/_core/cfgdlgbase.ui @@ -0,0 +1,177 @@ + + + ConfigureDialogBase + + + + 0 + 0 + 577 + 416 + + + + Setup + + + true + + + + 6 + + + 11 + + + + + 6 + + + 0 + + + + + + 0 + 0 + + + + 1 + + + false + + + false + + + + 1 + + + + + + + + + 0 + 0 + + + + 0 + + + + + + + + + + 6 + + + 0 + + + + + &Update + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + &Apply + + + true + + + + + + + &OK + + + true + + + true + + + + + + + &Cancel + + + true + + + + + + + + + + + buttonOk + clicked() + ConfigureDialogBase + accept() + + + 20 + 20 + + + 20 + 20 + + + + + buttonCancel + clicked() + ConfigureDialogBase + reject() + + + 20 + 20 + + + 20 + 20 + + + + + diff --git a/plugins/_core/cmenu.cpp b/plugins/_core/cmenu.cpp new file mode 100644 index 0000000..85e954f --- /dev/null +++ b/plugins/_core/cmenu.cpp @@ -0,0 +1,249 @@ +/*************************************************************************** + cmenu.cpp - description + ------------------- + begin : Sun Mar 10 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "cmddef.h" +#include "misc.h" +#include "icons.h" +#include "cmenu.h" +#include "commands.h" + +#include +#include +#include +#include + +using namespace SIM; + +CMenu::CMenu(CommandsDef *def) + : QMenu(NULL) + , m_def(def) + , m_param(NULL) + , m_bInit(false) +{ + connect(this, SIGNAL(aboutToShow()), this, SLOT(showMenu())); + connect(this, SIGNAL(aboutToHide()), this, SLOT(hideMenu())); + connect(this, SIGNAL(triggered(QAction*)), this, SLOT(menuActivated(QAction*))); +} + +CMenu::~CMenu() +{ +} + +void CMenu::setParam(void *param) +{ + m_param = param; +} + +void CMenu::processItem(CommandDef *s, bool &bSeparator, bool &bFirst, unsigned base_id) +{ + if (s->id == 0) + { + bSeparator = true; + return; + } + s->param = m_param; + if (s->flags & COMMAND_CHECK_STATE) + { + s->flags &= ~COMMAND_DISABLED; + s->text_wrk = QString::null; + s->flags |= COMMAND_CHECK_STATE; // FIXME: What for? COMMAND_CHECK_STATE BIT is already 1 if this code is execued, because of "if" above + if(!EventCheckCommandState(s).process()) + return; + if (s->flags & COMMAND_RECURSIVE) + { + CommandDef *cmds = (CommandDef*)(s->param); + for (CommandDef *cmd = cmds; !cmd->text.isEmpty(); cmd++) + { + processItem(cmd, bSeparator, bFirst, s->id); + } + delete[] cmds; + s->param = NULL; + return; + } + } + if(s->flags & BTN_HIDE) + return; + if (m_wrk->actions().count()) + { + QSize s = m_wrk->sizeHint(); + QWidget *desktop = qApp->desktop(); + int nHeight = (s.height() - 2 * 2) / m_wrk->actions().count(); + if (s.height() + nHeight * 2 + 2 * 2 >= desktop->height()){ + QAction *pAction = m_wrk->addAction(i18n("More...")); + QMenu *more = new QMenu(m_wrk); + pAction->setMenu(more); + m_wrk = more; + connect(m_wrk, SIGNAL(triggered(QAction*)), this, SLOT(menuActivated(QAction*))); + } + } + if (bFirst) + { + bFirst = false; + bSeparator = false; + } + else if (bSeparator) + { + m_wrk->addSeparator(); + bSeparator = false; + } + QIcon icons; + if ((s->flags & COMMAND_CHECKED) && !s->icon_on.isEmpty()) + icons = Icon(s->icon_on); + if (icons.isNull() && !s->icon.isEmpty()) + icons = Icon(s->icon); + QString title = i18n(s->text); + if (!s->text_wrk.isEmpty()) + { + title = s->text_wrk; + s->text_wrk = QString::null; + } + if (!s->accel.isEmpty()) + { + title += '\t'; + title += i18n(s->accel); + } + if (s->flags & COMMAND_TITLE) + { + if (!icons.isNull()) + { +// m_wrk->insertTitle(icons.pixmap(QIcon::Automatic, QIcon::Normal), title); + } + else + { +// m_wrk->insertTitle(title); + } + bFirst = true; + bSeparator = false; + return; + } + QMenu *popup = NULL; + if (s->popup_id) + { + EventMenuProcess e(s->popup_id, s->param, 0); + e.process(); + popup = e.menu(); + } + unsigned id = 0; + QAction *pAction = m_wrk->addAction(icons, title); + if (popup) + { + pAction->setMenu(popup); + } + else + { + CMD c; + c.id = s->id; + c.base_id = base_id; + m_cmds.push_back(c); + id = m_cmds.size(); + pAction->setData(QVariant(id)); + } + if (id) + { + if (s->flags & COMMAND_DISABLED) + pAction->setEnabled(false); + if (!s->accel.isEmpty()) + pAction->setShortcut(QKeySequence::fromString(i18n(s->accel))); + if ((s->flags & COMMAND_CHECKED) != 0) + { + pAction->setCheckable(true); + pAction->setChecked((s->flags & COMMAND_CHECKED) != 0); + } + } + bSeparator = false; +} + +void CMenu::showMenu() +{ + initMenu(); +} + +void CMenu::hideMenu() +{ + m_bInit = false; +} + +void CMenu::clearMenu() +{ + clear(); +} + +QSize CMenu::sizeHint() const +{ + ((CMenu*)this)->initMenu(); + return QMenu::sizeHint(); +} + +void CMenu::initMenu() +{ + if (m_bInit) + return; + m_bInit = true; + m_wrk = this; + clear(); + m_cmds.clear(); + bool bSeparator = false; + bool bFirst = true; + CommandsList list(*m_def); + CommandDef *s; + while ((s = ++list) != NULL) + { + processItem(s, bSeparator, bFirst, 0); + } +} + +void CMenu::menuActivated(QAction *pAction) +{ + int n = pAction->data().toInt(); + + if ((n < 1) || (n > (int)(m_cmds.size()))) + return; + + CMD c = m_cmds[n - 1]; + unsigned id = c.id; + if (c.base_id) + id = c.base_id; + + CommandsList list(*m_def, true); + CommandDef *s; + while ((s = ++list) != NULL){ + if (s->id == id){ + s->text_wrk = QString::null; + if (s->flags & COMMAND_CHECK_STATE){ + s->param = m_param; + s->flags |= COMMAND_CHECK_STATE; + if(!EventCheckCommandState(s).process()){ + s->text_wrk = QString::null; + return; + } + s->flags ^= COMMAND_CHECKED; + if (s->flags & COMMAND_RECURSIVE){ + CommandDef *cmds = (CommandDef*)(s->param); + delete[] cmds; + } + } + if (c.base_id) + s->id = c.id; + s->param = m_param; + EventCommandExec(s).process(); + s->text_wrk = QString::null; + s->id = id; + break; + } + } +} + diff --git a/plugins/_core/cmenu.h b/plugins/_core/cmenu.h new file mode 100644 index 0000000..1af6c64 --- /dev/null +++ b/plugins/_core/cmenu.h @@ -0,0 +1,58 @@ +/*************************************************************************** + cmenu.h - description + ------------------- + begin : Sun Mar 10 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _CMENU_H +#define _CMENU_H + +#include "simapi.h" + +#include + +#include "event.h" +#include + +struct CMD +{ + unsigned id; + unsigned base_id; +}; + +class CMenu : public QMenu +{ + Q_OBJECT +public: + CMenu(SIM::CommandsDef *def); + ~CMenu(); + void setParam(void *param); +protected slots: + void showMenu(); + void hideMenu(); + void menuActivated(QAction *action); + void clearMenu(); +protected: + void processItem(SIM::CommandDef *s, bool &bSeparator, bool &bFirst, unsigned base_id); + QSize sizeHint() const; + void initMenu(); + std::vector m_cmds; + SIM::CommandsDef *m_def; + QMenu *m_wrk; + void *m_param; + bool m_bInit; +}; + +#endif + diff --git a/plugins/_core/commands.cpp b/plugins/_core/commands.cpp new file mode 100644 index 0000000..2b3a306 --- /dev/null +++ b/plugins/_core/commands.cpp @@ -0,0 +1,343 @@ +/*************************************************************************** + commands.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "commands.h" +#include "simgui/toolbtn.h" +#include "toolsetup.h" +#include "core.h" +#include "cmenu.h" +#include "log.h" + +#include +#include +#include + +using namespace SIM; + +Commands::Commands() +{ + qApp->installEventFilter(this); +} + +Commands::~Commands() +{ + CMDS_MAP::iterator it; + for (it = bars.begin(); it != bars.end(); ++it) + delete it->second; + + MENU_MAP::iterator itm; + for (itm = menus.begin(); itm != menus.end(); ++itm) + { + MenuDef &def = itm->second; + delete def.menu; + delete def.def; + } +} + +CommandsDef *Commands::createBar(unsigned id) +{ + CMDS_MAP::iterator it = bars.find(id); + if (it != bars.end()) + return it->second; + CommandsDef *def = new CommandsDef(id, false); + bars.insert(CMDS_MAP::value_type(id, def)); + return def; +} + +void Commands::removeBar(unsigned id) +{ + CMDS_MAP::iterator it = bars.find(id); + if (it == bars.end()) + return; + delete it->second; + bars.erase(it); +} + +void Commands::clear() +{ + for (MENU_MAP::iterator it = menus.begin(); it != menus.end(); ++it) + if (it->second.menu) + { + delete it->second.menu; + it->second.menu = NULL; + } +} + +CommandsDef *Commands::createMenu(unsigned id) +{ + MENU_MAP::iterator it = menus.find(id); + if (it != menus.end()) + return it->second.def; + MenuDef def; + def.def = new CommandsDef(id, true); + def.menu = NULL; + def.param = NULL; + menus.insert(MENU_MAP::value_type(id, def)); + return def.def; +} + +void Commands::removeMenu(unsigned id) +{ + MENU_MAP::iterator it = menus.find(id); + if (it == menus.end()) + return; + if (it->second.menu) + delete it->second.menu; + delete it->second.def; + menus.erase(it); +} + +CToolBar *Commands::show(unsigned id, QMainWindow *parent) +{ + CMDS_MAP::iterator it = bars.find(id); + if (it == bars.end()) + return NULL; + QString sName = QString("Button") + QString::number(id); + it->second->setConfig(CorePlugin::instance()->value(sName.toLatin1().data())); + return new CToolBar(it->second, parent); +} + +CMenu *Commands::get(CommandDef *cmd) +{ + MENU_MAP::iterator it = menus.find(cmd->popup_id); + if (it == menus.end()) + return NULL; + MenuDef &d = it->second; + if (d.menu && (cmd->flags & COMMAND_NEW_POPUP) == 0) + { + d.menu->setParam(cmd->param); + return d.menu; + } + QString sName = QString("Menu") + QString::number(cmd->popup_id); + d.def->setConfig(CorePlugin::instance()->value(sName.toLatin1().data())); + CMenu *menu = new CMenu(d.def); + menu->setParam(cmd->param); + if ((cmd->flags & COMMAND_NEW_POPUP) != 0) + return menu; + + d.menu = menu; + return menu; +} + +CMenu *Commands::processMenu(unsigned id, void *param, int key) +{ + QKeySequence Key( key ); + MENU_MAP::iterator it = menus.find(id); + if (it == menus.end()) + return NULL; + MenuDef &d = it->second; + if (key) + { + CommandsList list(*d.def, true); + CommandDef *cmd; + while ((cmd = ++list) != NULL) + { + QKeySequence cmdKey; + if (key & Qt::ALT && (key & ~Qt::MODIFIER_MASK) != Qt::Key_Alt) + { + if (cmd->text.isEmpty()) + continue; + cmdKey = QKeySequence::mnemonic(i18n(cmd->text)); + if((cmdKey & ~Qt::UNICODE_ACCEL) == key) + { + cmd->param = param; + EventCommandExec eCmd(cmd); + if (eCmd.process()) + break; + } + } + if (cmd->accel.isEmpty()) + continue; + cmdKey = QKeySequence::fromString(i18n(cmd->accel)); + if (cmdKey == Key) + { + cmd->param = param; + EventCommandExec eCmd(cmd); + if (eCmd.process()) + break; + } + } + if (cmd == NULL) + return NULL; + } + if (d.menu) + { + d.menu->setParam(param); + return d.menu; + } + QString sName = QString("Menu") + QString::number(id); + d.def->setConfig(CorePlugin::instance()->value(sName.toLatin1().data())); + d.menu = new CMenu(d.def); + d.menu->setParam(param); + return d.menu; +} + +CommandsDef *Commands::getDef(unsigned id) +{ + MENU_MAP::iterator it = menus.find(id); + if (it == menus.end()) + return NULL; + return it->second.def; +} + +bool Commands::processEvent(Event *e) +{ + switch (e->type()) + { +// case eEventPluginsUnload: +// clear(); +// break; + case eEventToolbar: + { + EventToolbar *et = static_cast(e); + switch(et->action()) + { + case EventToolbar::eAdd: + createBar(et->id()); + break; + case EventToolbar::eShow: + et->setToolbar(show(et->id(), et->parent())); + break; + case EventToolbar::eRemove: + removeBar(et->id()); + break; + } + return true; + } + case eEventMenu: + { + EventMenu *em = static_cast(e); + switch(em->action()) + { + case EventMenu::eAdd: + createMenu(em->id()); + break; + case EventMenu::eRemove: + removeMenu(em->id()); + break; + case EventMenu::eCustomize: + customizeMenu(em->id()); + break; + } + return true; + } + case eEventMenuGet: + { + EventMenuGet *egm = static_cast(e); + egm->setMenu(get(egm->def())); + return true; + } + case eEventMenuGetDef: + { + EventMenuGetDef *mgd = static_cast(e); + mgd->setCommandsDef(getDef(mgd->id())); + return true; + } + case eEventMenuProcess: + { + EventMenuProcess *emp = static_cast(e); + emp->setMenu(processMenu(emp->id(), emp->param(), emp->key())); + return true; + } + default: + break; + } + return false; +} + +QObject* Commands::getParent(QObject *o) +{ + return o->parent(); +} + +bool Commands::eventFilter(QObject *o, QEvent *e) +{ + if (e->type() == QEvent::Show && o->inherits("QMenu") && !o->inherits("CMenu") && getParent(o)) + { + unsigned id = 0; + if (getParent(o)->inherits("MainWindow")) + id = ToolBarMain; + else if (getParent(o)->inherits("CToolBar")) + { + CToolBar *bar = static_cast(getParent(o)); + id = bar->m_def->id(); + } + if (id) + { + QMenu *popup = static_cast(o); + popup->addAction(i18n("Customize toolbar..."), this, SLOT(popupActivated())); + cur_id = id; + } + } + return QObject::eventFilter(o, e); +} + +void Commands::popupActivated() +{ + CMDS_MAP::iterator it = bars.find(cur_id); + if (it == bars.end()) + return; + customize(it->second); +} + +void Commands::customize(CommandsDef *def) +{ + QWidgetList list = QApplication::topLevelWidgets(); + QWidget * w; + ToolBarSetup *wnd = NULL; + foreach (w,list) + { + if(!w->inherits("ToolBarSetup")) + continue; + ToolBarSetup *swnd = static_cast(w); + if (swnd->m_def != def) + continue; + wnd = swnd; + break; + } + if (wnd == NULL) + wnd = new ToolBarSetup(this, def); + raiseWindow(wnd); +} + +void Commands::customizeMenu(unsigned long id) +{ + MENU_MAP::iterator it = menus.find(id); + if (it == menus.end()) + return; + MenuDef &d = it->second; + QString sName = QString("Menu") + QString::number(id); + d.def->setConfig(CorePlugin::instance()->value(sName.toLatin1().data())); + customize(d.def); +} + +void Commands::set(CommandsDef *def, const char *str) +{ + if (def->isMenu()) + { + QString sName = QString("Menu") + QString::number(def->id()); + CorePlugin::instance()->setValue(sName.toLatin1().data(), str); + } + else + { + QString sName = QString("Button") + QString::number(def->id()); + CorePlugin::instance()->setValue(sName.toLatin1().data(), str); + EventToolbarChanged(def).process(); + } +} + +// vim: set expandtab: diff --git a/plugins/_core/commands.h b/plugins/_core/commands.h new file mode 100644 index 0000000..e884d7b --- /dev/null +++ b/plugins/_core/commands.h @@ -0,0 +1,71 @@ +/*************************************************************************** + commands.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _COMMANDS_H +#define _COMMANDS_H + +#include +#include + +#include "event.h" + +#include + +class CorePlugin; +class CMenu; + +struct MenuDef +{ + SIM::CommandsDef *def; + CMenu *menu; + void *param; +}; + +typedef std::map CMDS_MAP; +typedef std::map MENU_MAP; + +class Commands : public QObject, public SIM::EventReceiver +{ + Q_OBJECT +public: + Commands(); + ~Commands(); + void set(SIM::CommandsDef*, const char *str); + void clear(); +protected slots: + void popupActivated(); +protected: + bool eventFilter(QObject *o, QEvent *e); + virtual bool processEvent(SIM::Event*); + SIM::CommandsDef *createBar(unsigned id); + void removeBar(unsigned id); + SIM::CommandsDef *createMenu(unsigned id); + void removeMenu(unsigned id); + CToolBar *show(unsigned id, QMainWindow *parent); + CMenu *get(SIM::CommandDef *cmd); + SIM::CommandsDef *getDef(unsigned id); + CMenu *processMenu(unsigned id, void *param, int key); + void customize(SIM::CommandsDef *def); + void customizeMenu(unsigned long id); + QObject* getParent(QObject *o); + unsigned cur_id; + CMDS_MAP bars; + MENU_MAP menus; +}; + +#endif + diff --git a/plugins/_core/connectionsettings.cpp b/plugins/_core/connectionsettings.cpp new file mode 100644 index 0000000..177f814 --- /dev/null +++ b/plugins/_core/connectionsettings.cpp @@ -0,0 +1,55 @@ +/*************************************************************************** + connectionsetting.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "icons.h" +#include "misc.h" +#include "connectionsettings.h" +#include "contacts/client.h" + +#include + +using namespace SIM; + +ConnectionSettings::ConnectionSettings(Client *client) : QDialog(NULL) + //: ConnectionSettingsBase(NULL, NULL, true) +{ + setupUi(this); + SET_WNDPROC("client") + setButtonsPict(this); + m_client = client; + Protocol *protocol = client->protocol(); + const CommandDef *cmd = protocol->description(); + setWindowIcon(Icon(cmd->icon)); + setWindowTitle(i18n("Configure %1 client") .arg(i18n(cmd->text))); + QVBoxLayout *lay = new QVBoxLayout(addWnd); + QWidget *setupWnd = client->setupWnd(); + setupWnd->setParent(addWnd); + setupWnd->move(QPoint()); + lay->addWidget(setupWnd); + setupWnd->show(); +} + +void ConnectionSettings::apply() +{ +} + +/* +#ifndef NO_MOC_INCLUDES +#include "connectionsettings.moc" +#endif +*/ + diff --git a/plugins/_core/connectionsettings.h b/plugins/_core/connectionsettings.h new file mode 100644 index 0000000..48091ac --- /dev/null +++ b/plugins/_core/connectionsettings.h @@ -0,0 +1,36 @@ +/*************************************************************************** + connectionsetting.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _CONNECTIONSETTINGS_H +#define _CONNECTIONSETTINGS_H + +#include "ui_connectionsettingsbase.h" +#include "event.h" + +class ConnectionSettings : public QDialog, public Ui::ConnectionSettingsBase +{ + Q_OBJECT +public: + ConnectionSettings(SIM::Client *client); +protected slots: + void apply(); +protected: + SIM::Client *m_client; +}; + +#endif + diff --git a/plugins/_core/connectionsettingsbase.ui b/plugins/_core/connectionsettingsbase.ui new file mode 100644 index 0000000..efccbc5 --- /dev/null +++ b/plugins/_core/connectionsettingsbase.ui @@ -0,0 +1,121 @@ + + + + + ConnectionSettingsBase + + + + 0 + 0 + 390 + 276 + + + + MyDialog + + + true + + + + 11 + + + 6 + + + + + + + + 0 + + + 6 + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Horizontal + + + + + + + &OK + + + true + + + true + + + + + + + &Cancel + + + true + + + + + + + + + + QWidget + QWidget +
QWidget
+ + -1 + -1 + + 0 + + 5 + 5 + + image0 + + text + +
+
+ + + 789c6dd2c10ac2300c00d07bbf2234b7229d1be245fc04c5a3201e4615f430059d0711ff5ddb2e6bb236ec90eed134cb5a19d8ef36602af5ecdbfeeac05dda0798d3abebde87e3faa374d3807fa0d633a52d38d8de6f679fe33fc776e196f53cd010188256a3600a292882096246517815ca99884606e18044a3a40d91824820924265a7923a2e8bcd05f33db1173e002913175f2a6be6d3294871a2d95fa00e8a94ee017b69d339d90df1e77c57ea072ede6758 + + + + + buttonOk + clicked() + MyDialog + accept() + + + buttonCancel + clicked() + MyDialog + reject() + + +
diff --git a/plugins/_core/connectwnd.cpp b/plugins/_core/connectwnd.cpp new file mode 100644 index 0000000..8903dd5 --- /dev/null +++ b/plugins/_core/connectwnd.cpp @@ -0,0 +1,95 @@ +/*************************************************************************** + connectwnd.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "misc.h" +#include "connectwnd.h" +#include "simgui/linklabel.h" + +#include +#include +#include + +ConnectWnd::ConnectWnd(bool bStart) : QWizardPage(NULL) +{ + setupUi(this); + using SIM::app_file; + m_bStart = bStart; + setConnecting(true); + QMovie movie(app_file("pict/connect.gif")); + if (!movie.isValid()) + movie.setFileName(app_file("pict/connect.mng")); + if (movie.isValid()){ + lblMovie->setMovie(&movie); + connect(this, SIGNAL(updated()), this, SLOT(updateMovie())); + movie.stop(); + movie.start(); + updateMovie(); + } + setConnecting(true); +} + +void ConnectWnd::updateMovie() +{ + lblMovie->repaint(); +} + +void ConnectWnd::setConnecting(bool bState) +{ + lnkPass->hide(); + if (bState){ + lblConnect->show(); + QMovie *pMovie = lblMovie->movie(); + if(pMovie){ + pMovie->start(); + } + lblMovie->show(); + lblComplete->hide(); + lblNext->hide(); + frmError->hide(); + }else{ + lblConnect->hide(); + QMovie *pMovie = lblMovie->movie(); + if(pMovie){ + pMovie->stop(); + } + lblMovie->hide(); + lblComplete->show(); + if (m_bStart){ + lblNext->show(); + }else{ + lblNext->hide(); + } + frmError->hide(); + } +} + +void ConnectWnd::setErr(const QString &text, const QString &url) +{ + lblConnect->hide(); + lblMovie->hide(); + lblComplete->hide(); + lblNext->hide(); + lblError->setText(text); + frmError->show(); + if (!url.isEmpty()){ + lnkPass->setUrl(url); + lnkPass->setText(i18n("Forgot password?")); + lnkPass->show(); + }else{ + lnkPass->hide(); + } +} diff --git a/plugins/_core/connectwnd.h b/plugins/_core/connectwnd.h new file mode 100644 index 0000000..a50a44d --- /dev/null +++ b/plugins/_core/connectwnd.h @@ -0,0 +1,38 @@ +/*************************************************************************** + connectwnd.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _CONNECTWND_H +#define _CONNECTWND_H + +#include +#include "ui_connectwndbase.h" + +class ConnectWnd : public QWizardPage, public Ui::ConnectWndBase +{ + Q_OBJECT +public: + ConnectWnd(bool bStart); + void setConnecting(bool bState); + void setErr(const QString &text, const QString &url); +protected slots: + void updateMovie(); +protected: + bool m_bStart; +}; + +#endif + diff --git a/plugins/_core/connectwndbase.ui b/plugins/_core/connectwndbase.ui new file mode 100644 index 0000000..7fe3f8c --- /dev/null +++ b/plugins/_core/connectwndbase.ui @@ -0,0 +1,195 @@ + + + ConnectWndBase + + + + 0 + 0 + 300 + 268 + + + + + + + Form3 + + + + 11 + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + Connecting + + + Qt::AlignCenter + + + false + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + 0 + 0 + + + + + 60 + 60 + + + + + + + false + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + + Complete + + + Qt::AlignCenter + + + false + + + + + + + If you want to add connection press button " Next". +You can add connection later using connection manager + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + true + + + + + + + + 11 + + + + + + 75 + true + + + + + + + Qt::AlignCenter + + + true + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + LinkLabel + QWidget +
simgui/linklabel.h
+
+
+ + +
diff --git a/plugins/_core/container.cpp b/plugins/_core/container.cpp new file mode 100644 index 0000000..363514b --- /dev/null +++ b/plugins/_core/container.cpp @@ -0,0 +1,1119 @@ +/*************************************************************************** + container.cpp - description + ------------------- + begin : Sun Mar 10 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "simapi.h" + +#include "log.h" + +#include "container.h" +#include "userwnd.h" +#include "core.h" +#include "buffer.h" +#include "icons.h" +#include "contacts/contact.h" +#include "contacts/client.h" +#include "simgui/toolbtn.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace SIM; + +const unsigned ACCEL_MESSAGE = 0x1000; + + +class Splitter : public QSplitter +{ +public: + Splitter(QWidget *p) : QSplitter(Qt::Vertical, p) {} +protected: + virtual QSizePolicy sizePolicy() const; +}; + +//FIXME: Obsolete? +//static void copyData(SIM::Data *dest, const SIM::Data *src, unsigned count) +//{ +// for(unsigned i = 0; i < count; i++) +// dest[i] = src[i]; +//} + +ContainerStatus::ContainerStatus(QWidget *parent) + : QStatusBar(parent) +{ + QSize s; + { + QProgressBar p(this); + addWidget(&p); + s = minimumSizeHint(); + } + setMinimumSize(QSize(0, s.height())); +} + +void ContainerStatus::resizeEvent(QResizeEvent *e) +{ + QStatusBar::resizeEvent(e); + emit sizeChanged(width()); +} + +QSizePolicy Splitter::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); +} + +static DataDef containerData[] = + { + { "Id" , DATA_ULONG, 1, 0 }, + { "Windows" , DATA_STRING, 1, 0 }, + { "ActiveWindow", DATA_ULONG, 1, 0 }, + { "Geometry" , DATA_LONG, 5, 0 }, + { "BarState" , DATA_LONG, 7, 0 }, + { "StatusSize" , DATA_ULONG, 1, 0 }, + { "WndConfig" , DATA_STRLIST, 1, 0 }, + { NULL , DATA_UNKNOWN, 0, 0 } + }; + +Container::Container(unsigned id, const char *cfg) + : QMainWindow() + , m_bNoRead (false) + , m_bInit (false) + , m_bInSize (false) + , m_bStatusSize (false) + , m_bBarChanged (false) + , m_bReceived (false) + , m_bNoSwitch (false) + , m_avatar_window(this) + , m_avatar_label(&m_avatar_window) + , m_tabBar (NULL) + , m_wnds (NULL) +{ + + + m_avatar_window.setWidget(&m_avatar_label); + //m_avatar_window.setOrientation(Qt::Vertical); + m_avatar_window.setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); + m_avatar_window.setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum ); + addDockWidget(Qt::LeftDockWidgetArea, &m_avatar_window); + setAttribute(Qt::WA_DeleteOnClose, true); + + setIconSize(QSize(16,16)); + + if(cfg && *cfg) + { + Buffer config; + config << "[Title]\n" << cfg; + config.setWritePos(0); + config.getSection(); + load_data(containerData, &data, &config); + } + else + load_data(containerData, &data, NULL); + + + if (cfg != NULL) + return; + + setId(id); + setContainerGeometry(); +} + +void Container::setContainerGeometry() +{ + + //copyData(data.barState, CorePlugin::instance()->data.ContainerBar, 7); + //copyData(data.geometry, CorePlugin::instance()->data.ContainerGeometry, 5); + if(data.geometry[WIDTH].toLong() == -1 || data.geometry[HEIGHT].toLong() == -1) + { + QWidget *desktop = QApplication::desktop(); + data.geometry[WIDTH].asLong() = desktop->width() / 3; + data.geometry[HEIGHT].asLong() = desktop->height() / 3; + } + if(data.geometry[TOP].toLong() != -1 || data.geometry[LEFT].toLong() != -1) + { + QWidgetList list = QApplication::topLevelWidgets(); + for(int i = 0; i < 2; i++) + { + QWidget *w; + bool bOK = true; + foreach(w,list) + { + if(w == this) + continue; + if(w->inherits("Container")) + { + int dw = w->pos().x() - data.geometry[LEFT].toLong(); + int dh = w->pos().y() - data.geometry[TOP].toLong(); + if (dw < 0) + dw = -dw; + if (dh < 0) + dh = -dh; + if (dw < 3 && dh < 3) + { + long nl = data.geometry[LEFT].toLong(); + long nt = data.geometry[TOP].toLong(); + nl += 21; + nt += 20; + QWidget *desktop = QApplication::desktop(); + if (nl + data.geometry[WIDTH].toLong() > desktop->width()) + nl = 0; + if (nt + data.geometry[WIDTH].toLong() > desktop->width()) + nt = 0; + if (nl != data.geometry[LEFT].toLong() && nt != data.geometry[TOP].toLong()) + { + data.geometry[LEFT].asLong() = nl; + data.geometry[TOP].asLong() = nt; + bOK = false; + } + } + } + } + if (bOK) + break; + } + } + setStatusSize(CorePlugin::instance()->value("ContainerStatusSize").toUInt()); + /* + m_bInSize = true; + ::restoreGeometry(this, data.geometry, bPos, true); + m_bInSize = false; + */ +} +Container::~Container() +{ + if( NULL != m_tabBar ) + { + list wnds = m_tabBar->windows(); + list::iterator it; + for (it = wnds.begin(); it != wnds.end(); ++it) + disconnect(*it, SIGNAL(closed(UserWnd*)), this, SLOT(removeUserWnd(UserWnd*))); + } + list::iterator it; + for (it = m_childs.begin(); it != m_childs.end(); ++it) + delete (*it); + free_data(containerData, &data); +} + +void Container::init() +{ + if (m_bInit) + return; + + frm = new QFrame(this); + setCentralWidget(frm); + + QObject::connect(CorePlugin::instance(), SIGNAL(modeChanged()), this, SLOT(modeChanged())); + + lay = new QVBoxLayout(frm); + m_wnds = new QStackedWidget(frm); + m_wnds->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); + lay->addWidget(m_wnds); + + m_tabSplitter = new Splitter(frm); + m_tabSplitter->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum)); + m_tabBar = new UserTabBar(m_tabSplitter); + m_tabBar->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding)); + m_tabBar->hide(); + + m_bInit = true; + + m_status = new ContainerStatus(m_tabSplitter); + lay->addWidget(m_tabSplitter); + connect(m_tabBar, SIGNAL(selected(int)), this, SLOT(contactSelected(int))); + //connect(this, SIGNAL(toolBarPositionChanged(QToolBar*)), this, SLOT(toolbarChanged(QToolBar*))); + connect(m_status, SIGNAL(sizeChanged(int)), this, SLOT(statusChanged(int))); + setupAccel(); + showBar(); + setStatusBar(m_status); + + for (list::iterator it = m_childs.begin(); it != m_childs.end(); ++it) + addUserWnd((*it), false); + + m_childs.clear(); + + QStringList windows = getWindows().split(','); + Q_FOREACH(const QString &win, windows) + { + unsigned long id = win.toULong(); + Contact *contact = getContacts()->contact(id); + if (contact == NULL) + continue; + Buffer config; + QString cfg = getWndConfig(id); + if (!cfg.isEmpty()) + { + config << "[Title]\n" << (const char*)cfg.toLocal8Bit(); + config.setWritePos(0); + config.getSection(); + } + addUserWnd(new UserWnd(id, &config, false, true), true); + } + + if (m_tabBar->count() == 0) + QTimer::singleShot(0, this, SLOT(close())); + setWindows(QString::null); + clearWndConfig(); + m_tabBar->raiseTab(getActiveWindow()); + show(); +} + +QShortcut* Container::makeShortcut(unsigned int key, unsigned int id) +{ + QShortcut* shortcut = new QShortcut(QKeySequence(key), this); + shortcut->setProperty("id", id); + connect(shortcut, SIGNAL(activated()), this, SLOT(accelActivated())); + return shortcut; +} + +void Container::setupAccel() +{ + m_shortcuts.clear(); + m_shortcuts.append(makeShortcut(Qt::Key_1 + Qt::ALT, 1)); + m_shortcuts.append(makeShortcut(Qt::Key_2 + Qt::ALT, 2)); + m_shortcuts.append(makeShortcut(Qt::Key_3 + Qt::ALT, 3)); + m_shortcuts.append(makeShortcut(Qt::Key_4 + Qt::ALT, 4)); + m_shortcuts.append(makeShortcut(Qt::Key_5 + Qt::ALT, 5)); + m_shortcuts.append(makeShortcut(Qt::Key_6 + Qt::ALT, 6)); + m_shortcuts.append(makeShortcut(Qt::Key_7 + Qt::ALT, 7)); + m_shortcuts.append(makeShortcut(Qt::Key_8 + Qt::ALT, 8)); + m_shortcuts.append(makeShortcut(Qt::Key_9 + Qt::ALT, 9)); + m_shortcuts.append(makeShortcut(Qt::Key_0 + Qt::ALT, 10)); + m_shortcuts.append(makeShortcut(Qt::Key_Left + Qt::ALT, 11)); + m_shortcuts.append(makeShortcut(Qt::Key_Right + Qt::ALT, 12)); + m_shortcuts.append(makeShortcut(Qt::Key_Home + Qt::ALT, 13)); + m_shortcuts.append(makeShortcut(Qt::Key_End + Qt::ALT, 14)); + + EventMenuGetDef eMenu(MenuMessage); + eMenu.process(); + CommandsDef *cmdsMsg = eMenu.defs(); + CommandsList it(*cmdsMsg, true); + CommandDef *c; + while ((c = ++it) != NULL) + { + if (c->accel.isEmpty()) + continue; + m_shortcuts.append(makeShortcut(QKeySequence::fromString(c->accel), ACCEL_MESSAGE + c->id)); + } +} + +void Container::setNoSwitch(bool bState) +{ + m_bNoSwitch = bState; +} + +list Container::windows() +{ + return m_tabBar->windows(); +} + +QByteArray Container::getState() +{ + clearWndConfig(); + QString windows; + if (m_tabBar == NULL) + return save_data(containerData, &data); + list userWnds = m_tabBar->windows(); + for(list::iterator it = userWnds.begin(); it != userWnds.end(); ++it) + { + if(!windows.isEmpty()) + windows += ','; + windows += QString::number((*it)->id()); + setWndConfig((*it)->id(), (*it)->getConfig()); + } + setWindows(windows); + UserWnd *userWnd = m_tabBar->currentWnd(); + if(userWnd) + setActiveWindow(userWnd->id()); + ::saveGeometry(this, data.geometry); + saveToolbar(m_bar, data.barState); + if(m_tabBar->isVisible()) + setStatusSize(m_status->width()); + return save_data(containerData, &data); +} + +QString Container::name() +{ + UserWnd *wnd = m_tabBar ? m_tabBar->currentWnd() : 0; + if (wnd) + return wnd->getName(); + return i18n("Container"); +} + +Q_DECLARE_METATYPE( UserWnd* ) + +void Container::addUserWnd(UserWnd *wnd, bool bRaise) +{ + if(m_wnds == NULL) + { + m_childs.push_back(wnd); + if(m_childs.size() == 1) + { + setWindowIcon(Icon(wnd->getIcon())); + setWindowTitle(wnd->getLongName()); + } + return; + } + connect(wnd, SIGNAL(closed(UserWnd*)), this, SLOT(removeUserWnd(UserWnd*))); + connect(wnd, SIGNAL(statusChanged(UserWnd*)), this, SLOT(statusChanged(UserWnd*))); + m_wnds->addWidget(wnd); +// m_tabSplitter->addWidget(m_wnds); + bool bHighlight = false; + for(list::iterator it = CorePlugin::instance()->unread.begin(); it != CorePlugin::instance()->unread.end(); ++it) + { + if(it->contact == wnd->id()) + { + bHighlight = true; + break; + } + } + + int tab = m_tabBar->addTab(Icon(wnd->getIcon()),wnd->getName()); + m_tabBar->setTabData(tab,QVariant::fromValue(wnd)); + if (bRaise) + m_tabBar->setCurrentIndex(tab); + else + m_tabBar->repaint(); + contactSelected(0); + if ((m_tabBar->count() > 1) && !m_tabBar->isVisible()) + { + m_tabBar->show(); + if (getStatusSize()){ + QList s; + s.append(1); + s.append(getStatusSize()); + m_bStatusSize = true; + m_tabSplitter->setSizes(s); + m_bStatusSize = false; + } + m_tabSplitter->setStretchFactor(m_tabSplitter->indexOf(m_status), 0); + } +} + +void Container::raiseUserWnd(int id/*UserWnd *wnd*/) +{ + if (m_tabBar == NULL) + return; + m_tabBar->raiseTab(id); + contactSelected(0); +} + +void Container::removeUserWnd(UserWnd *wnd) +{ + disconnect(wnd, SIGNAL(closed(UserWnd*)), this, SLOT(removeUserWnd(UserWnd*))); + disconnect(wnd, SIGNAL(statusChanged(UserWnd*)), this, SLOT(statusChanged(UserWnd*))); + m_wnds->removeWidget(wnd); + m_tabBar->removeTab(wnd->id()); + if (m_tabBar->count() == 0) + QTimer::singleShot(0, this, SLOT(close())); + if (m_tabBar->count() == 1) + m_tabBar->hide(); + contactSelected(0); +} + +UserWnd *Container::wnd(unsigned id) +{ + if (m_tabBar == NULL){ + for (list::iterator it = m_childs.begin(); it != m_childs.end(); ++it){ + if ((*it)->id() == id) + return (*it); + } + return NULL; + } + return m_tabBar->wnd(id); +} + +UserWnd *Container::wnd() +{ + if(m_tabBar == NULL) + { + if (m_childs.empty()) + return NULL; + return m_childs.front(); + } + return m_tabBar->currentWnd(); +} + +void Container::showBar() +{ + EventToolbar e(ToolBarContainer, this); + e.process(); + m_bar = e.toolBar(); + m_bBarChanged = true; + restoreToolbar(m_bar, data.barState); + m_bar->show(); + addToolBar(m_bar); + m_bBarChanged = false; + contactSelected(0); + //m_avatar_window.area()->moveDockWindow(&m_avatar_window, 0); +} + +void Container::contactSelected(int) +{ + UserWnd *userWnd = m_tabBar ? m_tabBar->currentWnd() : 0; + if (userWnd == NULL) + return; + m_wnds->setCurrentWidget(userWnd); + userWnd->setFocus(); + m_bar->setParam((void*)userWnd->id()); + Command cmd; + cmd->id = CmdContainerContact; + cmd->text_wrk = userWnd->getName(); + cmd->icon = userWnd->getIcon(); + cmd->param = (void*)(userWnd->id()); + cmd->popup_id = MenuContainerContact; + cmd->flags = BTN_PICT; + EventCommandChange e(cmd); + e.setNoProcess(); + m_bar->processEvent(&e); + setMessageType(userWnd->type()); + setWindowIcon(Icon(cmd->icon)); + setWindowTitle(userWnd->getLongName()); + m_bar->checkState(); + m_status->showMessage(userWnd->status()); + if (isActiveWindow()) + userWnd->markAsRead(); + + if(CorePlugin::instance()->value("ShowAvatarInContainer").toBool()) + { + Client *client = NULL; + unsigned j=0; + QImage img; + while (j < getContacts()->nClients()) + { + client = getContacts()->getClient(j++); + img = client->userPicture(userWnd->id()); + if (!img.isNull()) + break; + } + + if(!img.isNull()) + { + m_avatar_label.setPixmap(QPixmap::fromImage(img)); + if (!m_avatar_label.isVisible()) + m_avatar_window.show(); + } + else + { + m_avatar_label.clear(); + m_avatar_window.hide(); + } + } + else + { + m_avatar_label.clear(); + m_avatar_window.hide(); + } +} + +void Container::setMessageType(unsigned type) +{ + CommandDef *def; + def = CorePlugin::instance()->messageTypes.find(type); + if (def == NULL) + return; + Command cmd; + cmd->id = CmdMessageType; + cmd->text = def->text; + cmd->icon = def->icon; + cmd->bar_id = ToolBarContainer; + cmd->bar_grp = 0x2000; + cmd->menu_id = 0; + cmd->menu_grp = 0; + cmd->popup_id = MenuMessage; + cmd->flags = BTN_PICT; + EventCommandChange eCmd(cmd); + eCmd.setNoProcess(); + m_bar->processEvent(&eCmd); +} + +void Container::resizeEvent(QResizeEvent *e) +{ + QMainWindow::resizeEvent(e); + if (m_bInSize) + return; + ::saveGeometry(this, data.geometry); + //CorePlugin::instance()->data.ContainerGeometry[WIDTH] = data.geometry[WIDTH]; + //CorePlugin::instance()->data.ContainerGeometry[HEIGHT] = data.geometry[HEIGHT]; +} + +void Container::moveEvent(QMoveEvent *e) +{ + QMainWindow::moveEvent(e); + if (m_bInSize) + return; + ::saveGeometry(this, data.geometry); + //CorePlugin::instance()->data.ContainerGeometry[LEFT] = data.geometry[LEFT]; + //CorePlugin::instance()->data.ContainerGeometry[TOP] = data.geometry[TOP]; +} + +void Container::toolbarChanged(QToolBar*) +{ + if (m_bBarChanged) + return; + saveToolbar(m_bar, data.barState); + //copyData(CorePlugin::instance()->data.ContainerBar, data.barState, 7); +} + +void Container::statusChanged(int width) +{ + if (m_tabBar->isVisible() && !m_bStatusSize){ + setStatusSize(width); + CorePlugin::instance()->setValue("ContainerStatusSize", width); + } +} + +void Container::statusChanged(UserWnd *wnd) +{ + if (wnd == m_tabBar->currentWnd()) + m_status->showMessage(wnd->status()); +} + +void Container::accelActivated() +{ + QShortcut* sender = dynamic_cast(QObject::sender()); + unsigned int id = 0; + if(sender) + id = sender->property("id").toUInt(); + if ((unsigned)id >= ACCEL_MESSAGE){ + Command cmd; + cmd->id = id - ACCEL_MESSAGE; + cmd->menu_id = MenuMessage; + cmd->param = (void*)(m_tabBar->currentWnd()->id()); + EventCommandExec(cmd).process(); + return; + } + switch (id){ + case 11: + if (m_tabBar->current() == 0) + m_tabBar->setCurrent(m_tabBar->count() - 1); + else + m_tabBar->setCurrent(m_tabBar->current() - 1); + break; + case 12: + if (m_tabBar->current() == (unsigned)m_tabBar->count() - 1) + m_tabBar->setCurrent(0); + else + m_tabBar->setCurrent(m_tabBar->current() + 1); + break; + case 13: + m_tabBar->setCurrent(0); + break; + case 14: + m_tabBar->setCurrent(m_tabBar->count() - 1); + break; + default: + m_tabBar->setCurrent(id - 1); + } +} + +static const char *accels[] = + { + "Alt+1", + "Alt+2", + "Alt+3", + "Alt+4", + "Alt+5", + "Alt+6", + "Alt+7", + "Alt+8", + "Alt+9", + "Alt+0" + }; + +#if 0 +i18n("male", "%1 is typing") +i18n("female", "%1 is typing") +#endif + +void Container::flash() +{ + QApplication::alert( this ); +} + +bool Container::processEvent(Event *e) +{ + if (m_tabBar == NULL) + return false; + switch (e->type()){ + case eEventMessageReceived: + { + EventMessage *em = static_cast(e); + Message *msg = em->msg(); + if (msg->type() == MessageStatus){ + Contact *contact = getContacts()->contact(msg->contact()); + if (contact) + contactChanged(contact); + return false; + } + if (msg->getFlags() & MESSAGE_NOVIEW) + return false; + if (CorePlugin::instance()->getContainerMode()) + { + if (isActiveWindow() && !isMinimized()) + { + UserWnd *userWnd = m_tabBar->currentWnd(); + if (userWnd && (userWnd->id() == msg->contact())) + userWnd->markAsRead(); + } + else + { + UserWnd *userWnd = wnd(msg->contact()); + if (userWnd) + QTimer::singleShot(0, this, SLOT(flash())); + } + } + // no break here - otherwise we have to duplicate the code below... + } + case eEventMessageRead: + { + EventMessage *em = static_cast(e); + Message *msg = em->msg(); + UserWnd *userWnd = wnd(msg->contact()); + if (userWnd){ + bool bHighlight = false; + for (list::iterator it = CorePlugin::instance()->unread.begin(); it != CorePlugin::instance()->unread.end(); ++it){ + if (it->contact != msg->contact()) + continue; + bHighlight = true; + break; + } + m_tabBar->setHighlighted(msg->contact(), bHighlight); + } + break; + } + case eEventActiveContact: + { + EventActiveContact *eac = static_cast(e); + if (!isActiveWindow()) + return false; + UserWnd *userWnd = m_tabBar->currentWnd(); + if (userWnd) { + eac->setContactID(userWnd->id()); + return true; + } + break; + } + case eEventContact: + { + EventContact *ec = static_cast(e); + Contact *contact = ec->contact(); + UserWnd *userWnd = wnd(contact->id()); + if(!userWnd) + break; + switch(ec->action()) + { + case EventContact::eDeleted: + { + removeUserWnd(userWnd); + break; + } + case EventContact::eChanged: + { + if (contact->getIgnore()){ + removeUserWnd(userWnd); + break; + } + m_tabBar->changeTab(contact->id()); + contactChanged(contact); + break; + } + case EventContact::eStatus: + { + unsigned style = 0; + QSet wrkIcons; + QString statusIcon; + contact->contactInfo(style, statusIcon, &wrkIcons); + bool bTyping = wrkIcons.contains("typing"); + if (userWnd->m_bTyping != bTyping) + { + userWnd->m_bTyping = bTyping; + if (bTyping){ + userWnd->setStatus(g_i18n("%1 is typing", contact) .arg(contact->getName())); + }else{ + userWnd->setStatus(""); + } + userWnd = m_tabBar->currentWnd(); + if (userWnd && (contact->id() == userWnd->id())) + m_status->showMessage(userWnd->status()); + } + } + default: + break; + } + break; + } + case eEventClientsChanged: + setupAccel(); + break; + case eEventContactClient: + { + EventContactClient *ecc = static_cast(e); + contactChanged(ecc->contact()); + break; + } + case eEventInit: + init(); + break; + case eEventCommandExec: + { + EventCommandExec *ece = static_cast(e); + CommandDef *cmd = ece->cmd(); + UserWnd *userWnd = m_tabBar->currentWnd(); + if (userWnd && ((unsigned long)(cmd->param) == userWnd->id())){ + if (cmd->menu_id == MenuContainerContact){ + m_tabBar->raiseTab(cmd->id); + return true; + } + if (cmd->id == CmdClose){ + delete userWnd; + return true; + } + if (cmd->id == CmdInfo && cmd->menu_id != MenuContact){ + CommandDef c = *cmd; + c.menu_id = MenuContact; + c.param = (void*)userWnd->id(); + EventCommandExec(&c).process(); + return true; + } + } + break; + } + case eEventCheckCommandState: + { + EventCheckCommandState *ecs = static_cast(e); + CommandDef *cmd = ecs->cmd(); + UserWnd *userWnd = m_tabBar->currentWnd(); + if (userWnd && ((unsigned long)(cmd->param) == userWnd->id()) && + (cmd->menu_id == MenuContainerContact) && + (cmd->id == CmdContainerContacts)){ + list userWnds = m_tabBar->windows(); + CommandDef *cmds = new CommandDef[userWnds.size() + 1]; + unsigned n = 0; + for (list::iterator it = userWnds.begin(); it != userWnds.end(); ++it){ + cmds[n].id = (*it)->id(); + cmds[n].flags = COMMAND_DEFAULT; + cmds[n].text_wrk = (*it)->getName(); + cmds[n].icon = (*it)->getIcon(); + cmds[n].text = "_"; + cmds[n].menu_id = n + 1; + if (n < sizeof(accels) / sizeof(const char*)) + cmds[n].accel = accels[n]; + if (*it == m_tabBar->currentWnd()) + cmds[n].flags |= COMMAND_CHECKED; + n++; + } + cmd->param = cmds; + cmd->flags |= COMMAND_RECURSIVE; + return true; + } + break; + } + default: + break; + } + return false; +} + +void Container::modeChanged() +{ + if (isReceived() && CorePlugin::instance()->getContainerMode()) + QTimer::singleShot(0, this, SLOT(close())); + if (CorePlugin::instance()->getContainerMode() == 0){ + list wnds = m_tabBar->windows(); + for (list::iterator it = wnds.begin(); it != wnds.end(); ++it){ + if ((*it) != m_tabBar->currentWnd()) + delete (*it); + } + } +} + +void Container::wndClosed() +{ + list wnds = m_tabBar->windows(); + for (list::iterator it = wnds.begin(); it != wnds.end(); ++it){ + if ((*it)->isClosed()) + delete (*it); + } +} + +bool Container::event(QEvent *e) +{ +#ifdef WIN32 + if (e->type() == QEvent::WindowActivate) + init(); +#endif + if ((e->type() == QEvent::WindowActivate)/* || + (((e->type() == QEvent::ShowNormal) || + (e->type() == QEvent::ShowMaximized)) && isActiveWindow())*/){ + UserWnd *userWnd = m_tabBar->currentWnd(); + if (m_bNoRead) + m_bNoRead = false; + if (userWnd) + userWnd->markAsRead(); + + if (m_bNoSwitch) + m_bNoSwitch = false; + else if ((userWnd == NULL) || !m_tabBar->isHighlighted(m_tabBar->current())) + { + list wnds = m_tabBar->windows(); + for (int i=0; icount();++i) //list::iterator it = wnds.begin(); it != wnds.end(); ++it){ + { + if (m_tabBar->isHighlighted(i)) + { + raiseUserWnd(i); + break; + } + } + } + } + return QMainWindow::event(e); +} + +void Container::contactChanged(Contact *contact) +{ + UserWnd *userWnd = NULL; + if (m_tabBar){ + userWnd = m_tabBar->currentWnd(); + }else if (!m_childs.empty()){ + userWnd = m_childs.front(); + } + if (userWnd && contact && (contact->id() == userWnd->id())){ + Command cmd; + cmd->id = CmdContainerContact; + cmd->text_wrk = userWnd->getName(); + cmd->icon = userWnd->getIcon(); + cmd->param = (void*)(contact->id()); + cmd->popup_id = MenuContainerContact; + cmd->flags = BTN_PICT; + EventCommandChange e(cmd); + m_bar->processEvent(&e); + e.setNoProcess(); + setWindowIcon(Icon(cmd->icon)); + setWindowTitle(userWnd->getLongName()); + } +} + +void Container::setReadMode() +{ + log(L_DEBUG, "Set read mode"); + m_bNoRead = false; +} + +UserTabBar::UserTabBar(QWidget *parent) : QTabBar(parent) +{ + setShape(QTabBar::TriangularSouth); +} + +UserWnd *UserTabBar::wnd(unsigned id) +{ + UserWnd *res = NULL; + for (int t = 0; t < count(); t++) + { + UserWnd *wnd = wndForTab(t); + if (wnd && wnd->id() == id) + { + res = wnd; + break; + } + } + return res; +} + +int UserTabBar::tab(unsigned contactid) +{ + UserWnd *res = NULL; + for (int t = 0; t < count(); t++) + { + UserWnd *wnd = wndForTab(t); + if (wnd && wnd->id() == contactid) + { + res = wnd; + return t; + } + } + return -1; +} + +void UserTabBar::raiseTab(unsigned id) +{ + for (int t = 0; t < count(); t++) + { + UserWnd *wnd = wndForTab(t); + if (wnd && wnd->id() == id) + { + setCurrent(t); + break; + } + } +} + +list UserTabBar::windows() +{ + list res; + for (int i = 0; i < count(); i++) + { + res.push_back(wndForTab(i)); + } + return res; +} + +void UserTabBar::setCurrent(unsigned n) +{ + setCurrentIndex(n); +} + +unsigned UserTabBar::current() +{ + return currentIndex(); +} + +void UserTabBar::slotRepaint() +{ + repaint(); +} + +void UserTabBar::removeTab(unsigned id) +{ + layoutTabs(); + for (int t = 0; t < count(); t++) + { + UserWnd *wnd = wndForTab(t); + if (wnd && wnd->id() == id) + { + QTabBar::removeTab(t); + QTimer::singleShot(0, this, SLOT(slotRepaint())); + break; + } + } +} + +void UserTabBar::changeTab(unsigned id) +{ + layoutTabs(); + for (int t = 0; t < count(); t++) + { + UserWnd *wnd = wndForTab(t); + if (wnd && wnd->id() == id) + { + setTabText(t,wnd->getName()); + QTimer::singleShot(0, this, SLOT(slotRepaint())); + break; + } + } +} + +void UserTabBar::setHighlighted(unsigned contactid, bool bHighlight) //bHighlight +{ + int index = tab(contactid); + if (index == -1) return; //corresponding contact not found + + QColor c; + if (bHighlight) + c = QColor ( 255, 0, 0 ); //red + else + c = QColor ( 0, 0, 0 ); //black + + this->setTabTextColor(index,c); + +// for(std::list::iterator it = m_tabs.begin(); it != m_tabs.end(); ++it) +// { +// UserTab *tab = *it; +// if (tab->wnd()->id() == id) +// { +// repaint(); +// break; +// } +// } +} + +bool UserTabBar::isHighlighted(int id /*UserWnd *wnd*/) +{ +// for(std::list::iterator it = m_tabs.begin(); it != m_tabs.end(); ++it) +// { +// UserTab* tab = *it; +// if (tab->wnd() == wnd) +// return tab->isHighlighted(); +// } + return this->tabTextColor(id)==QColor(255,0,0); +} + +void UserTabBar::resizeEvent(QResizeEvent *e) +{ + QTabBar::resizeEvent(e); + QTimer::singleShot(0, this, SLOT(slotRepaint())); +} + +void UserTabBar::mousePressEvent(QMouseEvent *e) +{ + if (e->button() == Qt::RightButton) + { + int id = tabAt(e->pos()); + if(id == -1) + return; + setCurrentIndex(id); + UserWnd* wnd = wndForTab(id); + if(NULL == wnd) + return; + + EventMenuProcess eMenu(MenuContact, (void*)wnd->id()); + eMenu.process(); + QMenu *menu = eMenu.menu(); + if(menu) + menu->popup(e->globalPos()); + return; + } + QTabBar::mousePressEvent(e); +} + +UserWnd *UserTabBar::currentWnd() +{ + return wndForTab(currentIndex()); +} + +void UserTabBar::layoutTabs() +{ + //QTabBar::layoutTabs(); +} + +UserWnd* UserTabBar::wndForTab(int tab) { + QVariant v = tabData(tab); + if(!v.isValid()) + return NULL; + if(!v.canConvert()) + return NULL; + + return v.value(); +} + diff --git a/plugins/_core/container.h b/plugins/_core/container.h new file mode 100644 index 0000000..6d34659 --- /dev/null +++ b/plugins/_core/container.h @@ -0,0 +1,169 @@ +/*************************************************************************** + container.h - description + ------------------- + begin : Sun Mar 10 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _CONTAINER_H +#define _CONTAINER_H + +#include "cfg.h" +#include "event.h" +#include "message.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +const unsigned NEW_CONTAINER = (unsigned)(-1); +const unsigned GRP_CONTAINER = 0x80000000; + +class UserWnd; +class UserTabBar; +class QSplitter; +class CToolBar; +class QWidgetStack; +class CorePlugin; +class Container; + +struct ContainerData +{ + SIM::Data Id; + SIM::Data Windows; + SIM::Data ActiveWindow; + SIM::Data geometry[5]; + SIM::Data barState[7]; + SIM::Data StatusSize; + SIM::Data WndConfig; +}; + +class ContainerStatus : public QStatusBar +{ + Q_OBJECT +public: + ContainerStatus(QWidget *parent); +signals: + void sizeChanged(int); +protected: + void resizeEvent(QResizeEvent*); +}; + +class UserTabBar : public QTabBar +{ + Q_OBJECT +public: + UserTabBar(QWidget *parent); + void raiseTab(unsigned id); + UserWnd *wnd(unsigned id); + int tab(unsigned contactid); + UserWnd *currentWnd(); + std::list windows(); + void removeTab(unsigned id); + void changeTab(unsigned id); + void setHighlighted(unsigned id, bool bState); + void setCurrent(unsigned i); + unsigned current(); + bool isHighlighted(int /*UserWnd *wnd*/); +public slots: + void slotRepaint(); +protected: + virtual void layoutTabs(); + virtual void mousePressEvent(QMouseEvent *e); + virtual void resizeEvent(QResizeEvent *e); + UserWnd* wndForTab(int tab); +}; + +class Container : public QMainWindow, public SIM::EventReceiver +{ + Q_OBJECT +public: + static const int WndType = QVariant::UserType + 1; + + Container(unsigned id, const char *cfg = NULL); + ~Container(); + QString name(); + UserWnd *wnd(unsigned id); + UserWnd *wnd(); + std::list windows(); + QByteArray getState(); + bool isReceived() { return m_bReceived; } + void setReceived(bool bReceived) { m_bReceived = bReceived; } + void setNoSwitch(bool bState); + void setMessageType(unsigned id); + void contactChanged(SIM::Contact *contact); + PROP_ULONG(Id); + PROP_STR(Windows); + PROP_ULONG(ActiveWindow); + PROP_ULONG(StatusSize); + PROP_STRLIST(WndConfig); + bool m_bNoRead; + void init(); + void setContainerGeometry(); +public slots: + void addUserWnd(UserWnd*, bool bRaise); + void removeUserWnd(UserWnd*); + void raiseUserWnd(int /*UserWnd**/); + void contactSelected(int); + void toolbarChanged(QToolBar*); + void statusChanged(int); + void accelActivated(); + void statusChanged(UserWnd*); + void modeChanged(); + void wndClosed(); + void flash(); + void setReadMode(); +protected: + virtual void resizeEvent(QResizeEvent*); + virtual void moveEvent(QMoveEvent*); + virtual bool event(QEvent*); + virtual bool processEvent(SIM::Event*); + void showBar(); + void setupAccel(); + QShortcut* makeShortcut(unsigned int key, unsigned int id); + ContainerData data; + bool m_bInit; + bool m_bInSize; + bool m_bStatusSize; + bool m_bBarChanged; + bool m_bReceived; + bool m_bNoSwitch; + CToolBar *m_bar; + QDockWidget m_avatar_window; + QLabel m_avatar_label; + QSplitter *m_tabSplitter; + UserTabBar *m_tabBar; + ContainerStatus *m_status; + QStackedWidget *m_wnds; + QList m_shortcuts; + std::list m_childs; + QFrame *frm; + QVBoxLayout *lay; +}; + +#endif + diff --git a/plugins/_core/core.cpp b/plugins/_core/core.cpp new file mode 100644 index 0000000..6963ad3 --- /dev/null +++ b/plugins/_core/core.cpp @@ -0,0 +1,4123 @@ +/*************************************************************************** + core.cpp - description + ------------------- +begin : Sun Mar 17 2002 +copyright : (C) 2002 by Vladimir Shutoff +email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "simapi.h" + +#ifdef WIN32 +#include +#include +#else +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// simlib + +#include "buffer.h" +#include "icons.h" +#include "log.h" +#include "kdeisversion.h" +#include "unquot.h" +#include "xsl.h" + +#include "simgui/textshow.h" +#include "simgui/toolbtn.h" +#include "simgui/ballonmsg.h" +#include "contacts/clientdataiterator.h" +#include "contacts/contact.h" +#include "contacts/group.h" +#include "contacts/client.h" +#include "contacts/protocolmanager.h" +// _core +#include "core.h" +#include "cfgdlg.h" +#include "mainwin.h" +#include "userview.h" +#include "commands.h" +#include "usercfg.h" +#include "interfacecfg.h" +#include "search.h" +#include "logindlg.h" +#include "newprotocol.h" +#include "status.h" +#include "statuswnd.h" +#include "manager.h" +#include "connectionsettings.h" +#include "container.h" +#include "userwnd.h" +#include "msgedit.h" +#include "simgui/fontedit.h" +#include "clientlist.h" +#include "history.h" +#include "historywnd.h" +#include "msgcfg.h" +#include "smscfg.h" +#include "tmpl.h" +#include "autoreply.h" +#include "filetransfer.h" +#include "declinedlg.h" +#include "userhistorycfg.h" +#include "profilemanager.h" + +using namespace std; +using namespace SIM; + +#ifdef WIN32 + +class LockThread : public QThread +{ + public: + LockThread(Qt::HANDLE hEvent); + Qt::HANDLE hEvent; + protected: + void run(); +}; + +#endif + +class FileLock : public QFile +{ + public: + FileLock(const QString &name); + ~FileLock(); + bool lock(bool bSend); + protected: +#ifdef WIN32 + LockThread *m_thread; +#else + bool m_bLock; +#endif +}; + +Plugin *createCorePlugin(unsigned base, bool, Buffer *config) +{ + Plugin *plugin = new CorePlugin(base, config); + return plugin; +} + +static PluginInfo info = +{ + I18N_NOOP("Interface"), + I18N_NOOP("System interface"), + VERSION, + createCorePlugin, + PLUGIN_DEFAULT | PLUGIN_NODISABLE | PLUGIN_RELOAD +}; + +EXPORT_PROC PluginInfo* GetPluginInfo() +{ + return &info; +} + +#if !defined(WIN32) && !defined(USE_KDE) + +struct loaded_domain; + +struct loaded_l10nfile +{ + const char *filename; + int decided; + const void *data; + loaded_l10nfile() : filename(0), decided(0), data(0) {} +}; + + +void k_nl_load_domain (loaded_l10nfile *domain_file); +void k_nl_unload_domain (loaded_domain *domain); +char *k_nl_find_msg (loaded_l10nfile *domain_file, const char *msgid); + +#endif + +static CorePlugin* g_plugin = 0; + +static QWidget *getInterfaceSetup(QWidget *parent, SIM::PropertyHubPtr data) +{ + return new MessageConfig(parent, data); +} + +static QWidget *getSMSSetup(QWidget *parent, SIM::PropertyHubPtr data) +{ + return new SMSConfig(parent, data); +} + +static QWidget *getHistorySetup(QWidget *parent, SIM::PropertyHubPtr data) +{ + return new UserHistoryCfg(parent, data); +} + +struct autoReply +{ + unsigned status; + const char *text; +}; + +static autoReply autoReplies[] = +{ + { STATUS_AWAY, I18N_NOOP( + "I am currently away from the computer,\n" + "please leave your message and I will get back to you as soon as I return!" + ) }, + { STATUS_NA, I18N_NOOP( + "I am out'a here.\n" + "See you tomorrow!" + ) }, + { STATUS_DND, I18N_NOOP( + "Please do not disturb me now. Disturb me later." + ) }, + { STATUS_OCCUPIED, I18N_NOOP( + "I'm occupied at the moment. Please only urgent messages." + ) }, + { STATUS_FFC, I18N_NOOP( + "We'd love to hear what you have to say. Join our chat." + ) }, + { STATUS_ONLINE, I18N_NOOP( + "I'm here." + ) }, + { STATUS_OFFLINE, I18N_NOOP( + "I'm offline." + ) }, + { 0, NULL } +}; + +CorePlugin::CorePlugin(unsigned base, Buffer* /*config*/) + : QObject() + //, PropertyHub ("_core") + , Plugin (base) + , EventReceiver (HighPriority) + , historyXSL (NULL) + , m_bInit (false) + , m_cfg (NULL) + , m_focus (NULL) + , m_view (NULL) + , m_search (NULL) + , m_translator (NULL) + , m_manager (NULL) + , m_status (NULL) + , m_statusWnd (NULL) + , m_nClients (0) + , m_nClientsMenu (0) + , m_nResourceMenu (0) + , m_main (NULL) + , m_alert (NULL) + , m_lock (NULL) + , m_RegNew (false) + , m_tmpl (new Tmpl(this)) + , m_cmds (new Commands()) + , m_HistoryThread (NULL) + , m_bIgnoreEvents (false) + , m_propertyHub (SIM::PropertyHub::create("_core")) +{ + g_plugin= this; + setValue("StatusTime", QDateTime::currentDateTime().toTime_t()); + + //loadDir(); + boundTypes(); + + EventMenu(MenuFileDecline, EventMenu::eAdd).process(); + EventMenu(MenuMailList, EventMenu::eAdd).process(); + EventMenu(MenuPhoneList, EventMenu::eAdd).process(); + EventMenu(MenuStatusWnd, EventMenu::eAdd).process(); + EventMenu(MenuEncoding, EventMenu::eAdd).process(); + EventMenu(MenuSearchItem, EventMenu::eAdd).process(); + EventMenu(MenuSearchGroups, EventMenu::eAdd).process(); + EventMenu(MenuSearchOptions, EventMenu::eAdd).process(); + + createMainToolbar(); + createHistoryToolbar(); + createContainerToolbar(); + createMsgEditToolbar(); + createTextEditToolbar(); + createMenuMsgView(); + createMenuTextEdit(); + + MsgEdit::setupMessages(); // Make sure this function is called after createContainerToolbar and createMsgEditToolbar + // because setupMessages() adds items to MenuMessage and to ToolBatMsgEdit, witch are + // created by createContainerToolbar and createMsgEditToolbar + // If menu or toolbar were not created, items can't be added, and will be just missing + Command cmd; + + EventMenu(MenuGroup, EventMenu::eAdd).process(); + EventMenu(MenuContact, EventMenu::eAdd).process(); + EventMenu(MenuContactGroup, EventMenu::eAdd).process(); + EventMenu(MenuMsgCommand, EventMenu::eAdd).process(); + + createEventCmds(); +} + +void CorePlugin::createCommand(int id, const QString& text, const QString& icon, int menu_id, + int menu_grp, int bar_id, int bar_grp, int flags, const QString& accel) +{ + Command cmd; + cmd->id = id; + cmd->text = text; + cmd->icon = icon; + cmd->menu_id = menu_id; + cmd->menu_grp = menu_grp; + cmd->bar_id = bar_id; + cmd->bar_grp = bar_grp; + cmd->flags = flags; + cmd->accel = accel; + EventCommandCreate(cmd).process(); +} + +void CorePlugin::createEventCmds() +{ + Command cmd; + createCommand(CmdMsgQuote, I18N_NOOP("&Quote"), QString::null, MenuMsgCommand, 0x1002, + 0, 0, COMMAND_CHECK_STATE, QString::null); + + createCommand(CmdMsgQuote + CmdReceived, I18N_NOOP("&Quote"), QString::null, MenuMsgCommand, 0x1002, + ToolBarMsgEdit, 0x1041, COMMAND_CHECK_STATE | BTN_PICT, QString::null); + + createCommand(CmdMsgForward, I18N_NOOP("&Forward"), QString::null, MenuMsgCommand, 0x1003, + 0, 0, COMMAND_CHECK_STATE, QString::null); + + createCommand(CmdMsgForward + CmdReceived, I18N_NOOP("&Forward"), QString::null, MenuMsgCommand, 0x1003, + ToolBarMsgEdit, 0x1042, COMMAND_CHECK_STATE | BTN_PICT, QString::null); + + createCommand(CmdMsgAnswer, I18N_NOOP("&Answer"), "mail_generic", MenuMsgCommand, 0x1003, + ToolBarMsgEdit, 0x8000, COMMAND_CHECK_STATE | BTN_PICT, QString::null); + + + EventMenu(MenuContainer, EventMenu::eAdd).process(); + + createCommand(0, I18N_NOOP("&Messages"), "message", MenuMsgCommand, 0x1003, 0, 0x8000, COMMAND_CHECK_STATE | BTN_PICT, "_core"); + + cmd->id = 0; + cmd->text = I18N_NOOP("SMS"); + cmd->icon = "cell"; + cmd->icon_on = QString::null; + cmd->param = (void*)getSMSSetup; + cmd->accel = "SMS"; + EventAddPreferences(cmd).process(); + + cmd->id = 0; + cmd->text = I18N_NOOP("&History setup"); + cmd->icon = "history"; + cmd->icon_on = QString::null; + cmd->param = (void*)getHistorySetup; + cmd->accel = "history"; + EventAddPreferences(cmd).process(); + + cmd->id = CmdGrpCreate; + cmd->text = I18N_NOOP("&Create group"); + cmd->icon = "grp_create"; + cmd->icon_on = QString::null; + cmd->menu_id = MenuGroup; + cmd->menu_grp = 0x4000; + EventCommandCreate(cmd).process(); + + cmd->id = CmdGrpRename; + cmd->text = I18N_NOOP("&Rename group"); + cmd->icon = "grp_rename"; + cmd->accel = "F2"; + cmd->menu_grp = 0x4001; + EventCommandCreate(cmd).process(); + + cmd->id = CmdGrpDelete; + cmd->text = I18N_NOOP("&Delete group"); + cmd->icon = "remove"; + cmd->accel = "Del"; + cmd->menu_grp = 0x4002; + EventCommandCreate(cmd).process(); + + cmd->id = CmdGrpUp; + cmd->text = I18N_NOOP("Up"); + cmd->icon = "1uparrow"; + cmd->accel = "Ctrl+Up"; + cmd->menu_grp = 0x6000; + EventCommandCreate(cmd).process(); + + cmd->id = CmdGrpDown; + cmd->text = I18N_NOOP("Down"); + cmd->icon = "1downarrow"; + cmd->accel = "Ctrl+Down"; + cmd->menu_grp = 0x6001; + EventCommandCreate(cmd).process(); + + cmd->id = CmdGrpTitle; + cmd->text = "_"; + cmd->icon = "grp_on"; + cmd->accel = QString::null; + cmd->menu_grp = 0x1000; + cmd->flags = COMMAND_CHECK_STATE | COMMAND_TITLE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdConfigure; + cmd->text = I18N_NOOP("Setup"); + cmd->icon = "configure"; + cmd->menu_grp = 0xB000; + cmd->flags = COMMAND_DEFAULT; + EventCommandCreate(cmd).process(); + + cmd->id = CmdContactTitle; + cmd->text = "_"; + cmd->icon = QString::null; + cmd->accel = QString::null; + cmd->menu_id = MenuContact; + cmd->menu_grp = 0x1000; + cmd->popup_id = 0; + cmd->flags = COMMAND_CHECK_STATE | COMMAND_TITLE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdUnread; + cmd->menu_grp = 0x1000; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdSendMessage; + cmd->menu_grp = 0x2000; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdClose; + cmd->text = "&Close"; + cmd->icon = "exit"; + cmd->menu_id = MenuContact; + cmd->menu_grp = 0xF000; + EventCommandCreate(cmd).process(); + + cmd->id = CmdContactGroup; + cmd->text = I18N_NOOP("Group"); + cmd->icon = "grp_on"; + cmd->menu_grp = 0x8000; + cmd->popup_id = MenuContactGroup; + cmd->flags = COMMAND_DEFAULT; + EventCommandCreate(cmd).process(); + + cmd->id = CmdContactRename; + cmd->text = I18N_NOOP("&Rename"); + cmd->icon = QString::null; + cmd->menu_grp = 0x8001; + cmd->popup_id = 0; + cmd->accel = "F2"; + cmd->flags = COMMAND_DEFAULT; + EventCommandCreate(cmd).process(); + + cmd->id = CmdContactDelete; + cmd->text = I18N_NOOP("&Delete"); + cmd->icon = "remove"; + cmd->menu_grp = 0x8002; + cmd->accel = "Del"; + cmd->flags = COMMAND_DEFAULT; + EventCommandCreate(cmd).process(); + + cmd->id = CmdShowAlways; + cmd->text = I18N_NOOP("Show &always"); + cmd->icon = QString::null; + cmd->menu_grp = 0x8003; + cmd->accel = QString::null; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdFetchAway; + cmd->text = I18N_NOOP("&Fetch away message"); + cmd->icon = "message"; + cmd->menu_grp = 0x8020; + cmd->flags = COMMAND_CHECK_STATE | BTN_HIDE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdInfo; + cmd->text = I18N_NOOP("User &info"); + cmd->icon = "info"; + cmd->menu_grp = 0x7010; + cmd->accel = QString::null; + cmd->flags = COMMAND_DEFAULT; + EventCommandCreate(cmd).process(); + + cmd->id = CmdHistory; + cmd->text = I18N_NOOP("&History"); + cmd->icon = "history"; + cmd->menu_grp = 0x7020; + cmd->flags = COMMAND_DEFAULT; + EventCommandCreate(cmd).process(); + + cmd->id = CmdConfigure; + cmd->text = I18N_NOOP("Setup"); + cmd->icon = "configure"; + cmd->menu_grp = 0x7020; + cmd->flags = COMMAND_DEFAULT; + EventCommandCreate(cmd).process(); + + cmd->id = CmdContainer; + cmd->text = I18N_NOOP("To container"); + cmd->icon = QString::null; + cmd->popup_id = MenuContainer; + cmd->menu_grp = 0x8010; + cmd->accel = QString::null; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdContainer; + cmd->text = "_"; + cmd->popup_id = 0; + cmd->menu_id = MenuContainer; + cmd->menu_grp = 0x1000; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdContactGroup; + cmd->text = "_"; + cmd->icon = QString::null; + cmd->accel = QString::null; + cmd->menu_id = MenuContactGroup; + cmd->menu_grp = 0x2000; + EventCommandCreate(cmd).process(); + + cmd->id = CmdDeclineWithoutReason; + cmd->text = I18N_NOOP("Decline file without reason"); + cmd->icon = QString::null; + cmd->menu_id = MenuFileDecline; + cmd->menu_grp = 0x1000; + cmd->flags = COMMAND_DEFAULT; + EventCommandCreate(cmd).process(); + + cmd->id = CmdDeclineReasonBusy; + cmd->text = I18N_NOOP("Sorry, I'm busy right now, and can not respond to your request"); + cmd->menu_grp = 0x1001; + EventCommandCreate(cmd).process(); + + cmd->id = CmdDeclineReasonLater; + cmd->text = I18N_NOOP("Sorry, I'm busy right now, but I'll be able to respond to you later"); + cmd->menu_grp = 0x1002; + EventCommandCreate(cmd).process(); + + cmd->id = CmdDeclineReasonInput; + cmd->text = I18N_NOOP("Enter a decline reason"); + cmd->menu_grp = 0x1004; + EventCommandCreate(cmd).process(); + + cmd->id = CmdEditList; + cmd->text = I18N_NOOP("&Edit"); + cmd->icon = "mail_generic"; + cmd->menu_id = MenuMailList; + cmd->menu_grp = 0x1000; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdRemoveList; + cmd->text = I18N_NOOP("&Delete"); + cmd->icon = "remove"; + cmd->menu_grp = 0x1001; + EventCommandCreate(cmd).process(); + + cmd->id = CmdEditList; + cmd->text = I18N_NOOP("&Edit"); + cmd->icon = "phone"; + cmd->menu_id = MenuPhoneList; + cmd->menu_grp = 0x1000; + EventCommandCreate(cmd).process(); + + cmd->id = CmdRemoveList; + cmd->text = I18N_NOOP("&Delete"); + cmd->icon = "remove"; + cmd->menu_grp = 0x1001; + EventCommandCreate(cmd).process(); + + cmd->id = CmdStatusWnd; + cmd->text = "_"; + cmd->icon = QString::null; + cmd->menu_id = MenuStatusWnd; + EventCommandCreate(cmd).process(); + + cmd->id = CmdChangeEncoding; + cmd->text = "_"; + cmd->menu_id = MenuEncoding; + cmd->menu_grp = 0x1000; + EventCommandCreate(cmd).process(); + + cmd->id = CmdAllEncodings; + cmd->text = I18N_NOOP("&Show all encodings"); + cmd->menu_id = MenuEncoding; + cmd->menu_grp = 0x8000; + EventCommandCreate(cmd).process(); + + cmd->id = CmdContactGroup; + cmd->text = I18N_NOOP("Add to &group"); + cmd->icon = QString::null; + cmd->menu_id = MenuSearchItem; + cmd->menu_grp = 0x2000; + cmd->bar_id = 0; + cmd->bar_grp = 0; + cmd->popup_id = MenuSearchGroups; + cmd->flags = COMMAND_DEFAULT; + EventCommandCreate(cmd).process(); + + cmd->id = CmdSearchOptions; + cmd->text = "_"; + cmd->icon = QString::null; + cmd->menu_id = MenuSearchItem; + cmd->menu_grp = 0x3000; + cmd->popup_id = 0; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdSearchInfo; + cmd->text = I18N_NOOP("&Info"); + cmd->icon = "info"; + cmd->menu_id = MenuSearchOptions; + cmd->menu_grp = 0x3000; + cmd->popup_id = 0; + cmd->flags = COMMAND_DEFAULT; + EventCommandCreate(cmd).process(); + + cmd->id = CmdSearchMsg; + cmd->text = I18N_NOOP("Send &message"); + cmd->icon = "message"; + cmd->menu_id = MenuSearchOptions; + cmd->menu_grp = 0x3001; + EventCommandCreate(cmd).process(); + + cmd->id = CmdContactGroup; + cmd->text = "_"; + cmd->flags = COMMAND_CHECK_STATE; + cmd->menu_id = MenuSearchGroups; + cmd->menu_grp = 0x1000; + EventCommandCreate(cmd).process(); +} + +void CorePlugin::initData() +{ + delete historyXSL; + + historyXSL = new XSL(value("HistoryStyle").toString()); + if (value("EditBackground").toUInt() == 0 && value("EditForeground").toUInt() == 0) + { + QPalette pal = QApplication::palette(); + setValue("EditBackground", pal.color(QPalette::Base).rgb() & 0xFFFFFF); + setValue("EditForeground", pal.color(QPalette::Text).rgb() & 0xFFFFFF); + } + editFont = FontEdit::str2font(value("EditFont").toString(), QApplication::font()); + setAutoReplies(); +} + +void CorePlugin::setPropertyHub(SIM::PropertyHubPtr hub) +{ + m_propertyHub = hub; +} + +SIM::PropertyHubPtr CorePlugin::propertyHub() +{ + return m_propertyHub; +} + +QVariant CorePlugin::value(const QString& key) +{ + return m_propertyHub->value(key); +} + +void CorePlugin::setValue(const QString& key, const QVariant& v) +{ + m_propertyHub->setValue(key, v); +} + +void CorePlugin::setAutoReplies() +{ + SIM::PropertyHubPtr data = getContacts()->getUserData("AR"); + for (autoReply *a = autoReplies; a->text; a++) + { + const QString &t = data->stringMapValue("AutoReply", a->status); + if (!t.isEmpty()) + continue; + + data->setStringMapValue("AutoReply", a->status, i18n(a->text)); + } +} + +CorePlugin::~CorePlugin() +{ + prepareConfig(); + //PropertyHub::save(); + destroy(); + delete m_lock; + delete m_cmds; + delete m_tmpl; + delete m_status; + delete historyXSL; + delete m_HistoryThread; + + removeTranslator(); +} + +QString CorePlugin::tsFile(const QString &lang) +{ +#if defined( WIN32 ) || defined( __OS2__ ) + // lang is ascii, so this works fine + QString s = "ts\\" + lang.toLower() + ".qm"; + QFile f(app_file(s)); + if (!f.exists()) + return QString(); +#else + QString s = PREFIX "/share/locale/"; + QString l = lang; + int idx = l.indexOf('.'); + if(idx != -1) + l = l.left(idx); + s += l; + s += "/LC_MESSAGES/sim.mo"; + QFile f(s); + if (!f.exists()) + { + QString l = lang; + int idx = l.indexOf('_'); + if(idx != -1) + l = l.left(idx); + + s = PREFIX "/share/locale/"; + s += l; + s += "/LC_MESSAGES/sim.mo"; + f.setFileName(s); + if (!f.exists()) + return QString(); + } +#endif + return f.fileName(); +} + +void CorePlugin::installTranslator() +{ + m_translator = NULL; + QString lang = value("Lang").toString(); + if (lang == "-") + return; + if (lang.isEmpty()) + { +#ifdef WIN32 + char buff[256]; + int res = GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SABBREVLANGNAME, buff, sizeof(buff)); + if (res){ + lang += (char)tolower(buff[0]); + lang += (char)tolower(buff[1]); + } +#else + #ifdef USE_KDE + return; + #else + char *p = getenv("LANG"); + if (p) + { + for (; *p; p++) + { + if (*p == '.') break; + lang += *p; + } + } + #endif +#endif + } + QString ts = tsFile(lang); + if (ts.isEmpty()) + return; + /* +#if !defined(WIN32) && !defined(USE_KDE) +m_translator = new SIMTranslator(NULL, po); +#else +*/ + m_translator = new QTranslator(NULL); + m_translator->load(ts); + //#endif + qApp->installTranslator(m_translator); +#if !defined(WIN32) && !defined(USE_KDE) + resetPlural(); +#endif + EventLanguageChanged e(m_translator); + e.process(); +} + +void CorePlugin::removeTranslator() +{ + if (m_translator) + { + qApp->removeTranslator(m_translator); + delete m_translator; + m_translator = NULL; +#if !defined(WIN32) && !defined(USE_KDE) + resetPlural(); +#endif + EventLanguageChanged e(NULL); + e.process(); + } +} + +struct msgIndex +{ + unsigned contact; + unsigned type; +}; + +struct msgCount +{ + unsigned count; + unsigned index; +}; + +bool operator < (const msgIndex &a, const msgIndex &b) +{ + if (a.contact < b.contact) + return true; + if (a.contact > b.contact) + return false; + return a.type < b.type; +} + + +Client* CorePlugin::getClient(unsigned i) +{ + return getContacts()->getClient(i); +} + +typedef map MAP_COUNT; + +void CorePlugin::getWays(vector &ways, Contact *contact) +{ + clientData *data; + ClientDataIterator it(contact->clientData); + while ((data = ++it) != NULL) + { + clientData *data1; + ClientDataIterator it1(contact->clientData); + bool bOK = true; + while ((data1 = ++it1) != NULL) + { + if (data1 == data) + break; + if (data->Sign.toULong() != data1->Sign.toULong()) + continue; + if (it.client()->compareData(data, data1)) + { + bOK = false; + break; + } + } + if (!bOK) + continue; + clientContact c; + c.client = it.client(); + c.data = data; + c.bNew = false; + ways.push_back(c); + for (unsigned i = 0; i < getContacts()->nClients(); i++) + { + Contact *clContact; + clientData *data2 = data; + if (getClient(i) == it.client() || !getClient(i)->isMyData(data2, clContact) || clContact != contact) + continue; + + clientContact c; + c.client = getClient(i); + c.data = data2; + c.bNew = false; + ways.push_back(c); + } + } +} + +void CorePlugin::changeClientStatus(SIM::Client* client, const SIM::IMStatusPtr& status) +{ + if (status->hasText()) { + bool noShow = propertyHub()->value("NoShowAutoReply" + status->id()).toBool(); + if (!noShow) { + AutoReplyDialog dlg(status); + if (!dlg.exec()) + return; + } + } + client->changeStatus(status); +} + +static const char *helpList[] = +{ + "&IP;", + I18N_NOOP("ip-address"), + "&Mail;", + I18N_NOOP("e-mail"), + "&Phone;", + I18N_NOOP("phone"), + "&Nick;", + I18N_NOOP("contact nick"), + "&Unread;", + I18N_NOOP("number of unread messages from this contact"), + "&Status;", + I18N_NOOP("contact status"), + "&TimeStatus;", + I18N_NOOP("time of set status"), + "&IntervalStatus;", + I18N_NOOP("time from set status"), + NULL, +}; + +#if 0 +I18N_NOOP("male", "%1 wrote:" ) +I18N_NOOP("female", "%1 wrote:" ) +#endif + +bool CorePlugin::processEventIconChanged() +{ + QStringList smiles; + getIcons()->getSmiles(smiles); + unsigned flags = 0; + QString smile_icon; + if (smiles.empty()) + flags = BTN_HIDE; + else + smile_icon = smiles.front(); + Command cmd; + cmd->id = CmdSmile; + cmd->text = I18N_NOOP("I&nsert smile"); + cmd->icon = smile_icon; + cmd->bar_id = ToolBarMsgEdit; + cmd->bar_grp = 0x7000; + cmd->flags = COMMAND_CHECK_STATE | flags; + EventCommandChange(cmd).process(); + return false; +} + +bool CorePlugin::processEventJoinAlert() +{ + if (!value("NoJoinAlert").toBool() && (m_alert == NULL)) + { + Command cmd; + cmd->id = CmdStatusBar; + EventCommandWidget eWidget(cmd); + eWidget.process(); + QWidget *widget = eWidget.widget(); + if (widget == NULL) + return true; + raiseWindow(widget->topLevelWidget()); + QStringList l; + l.append(i18n("OK")); + m_alert = new BalloonMsg(NULL, + quoteString( + i18n("At loading contact list contacts with identical names were automatically joined.\n" + "If it is wrong, you can separate them. " + "For this purpose in contact menu choose the necessary name and choose a command \"Separate\".")), + l, widget, NULL, false, true, 150, i18n("Don't show this message in next time")); + connect(m_alert, SIGNAL(finished()), this, SLOT(alertFinished())); + } + return true; +} + +bool CorePlugin::processEventGroup(Event* e) +{ + EventGroup *ev = static_cast(e); + if (ev->action() != EventGroup::eChanged) + return false; + if (m_bIgnoreEvents) + return true; + return false; +} + +bool CorePlugin::processEventDeleteMessage(SIM::Event* e) +{ + EventMessage *em = static_cast(e); + History::del(em->msg()); + return true; +} + +bool CorePlugin::processEventRewriteMessage(SIM::Event* e) +{ + EventMessage *em = static_cast(e); + History::rewrite(em->msg()); + return false; +} + +bool CorePlugin::processEventTmplHelp(SIM::Event* e) +{ + EventTmplHelp *eth = static_cast(e); + QString str = eth->help(); + for (const char **p = helpList; *p;) + { + str += *(p++); + str += " - "; + str += i18n(*(p++)); + str += '\n'; + } + str += '\n'; + str += i18n("`` - call and substitute command output\n"); + eth->setHelp(str); + return true; +} + +bool CorePlugin::processEventTmplHelpList(SIM::Event* e) +{ + EventTmplHelpList *ethl = static_cast(e); + ethl->setHelpList(helpList); + return true; +} + +bool CorePlugin::processEventARRequest(SIM::Event* e) +{ + EventARRequest *ear = static_cast(e); + ARRequest *r = ear->request(); + SIM::PropertyHubPtr ar; + QString tmpl; + if (r->contact) { + ar = r->contact->getUserData()->getUserData("AR"); + if (ar) + tmpl = ar->stringMapValue("AutoReply", r->status); + if (tmpl.isEmpty()) { + ar.clear(); + Group *grp = getContacts()->group(r->contact->getGroup()); + if (grp) + ar = r->contact->getUserData()->getUserData("AR"); + if (ar) + tmpl = ar->stringMapValue("AutoReply", r->status); + } + } + if (tmpl.isEmpty()) { + ar = getContacts()->getUserData("AR"); + tmpl = ar->stringMapValue("AutoReply", r->status); + if (tmpl.isEmpty()) + tmpl = ar->stringMapValue("AutoReply", STATUS_AWAY); + } + EventTemplate::TemplateExpand t; + t.contact = r->contact; + t.param = r->param; + t.receiver = r->receiver; + t.tmpl = tmpl; + EventTemplateExpand(&t).process(); + return true; +} + +bool CorePlugin::processEventSaveState(SIM::Event* e) +{ + SIM::PropertyHubPtr ar = getContacts()->getUserData("AR"); + for (autoReply *a = autoReplies; a->text; a++) + { + QString t = ar->stringMapValue("AutoReply", a->status); + if (t == i18n(a->text)) + ar->setStringMapValue("AutoReply", a->status, QString::null); + } + e->process(this); + setAutoReplies(); + return true; +} + +bool CorePlugin::processEventPluginChanged(SIM::Event* e) +{ + EventPluginChanged *p = static_cast(e); + if (p->pluginName() == "_core") + { + QString profile = ProfileManager::instance()->currentProfileName(); + setValue("StatusTime", (unsigned int)QDateTime::currentDateTime().toTime_t()); + removeTranslator(); + installTranslator(); + initData(); + EventUpdateCommandState(CmdOnline).process(); + } + return false; +} + +bool CorePlugin::processEventInit(SIM::Event* e) +{ + EventInit *i = static_cast(e); + if (!m_bInit && !init(true)) { + i->setAbortLoading(); + return true; + } + QTimer::singleShot(0, this, SLOT(checkHistory())); + QTimer::singleShot(0, this, SLOT(postInit())); + return false; +} + +bool CorePlugin::processEventHomeDir(SIM::Event* e) +{ + EventHomeDir *homedir = static_cast(e); + QString fname = homedir->homeDir(); + QString profile; + if(QDir(fname).isRelative()) + profile = ProfileManager::instance()->currentProfileName(); + if (profile.length()) + profile += '/'; + profile += fname; + homedir->setHomeDir(profile); + // dunno know if this is correct... :( + EventHomeDir eProfile(homedir->homeDir()); + if (!eProfile.process(this)) + homedir->setHomeDir(app_file(homedir->homeDir())); + else + homedir->setHomeDir(eProfile.homeDir()); + makedir(homedir->homeDir()); + return true; +} + +bool CorePlugin::processEventGetProfile(SIM::Event* e) +{ + EventGetProfile *e_get_profile = static_cast(e); + e_get_profile->setProfileValue(ProfileManager::instance()->currentProfileName()); + return true; +} + +bool CorePlugin::processEventAddPreferences(SIM::Event* e) +{ + EventAddPreferences *ap = static_cast(e); + CommandDef *cmd = ap->def(); + cmd->menu_id = MenuGroup; + EventCommandCreate(cmd).process(); + cmd->menu_id = MenuContact; + EventCommandCreate(cmd).process(); + preferences.add(cmd); + return true; +} + +bool CorePlugin::processEventRemovePreferences(SIM::Event* e) +{ + EventRemovePreferences *rm = static_cast(e); + unsigned long id = rm->id(); + EventCommandRemove(id).process(); + preferences.erase(id); + return true; +} + +bool CorePlugin::processEventClientChanged(SIM::Event* e) +{ + if(e->type() == eEventClientsChanged) + { + if (m_bInit) + loadMenu(); + } + if (getContacts()->nClients()){ + unsigned i; + for (i = 0; i < getContacts()->nClients(); i++) + if (getContacts()->getClient(i)->getCommonStatus()) + break; + if (i >= getContacts()->nClients()){ + Client *client = getContacts()->getClient(0); + //setManualStatus(client->getManualStatus()); + client->setCommonStatus(true); + EventClientChanged(client).process(); + } + } + return false; +} + +bool CorePlugin::processEventCreateMessageType(SIM::Event* e) +{ + EventCreateMessageType *ecmt = static_cast(e); + CommandDef *cmd = ecmt->def(); + if (cmd->menu_grp){ + cmd->menu_id = MenuMessage; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + } + if (cmd->param){ + MessageDef *mdef = (MessageDef*)(cmd->param); + if (mdef->cmdReceived){ + for (const CommandDef *c = mdef->cmdReceived; !c->text.isEmpty(); c++){ + CommandDef cmd = *c; + if(cmd.icon.isEmpty()){ + cmd.icon = "empty"; + cmd.flags |= BTN_PICT; + } + cmd.id += CmdReceived; + cmd.menu_id = 0; + cmd.menu_grp = 0; + cmd.flags |= COMMAND_CHECK_STATE; + EventCommandCreate(&cmd).process(); + } + } + if (mdef->cmdSent){ + for (const CommandDef *c = mdef->cmdSent; !c->text.isEmpty(); c++){ + CommandDef cmd = *c; + if(cmd.icon.isEmpty()){ + cmd.icon = "empty"; + cmd.flags |= BTN_PICT; + } + cmd.id += CmdReceived; + cmd.menu_id = 0; + cmd.menu_grp = 0; + cmd.flags |= COMMAND_CHECK_STATE; + EventCommandCreate(&cmd).process(); + } + } + } + messageTypes.add(cmd); + QString name = typeName(cmd->text); + MAP_TYPES::iterator itt = types.find(name); + if (itt == types.end()){ + types.insert(MAP_TYPES::value_type(name, cmd->id)); + }else{ + (*itt).second = cmd->id; + } + return true; +} + +bool CorePlugin::processEventRemoveMessageType(SIM::Event* e) +{ + EventRemoveMessageType *ermt = static_cast(e); + unsigned long id = ermt->id(); + CommandDef *def; + def = CorePlugin::instance()->messageTypes.find(id); + if (def){ + MessageDef *mdef = (MessageDef*)(def->param); + if (mdef->cmdReceived){ + for (const CommandDef *c = mdef->cmdReceived; !c->text.isEmpty(); c++){ + EventCommandRemove(c->id + CmdReceived).process(); + } + } + if (mdef->cmdSent){ + for (const CommandDef *c = mdef->cmdSent; !c->text.isEmpty(); c++){ + EventCommandRemove(c->id + CmdReceived).process(); + } + } + } + for (MAP_TYPES::iterator itt = types.begin(); itt != types.end(); ++itt){ + if ((*itt).second == id){ + types.erase(itt); + break; + } + } + EventCommandRemove(id).process(); + messageTypes.erase(id); + return true; +} + +bool CorePlugin::processEventContact(SIM::Event* e) +{ + EventContact *ec = static_cast(e); + Contact *contact = ec->contact(); + switch(ec->action()) { + case EventContact::eDeleted: + clearUnread(contact->id()); + History::remove(contact); + break; + case EventContact::eChanged: + if (m_bIgnoreEvents) + return true; + if (contact->getIgnore()) + clearUnread(contact->id()); + break; + case EventContact::eOnline: + { + SIM::PropertyHubPtr data = contact->getUserData("_core"); + if (!data.isNull() && data->value("OpenOnOnline").toBool()){ + Message *msg = new Message(MessageGeneric); + msg->setContact(contact->id()); + EventOpenMessage(msg).process(); + delete msg; // wasn't here before event changes... + } + break; + } + default: + break; + } + return false; +} + +bool CorePlugin::processEventMessageAcked(SIM::Event* e) +{ + EventMessage *em = static_cast(e); + Message *msg = em->msg(); + if (msg->baseType() == MessageFile){ + QWidget *w = new FileTransferDlg(static_cast(msg)); + raiseWindow(w); + } + return false; +} + +bool CorePlugin::processEventMessageDeleted(SIM::Event* e) +{ + EventMessage *em = static_cast(e); + Message *msg = em->msg(); + History::del(msg->id()); + for (list::iterator it = unread.begin(); it != unread.end(); ++it){ + msg_id &m = *it; + if (m.id == msg->id()){ + unread.erase(it); + break; + } + } + return false; +} + +bool CorePlugin::processEventMessageReceived(SIM::Event* e) +{ + EventMessage *em = static_cast(e); + Message *msg = em->msg(); + Contact *contact = getContacts()->contact(msg->contact()); + if (contact){ + if (msg->getTime() == 0){ + msg->setTime(QDateTime::currentDateTime().toTime_t()); + } + unsigned type = msg->baseType(); + if (type == MessageStatus){ + SIM::PropertyHubPtr data = contact->getUserData("_core"); + if ((data.isNull()) || !data->value("LogStatus").toBool()) + return false; + }else if (type == MessageFile){ + SIM::PropertyHubPtr data = contact->getUserData("_core"); + if(!data.isNull()){ + if (data->value("AcceptMode").toUInt() == 1){ + QString dir = data->value("IncomingPath").toString(); + if (!dir.isEmpty() && !dir.endsWith("/") && !dir.endsWith("\\")) + dir += '/'; + dir = user_file(dir); + EventMessageAccept(msg, dir, + data->value("OverwriteFiles").toBool() ? + Replace : Ask).process(); + return msg; + } + if (data->value("AcceptMode").toUInt() == 2){ + EventMessageDecline(msg, data->value("DeclineMessage").toString()).process(); + return msg; + } + } + }else{ + contact->setLastActive(QDateTime::currentDateTime().toTime_t()); + EventContact(contact, EventContact::eStatus).process(); + } + } + return processEventSent(e); +} + +bool CorePlugin::processEventSent(SIM::Event* e) +{ + EventMessage *em = static_cast(e); + Message *msg = em->msg(); + CommandDef *def = messageTypes.find(msg->type()); + if (def){ + History::add(msg, typeName(def->text)); + if ((e->type() == eEventMessageReceived) && (msg->type() != MessageStatus)){ + msg_id m; + m.id = msg->id(); + m.contact = msg->contact(); + m.client = msg->client(); + m.type = msg->baseType(); + unread.push_back(m); + if (msg->getFlags() & MESSAGE_NOVIEW) + return false; + Contact *contact = getContacts()->contact(msg->contact()); + if (contact && (contact->getFlags() & CONTACT_TEMPORARY)){ + contact->setFlags(contact->getFlags() & ~CONTACT_TEMPORARY); + EventContact(contact, EventContact::eChanged).process(); + } + if (contact){ + SIM::PropertyHubPtr data = contact->getUserData("_core"); + if (!data.isNull() && data->value("OpenNewMessage").toUInt()){ + if (data->value("OpenNewMessage").toUInt() == NEW_MSG_MINIMIZE) + msg->setFlags(msg->getFlags() | MESSAGE_NORAISE); + EventOpenMessage(msg).process(); + } + } + } + } + else + { + log(L_WARN,"No CommandDef for message %u found!",msg->type()); + } + return false; +} + +bool CorePlugin::processEventDefaultAction(SIM::Event* e) +{ + EventDefaultAction *eda = static_cast(e); + unsigned long contact_id = eda->id(); + unsigned index = 0; + for (list::iterator it = CorePlugin::instance()->unread.begin(); it != CorePlugin::instance()->unread.end(); ++it, index++){ + if (it->contact != contact_id) + continue; + Command cmd; + cmd->id = CmdUnread + index; + cmd->menu_id = MenuMain; + return EventCommandExec(cmd).process(); + } + EventMenuGetDef eMenu(MenuMessage); + eMenu.process(); + CommandsDef *cmdsMsg = eMenu.defs(); + CommandsList itc(*cmdsMsg, true); + CommandDef *c; + while ((c = ++itc) != NULL){ + c->param = (void*)(contact_id); + if(EventCheckCommandState(c).process()) { + return EventCommandExec(c).process(); + } + } + return false; +} + +bool CorePlugin::processEventLoadMessage(SIM::Event* e) +{ + EventLoadMessage *elm = static_cast(e); + Message *msg = History::load(elm->id(), elm->client(), elm->contact()); + elm->setMessage(msg); + return true; +} + +bool CorePlugin::processEventOpenMessage(SIM::Event* e) +{ + EventMessage *em = static_cast(e); + Message *msg = em->msg(); + if (msg->getFlags() & MESSAGE_NOVIEW) + return false; + Contact *contact = getContacts()->contact(msg->contact()); + m_focus = qApp->focusWidget(); + if (m_focus) + connect(m_focus, SIGNAL(destroyed()), this, SLOT(focusDestroyed())); + if (contact == NULL) + return false; + UserWnd *userWnd = NULL; + Container *container = NULL; + QWidgetList list = QApplication::topLevelWidgets(); + QWidget * w; + bool bNew = false; + log(L_DEBUG, "contactID: %ld", contact->id()); + foreach (w,list) + { + if (w->inherits("Container")) + { + log(L_DEBUG, "ContainerFound"); + container = static_cast(w); + if(getContainerMode() == 0) + { + log(L_DEBUG, "Mode0"); + if(container->isReceived() != ((msg->getFlags() & MESSAGE_RECEIVED) != 0)) + { + container = NULL; + continue; + } + } + userWnd = container->wnd(contact->id()); + if (userWnd) + { + log(L_DEBUG, "found"); + break; + } + container = NULL; + } + } + if(userWnd == NULL) + { + log(L_DEBUG, "notfound"); + if (contact->getFlags() & CONTACT_TEMP) + { + contact->setFlags(contact->getFlags() & ~CONTACT_TEMP); + EventContact(contact, EventContact::eChanged).process(); + } + userWnd = new UserWnd(contact->id(), NULL, msg->getFlags() & MESSAGE_RECEIVED, msg->getFlags() & MESSAGE_RECEIVED); + if(getContainerMode() == 3) + { + QWidgetList list = QApplication::topLevelWidgets(); + QWidget * w; + foreach (w,list) + { + if (w->inherits("Container")){ + container = static_cast(w); + break; + } + } + if (container == NULL){ + container = new Container(1); + bNew = true; + } + } + else if (getContainerMode() == 2) + { + unsigned id = contact->getGroup() + CONTAINER_GRP; + QWidgetList list = QApplication::topLevelWidgets(); + QWidget * w; + foreach (w,list) + { + if(w->inherits("Container")) + { + container = static_cast(w); + if (container->getId() == id) + break; + container = NULL; + } + } + if(container == NULL) + { + container = new Container(id); + bNew = true; + } + } + else + { + unsigned max_id = 0; + QWidgetList list = QApplication::topLevelWidgets(); + QWidget * w; + foreach (w,list) + { + if (w->inherits("Container")) + { + container = static_cast(w); + if(!(container->getId() & CONTAINER_GRP)) + { + if(max_id < container->getId()) + max_id = container->getId(); + } + } + } + container = new Container(max_id + 1); + bNew = true; + if (getContainerMode() == 0) + container->setReceived(msg->getFlags() & MESSAGE_RECEIVED); + } + container->addUserWnd(userWnd, (msg->getFlags() & MESSAGE_NORAISE) == 0); + } + else + { + if ((msg->getFlags() & MESSAGE_NORAISE) == 0) + container->raiseUserWnd(userWnd->id()); + } + container->setNoSwitch(true); + userWnd->setMessage(msg); + if (msg->getFlags() & MESSAGE_NORAISE){ + if (bNew){ + container->m_bNoRead = true; +#ifdef WIN32 + ShowWindow(container->winId(), SW_SHOWMINNOACTIVE); +#else + container->init(); + container->showMinimized(); +#endif + } + if (m_focus) + m_focus->setFocus(); + }else{ + container->init(); + container->show(); + raiseWindow(container); + } + container->setNoSwitch(false); + if (m_focus) + disconnect(m_focus, SIGNAL(destroyed()), this, SLOT(focusDestroyed())); + m_focus = NULL; + return true; +} + +bool CorePlugin::processCheckCmdChangeEncoding(SIM::CommandDef* cmd) +{ + Contact *contact = getContacts()->contact((unsigned long)(cmd->param)); + if (contact == NULL) + return false; + QTextCodec *codec = getContacts()->getCodec(contact); + unsigned nEncoding = 3; + QStringList main; + QStringList nomain; + QStringList::Iterator it; + const ENCODING *enc; + for (enc = getContacts()->getEncodings(); enc->language; enc++){ + if (enc->bMain){ + main.append(i18n(enc->language) + " (" + enc->codec + ')'); + nEncoding++; + continue; + } + if (!value("ShowAllEncodings").toBool()) + continue; + nomain.append(i18n(enc->language) + " (" + enc->codec + ')'); + nEncoding++; + } + CommandDef *cmds = new CommandDef[nEncoding]; + cmd->param = cmds; + cmd->flags |= COMMAND_RECURSIVE; + nEncoding = 0; + cmds[nEncoding].id = 1; + cmds[nEncoding].text = I18N_NOOP("System"); + if (!strcmp(codec->name(), "System")) + cmds[nEncoding].flags = COMMAND_CHECKED; + nEncoding++; + main.sort(); + for (it = main.begin(); it != main.end(); ++it){ + QString str = *it; + int n = str.indexOf('('); + str = str.mid(n + 1); + n = str.indexOf(')'); + str = str.left(n); + if (str == codec->name()) + cmds[nEncoding].flags = COMMAND_CHECKED; + cmds[nEncoding].id = nEncoding + 1; + cmds[nEncoding].text = "_"; + cmds[nEncoding].text_wrk = (*it); + nEncoding++; + } + if (!value("ShowAllEncodings").toBool()) + return true; + cmds[nEncoding++].text = "_"; + nomain.sort(); + for (it = nomain.begin(); it != nomain.end(); ++it){ + QString str = *it; + int n = str.indexOf('('); + str = str.mid(n + 1); + n = str.indexOf(')'); + str = str.left(n); + if (str == codec->name()) + cmds[nEncoding].flags = COMMAND_CHECKED; + cmds[nEncoding].id = nEncoding; + cmds[nEncoding].text = "_"; + cmds[nEncoding].text_wrk = (*it); + nEncoding++; + } + return true; +} + +bool CorePlugin::processCheckCmdAllEncodings(SIM::CommandDef* cmd) +{ + cmd->flags &= ~COMMAND_CHECKED; + if (value("ShowAllEncodings").toBool()) + cmd->flags |= COMMAND_CHECKED; + return true; +} + +bool CorePlugin::processCheckCmdEnableSpell(SIM::CommandDef* cmd) +{ + cmd->flags &= ~COMMAND_CHECKED; + if (value("EnableSpell").toBool()) + cmd->flags |= COMMAND_CHECKED; + return true; +} + +bool CorePlugin::processCheckCmdSendClose(SIM::CommandDef* cmd) +{ + cmd->flags &= ~COMMAND_CHECKED; + if (value("CloseSend").toBool()) + cmd->flags |= COMMAND_CHECKED; + return false; +} + +bool CorePlugin::processCheckCmdContactClients(SIM::CommandDef* cmd) +{ + Contact *contact = getContacts()->contact((unsigned long)(cmd->param)); + if (contact == NULL) + return false; + vector ways; + getWays(ways, contact); + if (cmd->menu_id == MenuMessage){ + unsigned n = ways.size(); + if (n < 1) + return false; + if (n == 1){ + QString resources = ways[0].client->resources(ways[0].data); + if (resources.isEmpty()) + return false; + QString wrk = resources; + unsigned n = 0; + while (!wrk.isEmpty()){ + getToken(wrk, ';'); + n++; + } + CommandDef *cmds = new CommandDef[n + 2]; + cmds[0].text = "_"; + n = 1; + while (!resources.isEmpty()){ + unsigned long id = CmdContactResource + n; + if (n > m_nResourceMenu){ + m_nResourceMenu = n; + EventMenu(id, EventMenu::eAdd).process(); + Command cmd; + cmd->id = CmdContactClients; + cmd->text = "_"; + cmd->menu_id = id; + cmd->menu_grp = 0x1000; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + } + cmds[n].id = id; + cmds[n].text = "_"; + cmds[n].popup_id = id; + QString res = getToken(resources, ';'); + cmds[n].icon = (const char*)(getToken(res, ',').toULong()); + QString t = ways[0].client->contactName(ways[0].data); + t += '/' + res; + cmds[n].text_wrk = t; + n++; + } + cmd->param = cmds; + cmd->flags |= COMMAND_RECURSIVE; + return true; + } + CommandDef *cmds = new CommandDef[n + 2]; + cmds[0].text = "_"; + n = 1; + for (vector::iterator itw = ways.begin(); itw != ways.end(); ++itw, n++){ + unsigned long id = CmdContactClients + n; + if (n > m_nClientsMenu){ + m_nClientsMenu = n; + EventMenu(id, EventMenu::eAdd).process(); + + Command cmd; + cmd->id = CmdContactClients; + cmd->text = "_"; + cmd->menu_id = id; + cmd->menu_grp = 0x1000; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdSeparate; + cmd->text = I18N_NOOP("&Separate"); + cmd->menu_grp = 0x2000; + cmd->flags = COMMAND_DEFAULT; + EventCommandCreate(cmd).process(); + } + cmds[n].id = id; + cmds[n].text = "_"; + cmds[n].popup_id = id; + unsigned long status = STATUS_UNKNOWN; + unsigned style = 0; + QString statusIcon; + if (itw->bNew){ + void *data = itw->data; + Client *client = contact->clientData.activeClient(data, itw->client); + if (client == NULL){ + client = itw->client; + data = itw->data; + } + client->contactInfo(data, status, style, statusIcon); + }else{ + itw->client->contactInfo(itw->data, status, style, statusIcon); + } + cmds[n].icon = statusIcon; + QString t = itw->client->contactName(itw->data); + bool bFrom = false; + for (unsigned i = 0; i < getContacts()->nClients(); i++){ + Client *client = getContacts()->getClient(i); + if (client == itw->client) + continue; + Contact *contact; + clientData *data = itw->data; + if (client->isMyData(data, contact)){ + bFrom = true; + break; + } + } + if (bFrom){ + t += ' '; + t += i18n("from %1") .arg(itw->client->name()); + } + cmds[n].text_wrk = t; + } + cmd->param = cmds; + cmd->flags |= COMMAND_RECURSIVE; + return true; + } + if (cmd->menu_id > CmdContactResource){ + unsigned nRes = cmd->menu_id - CmdContactResource - 1; + unsigned n; + for (n = 0; n < ways.size(); n++){ + QString resources = ways[n].client->resources(ways[n].data); + while (!resources.isEmpty()){ + getToken(resources, ';'); + if (nRes-- == 0){ + clientContact &cc = ways[n]; + EventMenuGetDef eMenu(MenuMessage); + eMenu.process(); + CommandsDef *cmdsMsg = eMenu.defs(); + unsigned nCmds = 0; + { + CommandsList it(*cmdsMsg, true); + while (++it) + nCmds++; + } + CommandDef *cmds = new CommandDef[nCmds]; + nCmds = 0; + + CommandsList it(*cmdsMsg, true); + CommandDef *c; + while ((c = ++it) != NULL){ + if ((c->id == MessageSMS) && (cc.client->protocol()->description()->flags & PROTOCOL_NOSMS)) + continue; + if (!cc.client->canSend(c->id, cc.data)){ + EventCheckSend e(c->id, cc.client, cc.data); + if (!e.process()) + continue; + } + cmds[nCmds] = *c; + cmds[nCmds].id = c->id; + cmds[nCmds].flags = COMMAND_DEFAULT; + cmds[nCmds].menu_id = cmd->menu_id; + nCmds++; + } + cmd->param = cmds; + cmd->flags |= COMMAND_RECURSIVE; + return true; + } + } + } + return false; + } + unsigned n = cmd->menu_id - CmdContactClients - 1; + if (n >= ways.size()) + return false; + clientContact &cc = ways[n]; + + EventMenuGetDef eMenu(MenuMessage); + eMenu.process(); + CommandsDef *cmdsMsg = eMenu.defs(); + unsigned nCmds = 0; + { + CommandsList it(*cmdsMsg, true); + while (++it) + nCmds++; + } + QString resources = cc.client->resources(cc.data); + if (!resources.isEmpty()){ + nCmds++; + while (!resources.isEmpty()){ + getToken(resources, ';'); + nCmds++; + } + } + + CommandDef *cmds = new CommandDef[nCmds]; + nCmds = 0; + + CommandsList it(*cmdsMsg, true); + CommandDef *c; + while ((c = ++it) != NULL){ + if ((c->id == MessageSMS) && (cc.client->protocol()->description()->flags & PROTOCOL_NOSMS)) + continue; + if (!cc.client->canSend(c->id, cc.data)){ + EventCheckSend e(c->id, cc.client, cc.data); + if (!e.process()) + continue; + } + cmds[nCmds] = *c; + cmds[nCmds].id = c->id; + cmds[nCmds].flags = COMMAND_DEFAULT; + cmds[nCmds].menu_id = cmd->menu_id; + nCmds++; + } + resources = cc.client->resources(cc.data); + if (!resources.isEmpty()){ + cmds[nCmds++].text = "_"; + unsigned nRes = 1; + for (unsigned i = 0; i < n; i++){ + QString resources = ways[i].client->resources(ways[i].data); + while (!resources.isEmpty()){ + getToken(resources, ';'); + unsigned long id = CmdContactResource + nRes; + if (nRes > m_nResourceMenu){ + m_nResourceMenu = nRes; + EventMenu(id, EventMenu::eAdd).process(); + Command cmd; + cmd->id = CmdContactClients; + cmd->text = "_"; + cmd->menu_id = id; + cmd->menu_grp = 0x1000; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + } + nRes++; + } + } + QString resources = cc.client->resources(cc.data); + while (!resources.isEmpty()){ + unsigned long id = CmdContactResource + nRes; + if (nRes > m_nResourceMenu){ + m_nResourceMenu = nRes; + EventMenu(id, EventMenu::eAdd).process(); + Command cmd; + cmd->id = CmdContactClients; + cmd->text = "_"; + cmd->menu_id = id; + cmd->menu_grp = 0x1000; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + } + cmds[nCmds].id = id; + cmds[nCmds].text = "_"; + cmds[nCmds].popup_id = id; + QString res = getToken(resources, ';'); + cmds[nCmds].icon = (const char*)getToken(res, ',').toULong(); + QString t = cc.client->contactName(ways[0].data); + t += '/' + res; + cmds[nCmds++].text_wrk = t; + nRes++; + } + } + cmd->param = cmds; + cmd->flags |= COMMAND_RECURSIVE; + + return true; +} + +bool CorePlugin::processCheckMenuContainer(SIM::CommandDef* cmd) +{ + Contact *contact = getContacts()->contact((unsigned long)(cmd->param)); + if (contact){ + unsigned nContainers = 1; + QWidgetList list = QApplication::topLevelWidgets(); + QWidget * w; + foreach(w,list) + { + if (w->inherits("Container")) + nContainers++; + } + CommandDef *cmds = new CommandDef[nContainers + 1]; + unsigned n = 0; + foreach(w,list) + { + if (w->inherits("Container")){ + Container *c = static_cast(w); + cmds[n] = *cmd; + cmds[n].icon = QString::null; + cmds[n].id = c->getId(); + cmds[n].flags = COMMAND_DEFAULT; + cmds[n].text_wrk = c->name(); + if (c->wnd(contact->id())) + cmds[n].flags |= COMMAND_CHECKED; + n++; + } + } + cmds[n].icon = QString::null; + cmds[n].id = NEW_CONTAINER; + cmds[n].flags = COMMAND_DEFAULT; + cmds[n].text = I18N_NOOP("&New"); + cmd->param = cmds; + cmd->flags |= COMMAND_RECURSIVE; + return true; + } + return false; +} + +bool CorePlugin::processCheckMenuMessage(SIM::CommandDef* cmd) +{ + cmd->flags &= ~COMMAND_CHECKED; + Contact *contact = getContacts()->contact((unsigned long)(cmd->param)); + if (contact){ + vector ways; + getWays(ways, contact); + for (vector::iterator it = ways.begin(); it != ways.end(); ++it){ + if ((cmd->id == MessageSMS) && (it->client->protocol()->description()->flags & PROTOCOL_NOSMS)) + return false; + if (it->client->canSend(cmd->id, it->data)){ + return true; + } + } + if ((cmd->id == MessageSMS) && !ways.empty()){ + vector::iterator it; + for (it = ways.begin(); it != ways.end(); ++it){ + if ((it->client->protocol()->description()->flags & PROTOCOL_NOSMS) == 0) + break; + } + if (it == ways.end()) + return false; + } + } + for (unsigned i = 0; i < getContacts()->nClients(); i++){ + if (getContacts()->getClient(i)->canSend(cmd->id, NULL)) + return true; + } + return false; +} + +bool CorePlugin::processCheckMenuMsgCommand(SIM::CommandDef* cmd) +{ + Message *msg = (Message*)(cmd->param); + switch (cmd->id){ + case CmdMsgQuote: + case CmdMsgForward: + if ((msg->getFlags() & MESSAGE_RECEIVED) == 0) + return false; + QString p = msg->presentation(); + if (!p.isEmpty()){ + unsigned type = msg->baseType(); + switch (type){ + case MessageFile: + return false; + } + cmd->flags &= ~COMMAND_CHECKED; + return true; + } + break; + } + return false; +} + +bool CorePlugin::processCheckCmdPhoneLocation(SIM::CommandDef* cmd) +{ + unsigned n = 2; + QString phones = getContacts()->owner()->getPhones(); + while (!phones.isEmpty()){ + getToken(phones, ';'); + n++; + } + CommandDef *cmds = new CommandDef[n]; + n = 0; + cmds[n].id = CmdPhoneLocation; + cmds[n].text = I18N_NOOP("Not available"); + cmds[n].menu_id = MenuPhoneLocation; + phones = getContacts()->owner()->getPhones(); + bool bActive = false; + while (!phones.isEmpty()){ + n++; + QString item = getToken(phones, ';', false); + item = getToken(item, '/', false); + QString number = getToken(item, ','); + getToken(item, ','); + unsigned long icon = getToken(item, ',').toULong(); + cmds[n].id = CmdPhoneLocation + n; + cmds[n].text = "_"; + cmds[n].menu_id = MenuPhoneLocation; + cmds[n].text_wrk = number; + if (!item.isEmpty()){ + cmds[n].flags = COMMAND_CHECKED; + bActive = true; + } + switch (icon){ + case PHONE: + cmds[n].icon = "phone"; + break; + case FAX: + cmds[n].icon = "fax"; + break; + case CELLULAR: + cmds[n].icon = "cell"; + break; + case PAGER: + cmds[n].icon = "pager"; + break; + } + } + if (!bActive) + cmds[0].flags = COMMAND_CHECKED; + cmd->param = cmds; + cmd->flags |= COMMAND_RECURSIVE; + return true; +} + +bool CorePlugin::processCheckCmdUnread(SIM::CommandDef* cmd) +{ + unsigned long contact_id = 0; + if (cmd->menu_id == MenuContact) + contact_id = (unsigned long)cmd->param; + MAP_COUNT count; + MAP_COUNT::iterator itc; + CommandDef *def; + unsigned n = 0; + for (list::iterator it = unread.begin(); it != unread.end(); ++it, n++){ + if (contact_id && (it->contact != contact_id)) + continue; + msgIndex m; + m.contact = it->contact; + m.type = it->type; + itc = count.find(m); + if (itc == count.end()){ + msgCount c; + c.index = n; + c.count = 1; + count.insert(MAP_COUNT::value_type(m, c)); + }else{ + msgCount &c = (*itc).second; + c.index = n; + c.count++; + } + } + if (count.empty()) + return false; + CommandDef *cmds = new CommandDef[count.size() + 1]; + n = 0; + for (itc = count.begin(); itc != count.end(); ++itc, n++){ + cmds[n].id = CmdUnread + (*itc).second.index; + def = messageTypes.find((*itc).first.type); + if (def == NULL) + continue; + MessageDef *mdef = (MessageDef*)(def->param); + cmds[n].icon = def->icon; + QString msg = i18n(mdef->singular, mdef->plural, (*itc).second.count); + if(msg.isEmpty()) + { + log(L_ERROR, "Message is missing some definitions! Text: %s, ID: %lu", + qPrintable(def->text), def->id); + int cnt = (*itc).second.count; + msg = QString("%1").arg(cnt); + } + if ((*itc).second.count == 1){ + int n = msg.indexOf("1 "); + if (n == 0){ + msg = msg.left(1).toUpper() + msg.mid(1); + }else{ + msg = msg.left(n - 1); + } + } + if (contact_id == 0){ + Contact *contact = getContacts()->contact((*itc).first.contact); + if (contact == NULL) + continue; + msg = i18n("%1 from %2") + .arg(msg) + .arg(contact->getName()); + } + cmds[n].text_wrk = msg; + cmds[n].text = "_"; + } + cmd->param = cmds; + cmd->flags |= COMMAND_RECURSIVE; + return true; +} + +bool CorePlugin::processCheckCmdSendSMS(SIM::CommandDef* cmd) +{ + cmd->flags &= COMMAND_CHECKED; + for (unsigned i = 0; i < getContacts()->nClients(); i++){ + Client *client = getContacts()->getClient(i); + if (client->canSend(MessageSMS, NULL)) + return true; + } + return false; +} + +bool CorePlugin::processCheckCmdShowPanel(SIM::CommandDef* cmd) +{ + cmd->flags &= ~COMMAND_CHECKED; + if (m_statusWnd) + cmd->flags |= COMMAND_CHECKED; + return true; +} + +bool CorePlugin::processCheckCmdCommonStatus(SIM::CommandDef* cmd) +{ + unsigned n = cmd->menu_id - CmdClient; + if (n >= getContacts()->nClients()) + return false; + Client *client = getContacts()->getClient(n); + cmd->flags &= ~COMMAND_CHECKED; + if (client->getCommonStatus()) + cmd->flags |= COMMAND_CHECKED; + return true; +} + +bool CorePlugin::processEventCheckCommandState(SIM::Event* e) +{ + EventCheckCommandState *ecs = static_cast(e); + CommandDef *cmd = ecs->cmd(); + if (cmd->menu_id == MenuEncoding){ + if (cmd->id == CmdChangeEncoding) { + return processCheckCmdChangeEncoding(cmd); + } + if (cmd->id == CmdAllEncodings) { + return processCheckCmdAllEncodings(cmd); + } + } + if (cmd->id == CmdEnableSpell) { + return processCheckCmdEnableSpell(cmd); + } + if (cmd->id == CmdSendClose) { + return processCheckCmdSendClose(cmd); + } + if ((cmd->id == CmdFileAccept) || (cmd->id == CmdFileDecline)) { + Message *msg = (Message*)(cmd->param); + if (msg->getFlags() & MESSAGE_TEMP) + return true; + return false; + } + if (cmd->id == CmdContactClients) { + return processCheckCmdContactClients(cmd); + } + if (cmd->menu_id == MenuContainer) { + return processCheckMenuContainer(cmd); + } + if (cmd->menu_id == MenuMessage) { + return processCheckMenuMessage(cmd); + } + if (cmd->menu_id == MenuMsgCommand){ + return processCheckMenuMsgCommand(cmd); + } + if (cmd->menu_id == MenuPhoneState){ + cmd->flags &= ~COMMAND_CHECKED; + if (cmd->id == CmdPhoneNoShow + getContacts()->owner()->getPhoneStatus()) + cmd->flags |= COMMAND_CHECKED; + return true; + } + if ((cmd->menu_id == MenuPhoneLocation) && (cmd->id == CmdPhoneLocation)){ + return processCheckCmdPhoneLocation(cmd); + } + if (cmd->id == CmdUnread){ + return processCheckCmdUnread(cmd); + } + if (cmd->id == CmdSendSMS){ + return processCheckCmdSendSMS(cmd); + } + if (cmd->id == CmdShowPanel){ + return processCheckCmdShowPanel(cmd); + } + if ((cmd->id == CmdContainer) && (cmd->menu_id == MenuContact)){ + if (getContainerMode() && getContainerMode() != 3) + return true; + return false; + } + if (cmd->id == CmdCommonStatus){ + return processCheckCmdCommonStatus(cmd); + } + if (cmd->id == CmdTitle) { + if (cmd->param && adjustClientItem(cmd->menu_id, cmd)) + return true; + return false; + } + if (adjustClientItem(cmd->id, cmd)) + return true; + unsigned n = cmd->menu_id - CmdClient; + if (n > getContacts()->nClients()) + return false; + Client *client = getContacts()->getClient(n); + if (cmd->id == CmdInvisible){ + if (client->getInvisible()){ + cmd->flags |= COMMAND_CHECKED; + }else{ + cmd->flags &= ~COMMAND_CHECKED; + } + return true; + } + const CommandDef *curStatus = NULL; + const CommandDef *d; + for (d = client->protocol()->statusList(); !d->text.isEmpty(); d++){ + if (d->id == cmd->id) + curStatus = d; + } + if (curStatus == NULL) + return 0; + bool bChecked = false; + unsigned status = client->getManualStatus(); + bChecked = (status == curStatus->id); + if (bChecked){ + cmd->flags |= COMMAND_CHECKED; + }else{ + cmd->flags &= ~COMMAND_CHECKED; + } + return true; +} + +bool CorePlugin::processExecMenuEncoding(SIM::CommandDef* cmd) +{ + if (cmd->id == CmdAllEncodings) + { + Command c; + c->id = CmdChangeEncoding; + c->param = cmd->param; + EventCommandWidget eWidget(cmd); + eWidget.process(); + QToolButton *btn = qobject_cast(eWidget.widget()); + if (btn) + QTimer::singleShot(0, btn, SLOT(animateClick())); + setValue("ShowAllEncodings", !value("ShowAllEncodings").toBool()); + return true; + } + Contact *contact = getContacts()->contact((unsigned long)(cmd->param)); + if (contact == NULL) + return false; + QByteArray codecStr; + const char *codec = NULL; + if (cmd->id == 1) + { + codec = "-"; + } + else + { + QStringList main; + QStringList nomain; + QStringList::Iterator it; + const ENCODING *enc; + for (enc = getContacts()->getEncodings(); enc->language; enc++){ + if (enc->bMain){ + main.append(i18n(enc->language) + " (" + enc->codec + ')'); + continue; + } + if (!value("ShowAllEncodings").toBool()) + continue; + nomain.append(i18n(enc->language) + " (" + enc->codec + ')'); + } + QString str; + main.sort(); + int n = cmd->id - 1; + for (it = main.begin(); it != main.end(); ++it){ + if (--n == 0){ + str = *it; + break; + } + } + if (n >= 0){ + nomain.sort(); + for (it = nomain.begin(); it != nomain.end(); ++it){ + if (--n == 0){ + str = *it; + break; + } + } + } + if (!str.isEmpty()){ + int n = str.indexOf('('); + str = str.mid(n + 1); + n = str.indexOf(')'); + codecStr = str.left(n).toLatin1(); + codec = codecStr; + } + } + if (codec == NULL) + return false; + QString oldCodec = contact->getEncoding(); + if (oldCodec != codec){ + contact->setEncoding(codec); + EventContact(contact, EventContact::eChanged).process(); + EventHistoryConfig(contact->id()).process(); + } + return false; +} + +bool CorePlugin::processExecMenuMessage(SIM::CommandDef* cmd) +{ + Message *msg; + CommandDef *def = messageTypes.find(cmd->id); + if (def == NULL) + return false; + MessageDef *mdef = (MessageDef*)(def->param); + if (mdef->create == NULL) + return false; + msg = mdef->create(NULL); + msg->setContact((unsigned long)(cmd->param)); + if (mdef->flags & MESSAGE_SILENT){ + Contact *contact = getContacts()->contact((unsigned long)(cmd->param)); + if (contact){ + ClientDataIterator it(contact->clientData); + void *data; + while ((data = ++it) != NULL){ + Client *client = it.client(); + if (client->canSend(msg->type(), data) && client->send(msg, data)) + break; + } + } + return true; + } + EventOpenMessage(msg).process(); + delete msg; + return true; +} + +bool CorePlugin::processExecMenuMsgCommand(SIM::CommandDef* cmd) +{ + Message *msg = (Message*)(cmd->param); + QString p; + switch (cmd->id){ + case CmdMsgQuote: + case CmdMsgForward: + p = msg->presentation(); + if (p.isEmpty()) + return false; + p = unquoteText(p); + QStringList l = p.split('\n'); + QStringList::Iterator it; + if (l.count() && l.last().isEmpty()){ + it = l.end(); + --it; + l.removeLast(); + } + for (it = l.begin(); it != l.end(); ++it) + (*it) = QLatin1String(">") + (*it); + p = l.join("\n"); + Message *m = new Message(MessageGeneric); + m->setContact(msg->contact()); + m->setClient(msg->client()); + if (cmd->id == CmdMsgForward){ + QString name; + Contact *contact = getContacts()->contact(msg->contact()); + if (contact) + name = contact->getName(); + p = g_i18n("%1 wrote:", contact) .arg(name) + '\n' + p; + m->setFlags(MESSAGE_FORWARD); + }else{ + m->setFlags(MESSAGE_INSERT); + } + m->setText(p); + EventOpenMessage(m).process(); + delete m; + return true; + } + return false; +} + +bool CorePlugin::processExecCmdGrantAuth(SIM::CommandDef* cmd) +{ + Message *from = (Message*)(cmd->param); + Message *msg = new AuthMessage(MessageAuthGranted); + msg->setContact(from->contact()); + msg->setClient(from->client()); + Contact *contact = getContacts()->contact(msg->contact()); + if (contact){ + void *data; + ClientDataIterator it(contact->clientData); + while ((data = ++it) != NULL){ + Client *client = it.client(); + if (!from->client().isEmpty()){ + if ((client->dataName(data) == from->client()) && client->send(msg, data)) + return true; + }else{ + if (client->canSend(MessageAuthGranted, data) && client->send(msg, data)) + return true; + } + } + } + delete msg; + return true; +} + +bool CorePlugin::processExecCmdRefuseAuth(SIM::CommandDef* cmd) +{ + Message *from = (Message*)(cmd->param); + Message *msg = new AuthMessage(MessageAuthRefused); + msg->setContact(from->contact()); + msg->setClient(from->client()); + EventOpenMessage(msg).process(); + delete msg; + return true; +} + +bool CorePlugin::processExecCmdSeparate(SIM::CommandDef* cmd) +{ + Contact *contact = getContacts()->contact((unsigned long)(cmd->param)); + if (contact == NULL) + return false; + unsigned n = cmd->menu_id - CmdContactClients - 1; + vector ways; + getWays(ways, contact); + if (n >= ways.size()) + return false; + clientContact &cc = ways[n]; + clientData *data; + ClientDataIterator it(contact->clientData, cc.client); + while ((data = ++it) != NULL){ + if (data == cc.data) + break; + } + if (data == NULL){ + data = cc.data; + cc.client->createData(data, contact); + } + Contact *newContact = getContacts()->contact(0, true); + newContact->setGroup(contact->getGroup()); + newContact->clientData.join(data, contact->clientData); + contact->setup(); + newContact->setup(); + EventContact e1(contact, EventContact::eChanged); + e1.process(); + EventContact e2(newContact, EventContact::eChanged); + e2.process(); + return true; +} + +bool CorePlugin::processExecCmdSendSMS(SIM::CommandDef* /*cmd*/) +{ + Contact *contact = getContacts()->contact(0, true); + contact->setFlags(CONTACT_TEMP); + contact->setName(i18n("Send SMS")); + EventContact eChanged(contact, EventContact::eChanged); + eChanged.process(); + Command com; + com->id = MessageSMS; + com->menu_id = MenuMessage; + com->param = (void*)(contact->id()); + EventCommandExec(com).process(); + return true; +} + +bool CorePlugin::processExecCmdHistory(SIM::CommandDef* cmd) +{ + unsigned long id = (unsigned long)(cmd->param); + if (!value("UseExtViewer").toBool()){ + HistoryWindow *wnd = NULL; + QWidgetList list = QApplication::topLevelWidgets(); + QWidget * w; + foreach(w,list) + { + if(w->inherits("HistoryWindow")) + { + wnd = static_cast(w); + if (wnd->id() == id) + break; + wnd = NULL; + } + } + if (wnd == NULL){ + wnd = new HistoryWindow(id); + unsigned int historySizeX = value("HistorySizeX").toUInt(); + unsigned int historySizeY = value("HistorySizeY").toUInt(); + if(historySizeX && historySizeY) + wnd->resize(historySizeX, historySizeY); + } + raiseWindow(wnd); + } + else + { + if (!m_HistoryThread) + m_HistoryThread = new HistoryThread(); + m_HistoryThread->set_id(id); + m_HistoryThread->set_Viewer(value("ExtViewer").toString()); + m_HistoryThread->start(); + } + return true; +} + +bool CorePlugin::processExecCmdConfigure(SIM::CommandDef* cmd) +{ + if ((cmd->menu_id == MenuContact) || (cmd->menu_id == MenuGroup)){ + showInfo(cmd); + return true; + } + if (m_cfg == NULL){ + m_cfg = new ConfigDlg::ConfigureDialog(); + connect(m_cfg, SIGNAL(finished()), this, SLOT(dialogFinished())); + + unsigned int cfgGeometryWidth = value("CfgGeometryWidth").toUInt(); + unsigned int cfgGeometryHeight = value("CfgGeometryHeight").toUInt(); + if(cfgGeometryWidth == 0 || cfgGeometryHeight == 0) + { + cfgGeometryWidth = 500; + cfgGeometryHeight = 380; + } + m_cfg->resize(cfgGeometryWidth, cfgGeometryHeight); + } + raiseWindow(m_cfg); + return true; +} + +bool CorePlugin::processExecCmdSearch(SIM::CommandDef* /*cmd*/) +{ + if (m_search == NULL){ + m_search = new SearchDialog; + connect(m_search, SIGNAL(finished()), this, SLOT(dialogFinished())); + unsigned int searchGeometryWidth = value("SearchGeometryWidth").toUInt(); + unsigned int searchGeometryHeight = value("SearchGeometryHeight").toUInt(); + if(searchGeometryWidth == 0 || searchGeometryHeight == 0) + { + searchGeometryWidth = 500; + searchGeometryHeight = 380; + } + m_search->resize(searchGeometryWidth, searchGeometryHeight); + } + raiseWindow(m_search); + return false; +} + +bool CorePlugin::processExecMenuPhoneState(SIM::CommandDef* cmd) +{ + Contact *owner = getContacts()->owner(); + if ((unsigned long)owner->getPhoneStatus() != cmd->id - CmdPhoneNoShow){ + owner->setPhoneStatus(cmd->id - CmdPhoneNoShow); + EventContact(owner, EventContact::eChanged).process(); + } + return true; +} + +bool CorePlugin::processExecMenuPhoneLocation(SIM::CommandDef* cmd) +{ + Contact *owner = getContacts()->owner(); + unsigned n = cmd->id - CmdPhoneLocation; + QString res; + QString phones = owner->getPhones(); + while (!phones.isEmpty()){ + QString item = getToken(phones, ';', false); + QString v = getToken(item, '/', false); + QString number = getToken(v, ',', false); + QString type = getToken(v, ',', false); + QString icon = getToken(v, ',', false); + v = number + ',' + type + ',' + icon; + if (--n == 0) + v += ",1"; + if (!res.isEmpty()) + res += ';'; + res += v; + } + if (res != owner->getPhones()){ + owner->setPhones(res); + EventContact(owner, EventContact::eChanged).process(); + } + return true; +} + +bool CorePlugin::processExecCmdSetup(SIM::CommandDef* cmd) +{ + unsigned n = cmd->menu_id - CmdClient; + if (n >= getContacts()->nClients()) + return false; + Client *client = getContacts()->getClient(n); + if (m_cfg == NULL){ + m_cfg = new ConfigDlg::ConfigureDialog(); + connect(m_cfg, SIGNAL(finished()), this, SLOT(dialogFinished())); + } + static_cast(m_cfg)->raisePage(client); + raiseWindow(m_cfg); + return true; +} + +bool CorePlugin::processExecCmdPhoneBook(SIM::CommandDef* /*cmd*/) +{ + if (m_cfg == NULL){ + m_cfg = new ConfigDlg::ConfigureDialog; + connect(m_cfg, SIGNAL(finished()), this, SLOT(dialogFinished())); + } + static_cast(m_cfg)->raisePhoneBook(); + raiseWindow(m_cfg); + return true; +} + +bool CorePlugin::processExecCmdCommonStatus(SIM::CommandDef* cmd) +{ + unsigned n = cmd->menu_id - CmdClient; + if (n >= getContacts()->nClients()) + return false; + Client *client = getContacts()->getClient(n); + if (cmd->flags & COMMAND_CHECKED){ + client->setStatus(getManualStatus(), true); + }else{ + client->setStatus(client->getManualStatus(), false); + } + for (unsigned i = 0; i < getContacts()->nClients(); i++){ + if (getContacts()->getClient(i)->getCommonStatus()) + return true; + } + client = getContacts()->getClient(0); + if (client){ + client->setCommonStatus(true); + EventClientChanged(client).process(); + } + return true; +} + +bool CorePlugin::processStatusChange(int clientnum, SIM::CommandDef* cmd) +{ + Client *client = getContacts()->getClient(clientnum); + if (cmd->id == CmdInvisible){ + client->setInvisible(!client->getInvisible()); + return true; + } + const CommandDef *d; + const CommandDef *curStatus = NULL; + for (d = client->protocol()->statusList(); !d->text.isEmpty(); d++){ + if (d->id == cmd->id) + curStatus = d; + } + if (curStatus == NULL) + return false; + if ((((cmd->id != STATUS_ONLINE) && (cmd->id != STATUS_OFFLINE)) || + (client->protocol()->description()->flags & PROTOCOL_AR_OFFLINE))&& + (client->protocol()->description()->flags & (PROTOCOL_AR | PROTOCOL_AR_USER))){ + QString noShow = propertyHub()->stringMapValue("NoShowAutoReply", cmd->id); + if (noShow.isEmpty()){ + AutoReplyDialog dlg(cmd->id); + if (!dlg.exec()) + return true; + } + } + client->setStatus(cmd->id, false); + return true; +} + +bool CorePlugin::processEventCommandExec(SIM::Event* e) +{ + EventCommandExec *ece = static_cast(e); + CommandDef *cmd = ece->cmd(); + if (cmd->menu_id == MenuEncoding) { + return processExecMenuEncoding(cmd); + } + if (cmd->id == CmdEnableSpell) { + setValue("EnableSpell", cmd->flags & COMMAND_CHECKED); + return false; + } + if (cmd->menu_id == MenuMessage){ + return processExecMenuMessage(cmd); + } + if (cmd->menu_id == MenuMsgCommand){ + return processExecMenuMsgCommand(cmd); + } + if (cmd->id == CmdGrantAuth){ + return processExecCmdGrantAuth(cmd); + } + if (cmd->id == CmdRefuseAuth){ + return processExecCmdRefuseAuth(cmd); + } + + if (cmd->id == CmdSeparate){ + return processExecCmdSeparate(cmd); + } + if (cmd->id == CmdSendClose){ + setValue("CloseSend", (cmd->flags & COMMAND_CHECKED) != 0); + return true; + } + if (cmd->id == CmdSendSMS){ + return processExecCmdSendSMS(cmd); + } + if (cmd->id == CmdHistory){ + return processExecCmdHistory(cmd); + } + if (cmd->id == CmdConfigure){ + return processExecCmdConfigure(cmd); + } + if (cmd->id == CmdSearch){ + return processExecCmdSearch(cmd); + } + if ((cmd->menu_id == MenuContact) || (cmd->menu_id == MenuGroup)){ + if (cmd->id == CmdInfo){ + showInfo(cmd); + return true; + } + CommandDef *def = preferences.find(cmd->id); + if (def){ + showInfo(cmd); + return true; + } + } + if (cmd->menu_id == MenuPhoneState){ + return processExecMenuPhoneState(cmd); + } + if (cmd->menu_id == MenuPhoneLocation){ + return processExecMenuPhoneLocation(cmd); + } + if (cmd->id == CmdSetup){ + return processExecCmdSetup(cmd); + } + if (cmd->id == CmdPhoneBook){ + return processExecCmdPhoneBook(cmd); + } + if (cmd->id == CmdCommonStatus){ + return processExecCmdCommonStatus(cmd); + } + if (cmd->id == CmdProfileChange){ + QTimer::singleShot(0, this, SLOT(selectProfile())); + return true; + } + unsigned n = cmd->menu_id - CmdClient; + if (n < getContacts()->nClients()){ + return processStatusChange(n, cmd); + } + if ((cmd->id == CmdCM) || (cmd->id == CmdConnections)){ + if (m_manager == NULL){ + m_manager = new ConnectionManager(false); + connect(m_manager, SIGNAL(finished()), this, SLOT(managerFinished())); + } + raiseWindow(m_manager); + return true; + } + Message *msg = (Message*)(cmd->param); + if (cmd->id == CmdFileAccept){ + Contact *contact = getContacts()->contact(msg->contact()); + SIM::PropertyHubPtr data = contact->getUserData("_core"); + QString dir; + if(!data.isNull()) + dir = data->value("IncomingPath").toString(); + if (!dir.isEmpty() && (!dir.endsWith("/")) && (!dir.endsWith("\\"))) + dir += '/'; + dir = user_file(dir); + EventMessageAccept(msg, dir, Ask).process(); + } + if (cmd->id == CmdDeclineWithoutReason){ + EventMessageDecline(msg).process(); + } + if (cmd->id == CmdDeclineReasonBusy){ + QString reason = i18n("Sorry, I'm busy right now, and can not respond to your request"); + EventMessageDecline(msg, reason).process(); + } + if (cmd->id == CmdDeclineReasonLater){ + QString reason = i18n("Sorry, I'm busy right now, but I'll be able to respond to you later"); + EventMessageDecline(msg, reason).process(); + } + if(cmd->id == CmdDeclineReasonInput) + { + Message *msg = (Message*)(cmd->param); + QWidgetList list = QApplication::topLevelWidgets(); + DeclineDlg *dlg = NULL; + QWidget *w; + foreach(w,list) + { + if(w->inherits("DeclineDlg")) + { + dlg = static_cast(w); + if (dlg->message()->id() == msg->id()) + break; + dlg = NULL; + } + } + if (dlg == NULL) + dlg = new DeclineDlg(msg); + raiseWindow(dlg); + } + if((cmd->id >= CmdUnread) && (cmd->id < CmdUnread + unread.size())) + { + unsigned n = cmd->id - CmdUnread; + for (list::iterator it = unread.begin(); it != unread.end(); ++it){ + if (n-- == 0){ + Message *msg = History::load(it->id, it->client, it->contact); + if (msg){ + msg->setFlags(msg->getFlags() & ~MESSAGE_NORAISE); + EventOpenMessage(msg).process(); + delete msg; + break; + } + } + } + return true; + } + if ((cmd->menu_id > CmdContactResource) && (cmd->menu_id <= CmdContactResource + 0x100)){ + Contact *contact = getContacts()->contact((unsigned long)(cmd->param)); + CommandDef *def = messageTypes.find(cmd->id); + if (def && contact){ + unsigned nRes = cmd->menu_id - CmdContactResource - 1; + vector ways; + getWays(ways, contact); + for (unsigned n = 0; n < ways.size(); n++){ + QString resources = ways[n].client->resources(ways[n].data); + while (!resources.isEmpty()){ + QString res = getToken(resources, ';'); + if (nRes-- == 0){ + clientContact &cc = ways[n]; + clientData *data; + ClientDataIterator it(contact->clientData, cc.client); + while ((data = ++it) != NULL){ + if (data == cc.data) + break; + } + if (data == NULL){ + data = cc.data; + cc.client->createData(data, contact); + EventContact(contact, EventContact::eChanged).process(); + } + getToken(res, ','); + MessageDef *mdef = (MessageDef*)(def->param); + Message *msg = mdef->create(NULL); + msg->setContact((unsigned long)(cmd->param)); + msg->setClient(cc.client->dataName(data)); + msg->setResource(res); + EventOpenMessage(msg).process(); + delete msg; + return true; + } + } + } + } + return false; + } + if ((cmd->menu_id > CmdContactClients) && (cmd->menu_id <= CmdContactClients + 0x100)){ + Contact *contact = getContacts()->contact((unsigned long)(cmd->param)); + CommandDef *def = messageTypes.find(cmd->id); + if (def && contact){ + unsigned n = cmd->menu_id - CmdContactClients - 1; + vector ways; + getWays(ways, contact); + if (n < ways.size()){ + clientContact &cc = ways[n]; + + clientData *data; + ClientDataIterator it(contact->clientData, cc.client); + while ((data = ++it) != NULL){ + if (data == cc.data) + break; + } + if (data == NULL){ + data = cc.data; + cc.client->createData(data, contact); + EventContact(contact, EventContact::eChanged).process(); + } + + MessageDef *mdef = (MessageDef*)(def->param); + Message *msg = mdef->create(NULL); + msg->setContact((unsigned long)(cmd->param)); + msg->setClient(cc.client->dataName(data)); + EventOpenMessage(msg).process(); + delete msg; + return true; + } + } + } + if (cmd->id == CmdShowPanel) + { + setValue("ShowPanel", ((cmd->flags & COMMAND_CHECKED) != 0)); + //setShowPanel((cmd->flags & COMMAND_CHECKED) != 0); + showPanel(); + } + return false; +} + +bool CorePlugin::processEventGoURL(SIM::Event* e) +{ + EventGoURL *u = static_cast(e); + QString url = u->url(); + QString proto; + int n = url.indexOf(':'); + if (n < 0) + return false; + proto = url.left(n); + url = url.mid(n + 1 ); + if (proto == "sms"){ + while (url[0] == '/') + url = url.mid(1); + Contact *contact = getContacts()->contactByPhone(url); + if (contact){ + Command cmd; + cmd->id = MessageSMS; + cmd->menu_id = MenuMessage; + cmd->param = (void*)(contact->id()); + EventCommandExec(cmd).process(); + } + return true; + } + if (proto != "sim") + return false; + unsigned long contact_id = url.toULong(); + Contact *contact = getContacts()->contact(contact_id); + if (contact){ + Command cmd; + cmd->id = MessageGeneric; + cmd->menu_id = MenuMessage; + cmd->param = (void*)contact_id; + EventCommandExec(cmd).process(); + } + return false; +} + +bool CorePlugin::processEvent(Event *e) +{ + switch (e->type()) + { + case eEventIconChanged: + return processEventIconChanged(); + + case eEventJoinAlert: + return processEventJoinAlert(); + + case eEventGroup: + return processEventGroup(e); + + case eEventDeleteMessage: + return processEventDeleteMessage(e); + + case eEventRewriteMessage: + return processEventRewriteMessage(e); + + case eEventTmplHelp: + return processEventTmplHelp(e); + + case eEventTmplHelpList: + return processEventTmplHelpList(e); + + case eEventARRequest: + return processEventARRequest(e); + + case eEventSaveState: + return processEventSaveState(e); + + case eEventPluginChanged: + return processEventPluginChanged(e); + + case eEventInit: + return processEventInit(e); + + case eEventQuit: + destroy(); + m_cmds->clear(); + return false; + + case eEventHomeDir: + return processEventHomeDir(e); + + case eEventGetProfile: + return processEventGetProfile(e); + + case eEventAddPreferences: + return processEventAddPreferences(e); + + case eEventRemovePreferences: + return processEventRemovePreferences(e); + + case eEventClientsChanged: + case eEventClientChanged: + return processEventClientChanged(e); + + case eEventCreateMessageType: + return processEventCreateMessageType(e); + + case eEventRemoveMessageType: + return processEventRemoveMessageType(e); + + case eEventContact: + return processEventContact(e); + + case eEventMessageAcked: + return processEventMessageAcked(e); + + case eEventMessageDeleted: + return processEventMessageDeleted(e); + + case eEventMessageReceived: + return processEventMessageReceived(e); + + case eEventSent: + return processEventSent(e); + + case eEventDefaultAction: + return processEventDefaultAction(e); + + case eEventLoadMessage: + return processEventLoadMessage(e); + + case eEventOpenMessage: + return processEventOpenMessage(e); + + case eEventCheckCommandState: + return processEventCheckCommandState(e); + + case eEventUpdateCommandState: + { + EventUpdateCommandState *eucs = static_cast(e); + return updateMainToolbar(eucs->commandID()); + } + case eEventCommandExec: + return processEventCommandExec(e); + + case eEventGoURL: + return processEventGoURL(e); + default: + break; + } + return false; +} + +void CorePlugin::showInfo(CommandDef *cmd) +{ + UserConfig *cfg = NULL; + Contact *contact = NULL; + Group *group = NULL; + unsigned long id = (unsigned long)(cmd->param); + if (cmd->menu_id == MenuContact) + { + contact = getContacts()->contact(id); + if (contact == NULL) + return; + } + if (cmd->menu_id == MenuGroup){ + group = getContacts()->group(id); + if (group == NULL) + return; + } + if ((contact == NULL) && (group == NULL)) + return; + QWidgetList list = QApplication::topLevelWidgets(); + QWidget *w; + foreach(w,list) + { + if (w->inherits("UserConfig")) + { + cfg = static_cast(w); + if ((contact && (cfg->m_contact == contact)) || + (group && (cfg->m_group == group))) + break; + cfg = NULL; + } + } + if (cfg == NULL){ + cfg = new UserConfig(contact, group); + unsigned int cfgGeometryWidth = value("CfgGeometryWidth").toUInt(); + unsigned int cfgGeometryHeight = value("CfgGeometryHeight").toUInt(); + if(cfgGeometryWidth == 0 || cfgGeometryHeight == 0) + { + cfgGeometryWidth = 500; + cfgGeometryHeight = 380; + } + cfg->resize(cfgGeometryWidth, cfgGeometryHeight); + } + raiseWindow(cfg); + if (!cfg->raisePage(cmd->id)) + cfg->raiseDefaultPage(); +} + +void CorePlugin::dialogFinished() +{ + QTimer::singleShot(0, this, SLOT(dialogDestroy())); +} + +void CorePlugin::dialogDestroy() +{ + if (m_cfg && !m_cfg->isVisible()){ + delete m_cfg; + m_cfg = NULL; + } + if (m_search && !m_search->isVisible()){ + delete m_search; + m_search = NULL; + } +} + +QWidget *CorePlugin::createConfigWindow(QWidget *parent) +{ + return new InterfaceConfig(parent); +} + +void CorePlugin::hideWindows() +{ + QWidgetList list = QApplication::topLevelWidgets(); + QWidget * w; + foreach(w,list) + { + w->hide(); + } +} + +void CorePlugin::ignoreEvents(bool i) +{ + m_bIgnoreEvents = i; +} + +void CorePlugin::changeProfile(const QString& profilename) +{ + log(L_DEBUG, "CorePlugin::changeProfile()"); + destroy(); + getContacts()->clearClients(); + getContacts()->clear(); + setValue("StatusTime", (unsigned int)QDateTime::currentDateTime().toTime_t()); + ProfileManager::instance()->selectProfile(profilename); + removeTranslator(); + installTranslator(); + initData(); +} + +void CorePlugin::selectProfile() +{ + log(L_DEBUG, "CorePlugin::selectProfile()"); + EventSaveState e; + e.process(); + bool changed = init(false); + if (changed){ + EventInit e2; + e2.process(); + } +} + +bool CorePlugin::init(bool bInit) +{ + m_bInit = bInit; + bool bLoaded = false; + bool bRes = true; + bool bNew = false; + bool bCmdLineProfile = false; + QSettings settings; + + // FIXME: + /* + EventArg e1("-profile:", I18N_NOOP("Use specified profile")); + e1.process(); + QString cmd_line_profile = e1.value(); + if (!cmd_line_profile.isEmpty()){ + bCmdLineProfile = true; + setProfile(QString::null); + QString profileDir = user_file(cmd_line_profile); + QDir d(profileDir); + if (d.exists()) { + bCmdLineProfile = false; + setProfile(cmd_line_profile); + } + } + */ + + QStringList profiles = ProfileManager::instance()->enumProfiles(); + QString profile; + bool newProfile = false; + + if(settings.value("Profile").toString().isEmpty() && settings.value("NoShow", false).toBool()) + { + settings.setValue("NoShow", false); + } + + QString sNewProfileName; + + if((!bInit || + settings.value("Profile").toString().isEmpty() || + !settings.value("NoShow", false).toBool() || + !settings.value("SavePasswd", false).toBool())) + { + LoginDialog dlg(bInit, ClientPtr(), "", bInit ? QString() : settings.value("Profile").toString()); + if (dlg.exec() == 0) + { + return false; + } + newProfile = dlg.isNewProfile(); + sNewProfileName = dlg.newProfileName(); + profile = dlg.profile(); + if (dlg.isChanged()) + bRes = false; + bLoaded = true; + } + else if(bInit && !profile.isEmpty()) + { + log(L_DEBUG, "profile = %s", profile.toUtf8().data()); + ProfileManager::instance()->selectProfile(profile); + } + else if(settings.value("NoShow", false).toBool()) + { + profile = settings.value("Profile").toString(); + ProfileManager::instance()->selectProfile(profile); + changeProfile(profile); + //bLoaded = true; + } + if(newProfile) + { + hideWindows(); + getContacts()->clearClients(); + + QDir d(ProfileManager::instance()->rootPath()); + settings.setValue("Profile", sNewProfileName); + + NewProtocol *pDlg = NULL; + if (bCmdLineProfile) + { + settings.setValue("SavePasswd", true); + settings.setValue("NoShow", true); + pDlg = new NewProtocol(NULL,1,getRegNew()); + } else { + pDlg = new NewProtocol(NULL); + } + if (!pDlg->exec() && !pDlg->connected()){ + delete(pDlg); + if (d.exists(sNewProfileName)) + d.rmdir(sNewProfileName); + return false; + } + delete(pDlg); + + bLoaded = true; + bRes = false; + bNew = true; + } + + PropertyHubPtr hub = ProfileManager::instance()->getPropertyHub("_core"); + if(!hub.isNull()) + setPropertyHub(hub); + // Defaults: + if(!value("ShowPanel").isValid()) + setValue("ShowPanel", true); // Show status panel by default + if(!value("HistoryStyle").isValid()) + setValue("HistoryStyle", "SIM"); + if(value("HistoryPage").toUInt() == 0) + setValue("HistoryPage", 100); + historyXSL = new XSL(value("HistoryStyle").toString()); + EventPluginLoadConfig eplc; + eplc.process(); + if (!bLoaded) + { + SIM::ClientList clients; + connect(&clients, SIGNAL(ignoreEvents(bool)), this, SLOT(ignoreEvents(bool))); + loadClients(clients); + clients.addToContacts(); + } + if (!bNew) + { + getContacts()->load(); + } + for (unsigned i = 0; i < getContacts()->nClients(); i++) + { + Client *client = getContacts()->getClient(i); + // "Emulate" contactsLoaded() when we're dealing with a new contact list + if (bNew) + client->contactsLoaded(); + if (client->getCommonStatus()) + client->setManualStatus(getManualStatus()); + client->setStatus(client->getManualStatus(), client->getCommonStatus()); + } + if (getRegNew()&&!bCmdLineProfile){ + hideWindows(); + NewProtocol pDlg(NULL,1,true); + pDlg.exec(); + } + if (!m_main) + m_main = new MainWindow(/*data.geometry*/); + + loadUnread(); + + log(L_DEBUG, "geometry: %s", value("geometry").toByteArray().toHex().data()); + m_main->restoreGeometry(value("geometry").toByteArray()); + m_view = new UserView; + + EventLoginStart e; + e.process(); + + if (!bNew) + { + QString containers = value("Containers").toString(); + QVariantMap containerMap = value("Container").toMap(); + while (!containers.isEmpty()) + { + Container *c = new Container(0, containerMap.value(getToken(containers, ',')).toString().toUtf8().constData()); + c->init(); + } + } + //clearContainer(); + setValue("Containers", QString()); + setValue("Container", QVariantMap()); + + m_bInit = true; + loadMenu(); + if (!bRes) + { + EventSaveState eSave; + eSave.process(); + return true; + } + return bRes || bNew; +} + +void CorePlugin::destroy() +{ + QWidgetList l = QApplication::topLevelWidgets(); + QWidget *w; + list forRemove; + foreach(w,l) + { + if (w->inherits("Container") || + w->inherits("HistoryWindow") || + w->inherits("UserConfig")) + forRemove.push_back(w); + } + for(list::iterator itr = forRemove.begin(); itr != forRemove.end(); ++itr) + delete *itr; + + if (m_statusWnd) + { + delete m_statusWnd; + m_statusWnd = NULL; + } + if (m_view) + { + delete m_view; + m_view = NULL; + } + if (m_cfg) + { + delete m_cfg; + m_cfg = NULL; + } + if (m_main) + { + delete m_main; + m_main = NULL; + } + if (m_view) + { + delete m_view; + m_view = NULL; + } + if (m_search) + { + delete m_search; + m_search = NULL; + } + if (m_manager) +{ + delete m_manager; + m_manager = NULL; + } +} + +static char CLIENTS_CONF[] = "clients.conf"; + +void CorePlugin::loadDir() +{ + //QString saveProfile = getProfile(); + //setProfile(QString::null); + //bool bOK = false; + QString baseName = user_file(QString::null); + QDir dir(baseName); + dir.setFilter(QDir::Dirs); + QStringList list = dir.entryList(); + for (QStringList::Iterator it = list.begin(); it != list.end(); ++it) + { + QString entry = *it; + if (entry[0] == '.') + continue; + QString fname = QString(baseName).append("/").append(entry).append("/").append(CLIENTS_CONF); + QFile f(fname); + if (f.exists()){ + m_profiles.append(entry); + /* + if (entry == saveProfile) + bOK = true; + */ + } + } + /* + if (bOK) + setProfile(saveProfile); + */ +} + +void CorePlugin::prepareConfig() +{ + QString unread_str; + for(list::iterator itUnread = unread.begin(); itUnread != unread.end(); ++itUnread) + { + msg_id &m = (*itUnread); + if (!unread_str.isEmpty()) + unread_str += ';'; + unread_str += QString::number(m.contact); + unread_str += ','; + unread_str += QString::number(m.id); + unread_str += ','; + unread_str += m.client; + } + setValue("Unread", unread_str); + +// unsigned editBgColor = value("EditBackground").toUInt(); +// unsigned editFgColor = value("EditForeground").toUInt(); + + QPalette pal = QApplication::palette(); + if (((pal.color(QPalette::Base).rgb() & 0xFFFFFF) == value("EditBackground").toUInt()) && + ((pal.color(QPalette::Text).rgb() & 0xFFFFFF) == value("EditForeground").toUInt())) + { + setValue("EditBackground", 0xffffff); + setValue("EditForeground", 0xffffff); + } + + QString ef = FontEdit::font2str(editFont, false); + QString def_ef = FontEdit::font2str(QApplication::font(), false); + setValue("EditFont", ef); + if ((ef == def_ef) || !value("EditSaveFont").toBool()) + setValue("EditFont", QString()); + + //clearContainer(); + QString containers; + + QWidgetList list = QApplication::topLevelWidgets(); + QWidget* w; + QVariantMap containerMap; + foreach(w,list) + { + if (w->inherits("Container")) + { + Container *c = static_cast(w); + if (c->isReceived()) + continue; + if (!containers.isEmpty()) + containers += ','; + containers += QString::number(c->getId()); + containerMap.insert(QString::number(c->getId()), c->getState()); + } + } + setValue("Containers", containers); + if (m_main) + { + log(L_DEBUG, "Saving geometry"); + setValue("geometry", m_main->saveGeometry()); + setValue("toolbar_state", m_main->saveState()); + } + +} + +static char BACKUP_SUFFIX[] = "~"; +QByteArray CorePlugin::getConfig() +{ + QString unread_str; + for(list::iterator itUnread = unread.begin(); itUnread != unread.end(); ++itUnread) + { + msg_id &m = (*itUnread); + if (!unread_str.isEmpty()) + unread_str += ';'; + unread_str += QString::number(m.contact); + unread_str += ','; + unread_str += QString::number(m.id); + unread_str += ','; + unread_str += m.client; + } + setValue("Unread", unread_str); + + unsigned editBgColor = value("EditBackground").toUInt(); + unsigned editFgColor = value("EditForeground").toUInt(); + + QPalette pal = QApplication::palette(); + if (((pal.color(QPalette::Base).rgb() & 0xFFFFFF) == value("EditBackground").toUInt()) && + ((pal.color(QPalette::Text).rgb() & 0xFFFFFF) == value("EditForeground").toUInt())) + { + setValue("EditBackground", 0); + setValue("EditForeground", 0); + } + + QString ef = FontEdit::font2str(editFont, false); + QString def_ef = FontEdit::font2str(QApplication::font(), false); + setValue("EditFont", ef); + if ((ef == def_ef) || !value("EditSaveFont").toBool()) + setValue("EditFont", QString()); + + //clearContainer(); + QString containers; + + QWidgetList list = QApplication::topLevelWidgets(); + QWidget* w; + QVariantMap containerMap;// = value("Container").toMap(); + foreach(w,list) + { + if (w->inherits("Container")) + { + Container *c = static_cast(w); + if (c->isReceived()) + continue; + if (!containers.isEmpty()) + containers += ','; + containers += QString::number(c->getId()); + containerMap.insert(QString::number(c->getId()), c->getState()); + } + } + setValue("Containers", containers); + if (m_main) + { + log(L_DEBUG, "Saving geometry"); + setValue("geometry", m_main->saveGeometry()); + setValue("toolbar_state", m_main->saveState()); + /* + if (m_main->m_bar) + { + // Should update main toolbar pos only when toolbar is really exist... + saveToolbar(m_main->m_bar, data.toolBarState); + } + */ + } + + // We should save profile and noshow values in profile-independent _core config, and + // all other values in profile-dependent config. + // FIXME: This is a nasty hack, profile management should be rewritten + + //Saving profile-independent config: + static DataDef generalCoreDataDef[] = + { + { "Profile", DATA_STRING, 1, 0 }, + { NULL, DATA_UNKNOWN, 0, 0 } + }; + struct TGeneralCoreData + { + SIM::Data Profile; + } GeneralCoreData; + + + QString saveProfile = ProfileManager::instance()->currentProfileName(); + //setProfile(QString::null); + + load_data(generalCoreDataDef, &GeneralCoreData, NULL); // This will just init data + GeneralCoreData.Profile.str() = saveProfile; + //GeneralCoreData.NoShow.asBool() = getNoShow(); + + QByteArray cfg = save_data(generalCoreDataDef, &GeneralCoreData); + + QString cfgName = user_file("plugins.conf"); + QFile fCFG(QString(cfgName).append(BACKUP_SUFFIX)); // use backup file for this ... + if(!fCFG.open(QIODevice::WriteOnly | QIODevice::Truncate)) + { + log(L_ERROR, "Can't create %s", qPrintable(cfgName)); + } + else + { + QByteArray write = "[_core]\n"; + write += "enable,"; + write += QByteArray::number(m_base); + write += '\n'; + write += cfg; + fCFG.write(write); + + fCFG.flush(); // Make sure that file is fully written and we will not get "Disk Full" error on fCFG.close + const QFile::FileError status = fCFG.error(); + const QString errorMessage = fCFG.errorString(); + fCFG.close(); + if (status != QFile::NoError) { + log(L_ERROR, "IO error writing to file %s : %s", qPrintable(fCFG.fileName()), qPrintable(errorMessage)); + } + else + { + // rename to normal file + QFileInfo fileInfo(fCFG.fileName()); + QString desiredFileName = fileInfo.fileName(); + desiredFileName = desiredFileName.left(desiredFileName.length() - strlen(BACKUP_SUFFIX)); +//#if defined( WIN32 ) || defined( __OS2__ ) + fileInfo.dir().remove(desiredFileName); +//#endif + if (!fileInfo.dir().rename(fileInfo.fileName(), desiredFileName)) + { + log(L_ERROR, "Can't rename file %s to %s (%s)", (const char*)fileInfo.fileName().toUtf8().data(), (const char*)desiredFileName.toUtf8().data(), fileInfo.dir().path().toUtf8().data()); + } + } + } + + // Saving profile-dependent config: + //setProfile(saveProfile); + cfgName = user_file(CLIENTS_CONF); + QFile f(QString(cfgName).append(BACKUP_SUFFIX)); // use backup file for this ... + if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)){ + log(L_ERROR, "Can't create %s", qPrintable(cfgName)); + }else{ + for (unsigned i = 0; i < getContacts()->nClients(); i++){ + Client *client = getContacts()->getClient(i); + Protocol *protocol = client->protocol(); + QByteArray line = "["; + line += QFile::encodeName(protocol->plugin()->name()).data(); + line += '/'; + line += protocol->description()->text.toUtf8(); + line += "]\n"; + f.write(line); + line = client->getConfig(); + if (line.length()){ + line += '\n'; + f.write(line); + } + } + f.flush(); // Make shure that file is fully written and we will not get "Disk Full" error on f.close + const QFile::FileError status = f.error(); + const QString errorMessage = f.errorString(); + f.close(); + if (status != QFile::NoError) { + log(L_ERROR, "IO error writing to file %s : %s", qPrintable(f.fileName()), qPrintable(errorMessage)); + } else { + // rename to normal file + QFileInfo fileInfo(f.fileName()); + QString desiredFileName = fileInfo.fileName(); + desiredFileName = desiredFileName.left(desiredFileName.length() - strlen(BACKUP_SUFFIX)); +//#if defined( WIN32 ) || defined( __OS2__ ) + fileInfo.dir().remove(desiredFileName); +//#endif + if (!fileInfo.dir().rename(fileInfo.fileName(), desiredFileName)) + { + log(L_ERROR, "Can't rename file %s to %s (%s)", (const char*)fileInfo.fileName().toUtf8().data(), (const char*)desiredFileName.toUtf8().data(), fileInfo.dir().path().toUtf8().data()); + } + } + } + +#ifndef WIN32 + QString dir = user_file(""); + chmod(QFile::encodeName(dir),S_IRUSR | S_IWUSR | S_IXUSR); +#endif + setValue("EditBackground", editBgColor); + setValue("EditForeground", editFgColor); + return QByteArray(); +} + +void CorePlugin::loadUnread() +{ + unread.clear(); + QString unread_str = value("Unread").toString(); + while (!unread_str.isEmpty()){ + QString item = getToken(unread_str, ';'); + unsigned long contact = getToken(item, ',').toULong(); + unsigned long id = getToken(item, ',').toULong(); + Message *msg = History::load(id, item, contact); + if (msg == NULL) + continue; + msg_id m; + m.id = id; + m.contact = contact; + m.client = item; + m.type = msg->baseType(); + unread.push_back(m); + } + setValue("Unread", QString()); +} + +void CorePlugin::clearUnread(unsigned contact_id) +{ + for (list::iterator it = unread.begin(); it != unread.end();) + { + if (it->contact != contact_id) + { + ++it; + continue; + } + unread.erase(it); + it = unread.begin(); + } +} + +Message *CorePlugin::createMessage(const char *type, Buffer *cfg) +{ + MAP_TYPES::iterator itt = types.find(type); + if (itt == types.end()) + return new Message(MessageGeneric, cfg); + + CommandDef *def = messageTypes.find(itt->second); + if (!def) + return new Message(MessageGeneric, cfg); + + MessageDef *mdef = (MessageDef*)(def->param); + if (!mdef->create) + return new Message(MessageGeneric, cfg); + + Message *msg = (mdef->create)(cfg); + if (msg) + return msg; + return new Message(MessageGeneric, cfg); +} + +void CorePlugin::loadClients(const QString& profilename, SIM::ClientList& clients) +{ + QString cfgName = ProfileManager::instance()->rootPath() + QDir::separator() + profilename + QDir::separator() + "clients.conf"; + QFile f(cfgName); + if (!f.open(QIODevice::ReadOnly)) + { + log(L_ERROR, "[1]Can't open %s", qPrintable(cfgName)); + return; + } + Buffer cfg = f.readAll(); + for (;;) + { + QByteArray section = cfg.getSection(); + if (section.isEmpty()) + break; + QString s = section; // ? + ClientPtr client = loadClient(s, &cfg); + if (client) + clients.push_back(client); + } +} + +void CorePlugin::loadClients(SIM::ClientList &clients) +{ + loadClients(ProfileManager::instance()->currentProfileName(), clients); +} + +ClientPtr CorePlugin::loadClient(const QString &name, Buffer *cfg) +{ + if (name.isEmpty()) + return ClientPtr(); + QString clientName = name; + QString pluginName = getToken(clientName, '/'); + if (pluginName.isEmpty() || clientName.length() == 0) + return ClientPtr(); + if(!getPluginManager()->isPluginProtocol(pluginName)) + { + log(L_DEBUG, "Plugin %s is not a protocol plugin", qPrintable(pluginName)); + return ClientPtr(); + } + PluginPtr plugin = getPluginManager()->plugin(pluginName); + if(plugin.isNull()) + { + log(L_WARN, "Plugin %s not found", qPrintable(pluginName)); + return ClientPtr(); + } + ProfileManager::instance()->currentProfile()->enablePlugin(pluginName); + ProtocolPtr protocol; + ProtocolIterator it; + while ((protocol = ++it) != NULL) + if (protocol->description()->text == clientName) + return protocol->createClient(cfg); + log(L_DEBUG, "Protocol %s not found", qPrintable(clientName)); + return ClientPtr(); +} + +bool CorePlugin::adjustClientItem(unsigned id, CommandDef *cmd) +{ + unsigned n = id - CmdClient; + if (n >= getContacts()->nClients()) + return false; + Client *client = getContacts()->getClient(n); + Protocol *protocol = client->protocol(); + const CommandDef *descr = protocol->description(); + cmd->icon = descr->icon; + cmd->text_wrk = clientName(client); + return true; +} + +void CorePlugin::managerFinished() +{ + QTimer::singleShot(0, this, SLOT(destroyManager())); +} + +void CorePlugin::destroyManager() +{ + if (m_manager){ + delete m_manager; + m_manager = NULL; + } +} + +QString CorePlugin::typeName(const QString &name) +{ + QString text = name; + + text.remove('&'); + if (!text.length()) + log(L_DEBUG,"defText is empty!"); + return text; +} + +void CorePlugin::postInit() +{ + m_main->restoreGeometry(value("geometry").toByteArray()); + m_main->restoreState(value("toolbar_state").toByteArray()); +} + +void CorePlugin::loadMenu() +{ + EventMenu(MenuConnections, EventMenu::eRemove).process(); + + unsigned nClients = getContacts()->nClients(); + + EventMenu(MenuConnections, EventMenu::eAdd).process(); + + Command cmd; + cmd->id = CmdCM; + cmd->text = I18N_NOOP("Connection manager"); + cmd->menu_id = MenuConnections; + cmd->menu_grp = 0x8000; + + EventCommandCreate(cmd).process(); + + cmd->id = CmdShowPanel; + cmd->text = I18N_NOOP("Show status panel"); + cmd->menu_grp = 0x8001; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + if (nClients >= 2) + { + cmd->id = CmdConnections; + cmd->text = I18N_NOOP("Connections"); + cmd->menu_id = MenuMain; + cmd->menu_grp = 0x8040; + cmd->popup_id = MenuConnections; + cmd->flags = COMMAND_DEFAULT; + } + else + { + cmd->id = CmdConnections; + cmd->text = I18N_NOOP("Connection manager"); + cmd->menu_grp = 0x8040; + cmd->menu_id = MenuMain; + cmd->flags = COMMAND_DEFAULT; + } + EventCommandCreate(cmd).process(); + + if (m_status == NULL) + m_status = new CommonStatus; + + for (unsigned i = 0; i < m_nClients; i++) + EventMenu(CmdClient + i, EventMenu::eRemove).process(); + + for (m_nClients = 0; m_nClients < getContacts()->nClients(); m_nClients++){ + unsigned long menu_id = CmdClient + m_nClients; + EventMenu(menu_id, EventMenu::eAdd).process(); + Client *client = getContacts()->getClient(m_nClients); + Protocol *protocol = client->protocol(); // FIXME there is no protocol, nirvana pointer :( + + CommandDef *cmd = const_cast(protocol->statusList()); + if (cmd){ + Command c; + c->id = CmdTitle; + c->text = "_"; + c->menu_id = menu_id; + c->menu_grp = 0x0001; + c->flags = COMMAND_CHECK_STATE | COMMAND_TITLE; + EventCommandCreate(c).process(); + c->id = CmdCommonStatus; + c->text = I18N_NOOP("Common status"); + c->menu_id = menu_id; + c->menu_grp = 0x3000; + c->flags = COMMAND_CHECK_STATE; + EventCommandCreate(c).process(); + c->id = CmdSetup; + c->text = I18N_NOOP("Configure client"); + c->icon = "configure"; + c->menu_id = menu_id; + c->menu_grp = 0x3001; + c->flags = COMMAND_DEFAULT; + EventCommandCreate(c).process(); + c->id = menu_id; + c->text = "_"; + c->icon = QString::null; + c->menu_id = MenuConnections; + c->menu_grp = 0x1000 + menu_id; + c->popup_id = menu_id; + c->flags = COMMAND_CHECK_STATE; + EventCommandCreate(c).process(); + unsigned id = 0x100; + // for (; cmd->id; cmd++){ + for (; !cmd->text.isEmpty(); cmd++){ + c = *cmd; + c->menu_id = menu_id; + c->menu_grp = id++; + c->flags = COMMAND_CHECK_STATE; + EventCommandCreate(c).process(); + } + if (protocol->description()->flags & PROTOCOL_INVISIBLE){ + c->id = CmdInvisible; + c->text = I18N_NOOP("&Invisible"); + c->icon = protocol->description()->icon_on; + c->menu_grp = 0x1000; + c->flags = COMMAND_CHECK_STATE; + EventCommandCreate(c).process(); + } + } + } + showPanel(); +} + +void CorePlugin::showPanel() +{ + if (m_main == NULL) + return; + bool bShow = value("ShowPanel").toBool(); + if (bShow){ + if (getContacts()->nClients() < 2) + bShow = false; + } + if (bShow){ + if (m_statusWnd == NULL) + m_statusWnd = new StatusWnd; + m_statusWnd->show(); + return; + } + if (m_statusWnd){ + delete m_statusWnd; + m_statusWnd = NULL; + } +} + + +unsigned CorePlugin::getContainerMode() +{ + return value("ContainerMode").toUInt(); //data.ContainerMode.toULong(); +} + +void CorePlugin::setContainerMode(unsigned value) +{ + setValue("ContainerMode", value); + emit modeChanged(value); +} + +QString CorePlugin::clientName(Client *client) +{ + QString s = client->name(); + QString res = i18n(getToken(s, '.')); + res += ' '; + return res + s; +} + +void CorePlugin::checkHistory() +{ + Contact *contact; + ContactList::ContactIterator it; + while ((contact = ++it) != NULL) + { + SIM::PropertyHubPtr data = contact->getUserData("history"); + if (data.isNull() || !data->value("CutDays").toBool()) + continue; + QDateTime now(QDateTime::currentDateTime()); + now = now.addSecs(-data->value("Days").toUInt() * 24 * 60 * 60); + History::cut(NULL, contact->id(), now.toTime_t()); + } + QTimer::singleShot(24 * 60 * 60 * 1000, this, SLOT(checkHistory())); +} + +void CorePlugin::setManualStatus(unsigned long status) +{ + if (status == getManualStatus()) + return; + setValue("StatusTime", (unsigned int)QDateTime::currentDateTime().toTime_t()); + //data.ManualStatus.asULong() = status; + setValue("ManualStatus", (uint)status); +} + +void CorePlugin::alertFinished() +{ + if (m_alert) + setValue("NoJoinAlert", m_alert->isChecked()); + m_alert = NULL; +} + +void CorePlugin::focusDestroyed() +{ + m_focus = NULL; +} + +bool CorePlugin::lockProfile(const QString &profile, bool bSend) +{ + if (profile.isEmpty()) + { + if (!m_lock) + return true; + + delete m_lock; + m_lock = NULL; + return true; + } + FileLock *lock = new FileLock(user_file(".lock")); + if (!lock->lock(bSend)) + { + delete lock; + return false; + } + if (m_lock) + delete m_lock; + m_lock = lock; + return true; +} + +void CorePlugin::showMain() +{ + if (m_main) + { + m_main->show(); + raiseWindow(m_main); + } +} + +#ifdef WIN32 + +LockThread::LockThread(Qt::HANDLE _hEvent) +{ + hEvent = _hEvent; +} + +void LockThread::run() +{ + for (;;) + { + DWORD res = WaitForSingleObject(hEvent, INFINITE); + if (res == WAIT_ABANDONED) + break; + QTimer::singleShot(0, CorePlugin::instance(), SLOT(showMain())); + } +} + +// From zlib +// Copyright (C) 1995-2002 Mark Adler + +#define BASE 65521L +#define NMAX 5552 + +#define DO1(buf,i) {s1 += buf[i]; s2 += s1;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +unsigned adler32(const char *buf, unsigned len) +{ + unsigned long s1 = 0; + unsigned long s2 = 0; + int k; + while (len > 0) { + k = len < NMAX ? len : NMAX; + len -= k; + while (k >= 16) { + DO16(buf); + buf += 16; + k -= 16; + } + if (k != 0) do { + s1 += *buf++; + s2 += s1; + } while (--k); + s1 %= BASE; + s2 %= BASE; + } + return (s2 << 16) | s1; +} + +#endif + + FileLock::FileLock(const QString &name) +: QFile(name) +{ +#ifdef WIN32 + m_thread = NULL; +#else + m_bLock = false; +#endif +} + +FileLock::~FileLock() +{ +#ifdef WIN32 + if (m_thread) + { + CloseHandle(m_thread->hEvent); + m_thread->wait(1000); + m_thread->terminate(); + delete m_thread; + } +#else + close(); + if (m_bLock) + QFile::remove(fileName()); +#endif +} + +#ifdef WIN32 +bool FileLock::lock(bool bSend) +{ + QString event = "SIM."; + const QByteArray s = fileName().toLocal8Bit(); + event += QString::number(adler32(s.data(), s.length())); + Qt::HANDLE hEvent = OpenEventA(EVENT_MODIFY_STATE, FALSE, event.toLatin1()); + if (hEvent) + { + if (bSend) + SetEvent(hEvent); + CloseHandle(hEvent); + return false; + } + hEvent = CreateEventA(NULL, false, false, event.toLatin1()); + if (hEvent == NULL) + return false; + m_thread = new LockThread(hEvent); + m_thread->start(); +#else + bool FileLock::lock(bool) + { + if (!open(QIODevice::ReadWrite | QIODevice::Truncate)) + { + log(L_WARN, "Can't create %s", qPrintable(fileName())); + return false; + } + struct flock fl; + fl.l_type = F_WRLCK; + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 1; + if (fcntl(handle(), F_SETLK, &fl) == -1) + //QFile::remove(name()); + return false; + m_bLock = true; +#endif + return true; + } + +void HistoryThread::run() +{ + QString str = user_file(".history_file"); + History::save(m_id, str); + QProcess *m_ex; + m_ex = new QProcess(); + m_ex->start(m_Viewer, QStringList(str)); +} + +CorePlugin* CorePlugin::instance() +{ + return g_plugin; +} + +unsigned long CorePlugin::getManualStatus() +{ + return value("ManualStatus").toUInt(); +} + +// vim: set expandtab: + diff --git a/plugins/_core/core.h b/plugins/_core/core.h new file mode 100644 index 0000000..7f00514 --- /dev/null +++ b/plugins/_core/core.h @@ -0,0 +1,345 @@ +/*************************************************************************** + core.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _CORE_H +#define _CORE_H + +#include +#include +#include + +#include +#include +#include +#include + +#include "cmddef.h" +#include "event.h" +#include "misc.h" +#include "plugins.h" +#include "propertyhub.h" +#include "core_consts.h" +#include "clientlist.h" +#include "simapi.h" + +using namespace std; + +typedef map MAP_TYPES; + +struct msg_id +{ + unsigned id; + unsigned contact; + unsigned type; + QString client; +}; + +class FileLock; +class QWidget; +class QTranslator; +class QMimeSource; +class Commands; +class MainWindow; +class UserView; +class SearchDialog; +class CommonStatus; +class StatusWnd; +class ConnectionManager; + +const unsigned CONTAINER_SIMPLE = 0; +const unsigned CONTAINER_NEW = 1; +const unsigned CONTAINER_GROUP = 2; +const unsigned CONTAINER_ALL = 3; + +const unsigned CONTAINER_GRP = 0x80000000; + +const unsigned char SORT_NONE = 0; +const unsigned char SORT_STATUS = 1; +const unsigned char SORT_ACTIVE = 2; +const unsigned char SORT_NAME = 3; + +const unsigned NEW_MSG_NOOPEN = 0; +const unsigned NEW_MSG_MINIMIZE = 1; +const unsigned NEW_MSG_RAISE = 2; + +#include "core_events.h" + +const unsigned MESSAGE_DEFAULT = 0x0000; +const unsigned MESSAGE_SILENT = 0x0001; +const unsigned MESSAGE_HIDDEN = 0x0002; +const unsigned MESSAGE_SENDONLY = 0x0004; +const unsigned MESSAGE_INFO = 0x0008; +const unsigned MESSAGE_SYSTEM = 0x0010; +const unsigned MESSAGE_ERROR = 0x0020; +const unsigned MESSAGE_CHILD = 0x0040; + +const unsigned MIN_INPUT_BAR_ID = 0x1010; +const unsigned MAX_INPUT_BAR_ID = 0x1500; + +const unsigned STYLE_UNDER = 1; +const unsigned STYLE_ITALIC = 2; +const unsigned STYLE_STRIKE = 4; + +class MsgEdit; + +struct MessageDef +{ + const SIM::CommandDef *cmdReceived; + const SIM::CommandDef *cmdSent; + unsigned flags; + const char *singular; + const char *plural; + SIM::Message* (*create)(Buffer *cfg); + QObject* (*generate)(MsgEdit *edit, SIM::Message *msg); + SIM::Message* (*drag)(QMimeSource*); +}; + +struct clientContact +{ + SIM::clientData *data; + SIM::Client *client; + bool bNew; +}; + + +class Tmpl; +class XSL; +class BalloonMsg; + +class HistoryThread : public QThread +{ +public: + virtual void run(); + void set_id(unsigned id) {m_id=id;} + void set_Viewer(const QString &Viewer) {m_Viewer=Viewer;} +protected: + unsigned m_id; + QString m_Viewer; +}; + +// Lets do this later whole in one, because at the moment it only breaks linking of all other plugins... +#ifndef CORE_EXPORT +# ifdef CORE_EXPORTS +# define CORE_EXPORT Q_DECL_EXPORT +# else // CORE_EXPORTS +# define CORE_EXPORT Q_DECL_IMPORT +# endif // CORE_EXPORTS +#endif // CORE_EXPORT + +class CORE_EXPORT CorePlugin : public QObject, public SIM::Plugin, public SIM::EventReceiver +{ + Q_OBJECT +public: + CorePlugin(unsigned, Buffer*); + virtual ~CorePlugin(); + void setManualStatus(unsigned long status); + unsigned long getManualStatus(); + unsigned getContainerMode(); + void setContainerMode(unsigned); + void setRegNew(bool p_new) {m_RegNew=p_new;} + bool getRegNew() const {return m_RegNew;} + MainWindow *getMainWindow() { return m_main; }; + + SIM::CommandsMap preferences; + SIM::CommandsMap messageTypes; + MAP_TYPES types; + + list unread; + + QFont editFont; + SIM::Message *createMessage(const char *type, Buffer *cfg); + QString clientName(SIM::Client *client); + + XSL *historyXSL; + static CorePlugin* instance(); + + void setPropertyHub(SIM::PropertyHubPtr hub); + SIM::PropertyHubPtr propertyHub(); + QVariant value(const QString& key); + void setValue(const QString& key, const QVariant& v); + + void changeClientStatus(SIM::Client* client, const SIM::IMStatusPtr& status); + +signals: + void modeChanged(int); +protected slots: + void dialogFinished(); + void dialogDestroy(); + void managerFinished(); + void destroyManager(); + void selectProfile(); + void checkHistory(); + void alertFinished(); + void focusDestroyed(); + void showMain(); + void postInit(); + void ignoreEvents(bool i); +protected: + + virtual bool processEvent(SIM::Event*); + virtual QByteArray getConfig(); + virtual QWidget *createConfigWindow(QWidget *parent); + void createEventCmds(); + void showInfo(SIM::CommandDef *cmd); + bool init(bool bFirst); + void destroy(); + void loadDir(); + void loadClients(SIM::ClientList&); + void loadClients(const QString& profilename, SIM::ClientList&); + void loadMenu(); + QString tsFile(const QString &lang); + SIM::ClientPtr loadClient(const QString &name, Buffer *cfg); + bool adjustClientItem(unsigned id, SIM::CommandDef *cmd); + void showPanel(); + void hideWindows(); + void changeProfile(const QString& profilename); + void installTranslator(); + void removeTranslator(); + void initData(); + void loadUnread(); + void clearUnread(unsigned contact_id); + SIM::Client* getClient(unsigned i); + void getWays(vector &ways, SIM::Contact *contact); + QString typeName(const QString &name); + void setAutoReplies(); + bool lockProfile(const QString &profile, bool bSend = false); + + void createMainToolbar(); + bool updateMainToolbar(unsigned long commandID); + void createHistoryToolbar(); + void createContainerToolbar(); + void createMsgEditToolbar(); + void createTextEditToolbar(); + void createMenuMsgView(); // in msgview_menu.cpp + void createMenuTextEdit(); // in textedit_menu.cpp + + void prepareConfig(); + + bool m_bInit; + QStringList m_profiles; + QWidget *m_cfg; + QWidget *m_focus; + UserView *m_view; + SearchDialog *m_search; + QTranslator *m_translator; + ConnectionManager *m_manager; + CommonStatus *m_status; + StatusWnd *m_statusWnd; + unsigned m_nClients; + unsigned m_nClientsMenu; + unsigned m_nResourceMenu; + MainWindow *m_main; + BalloonMsg *m_alert; + FileLock *m_lock; + bool m_RegNew; + Tmpl *m_tmpl; + Commands *m_cmds; + HistoryThread *m_HistoryThread; + +private: + bool m_bIgnoreEvents; + SIM::PropertyHubPtr m_propertyHub; + + // Event handlers: + bool processEventIconChanged(); + bool processEventJoinAlert(); + bool processEventGroup(SIM::Event* e); + bool processEventDeleteMessage(SIM::Event* e); + bool processEventRewriteMessage(SIM::Event* e); + bool processEventTmplHelp(SIM::Event* e); + bool processEventTmplHelpList(SIM::Event* e); + bool processEventARRequest(SIM::Event* e); + bool processEventSaveState(SIM::Event* e); + bool processEventPluginChanged(SIM::Event* e); + bool processEventInit(SIM::Event* e); + bool processEventHomeDir(SIM::Event* e); + bool processEventGetProfile(SIM::Event* e); + bool processEventAddPreferences(SIM::Event* e); + bool processEventRemovePreferences(SIM::Event* e); + bool processEventClientChanged(SIM::Event* e); + bool processEventCreateMessageType(SIM::Event* e); + bool processEventRemoveMessageType(SIM::Event* e); + bool processEventContact(SIM::Event* e); + bool processEventMessageAcked(SIM::Event* e); + bool processEventMessageDeleted(SIM::Event* e); + bool processEventMessageReceived(SIM::Event* e); + bool processEventSent(SIM::Event* e); + bool processEventDefaultAction(SIM::Event* e); + bool processEventLoadMessage(SIM::Event* e); + bool processEventOpenMessage(SIM::Event* e); + bool processEventCheckCommandState(SIM::Event* e); + bool processEventCommandExec(SIM::Event* e); + bool processEventGoURL(SIM::Event* e); + + bool processCheckCmdChangeEncoding(SIM::CommandDef* cmd); + bool processCheckCmdAllEncodings(SIM::CommandDef* cmd); + bool processCheckCmdEnableSpell(SIM::CommandDef* cmd); + bool processCheckCmdSendClose(SIM::CommandDef* cmd); + bool processCheckCmdContactClients(SIM::CommandDef* cmd); + bool processCheckMenuContainer(SIM::CommandDef* cmd); + bool processCheckMenuMessage(SIM::CommandDef* cmd); + bool processCheckMenuMsgCommand(SIM::CommandDef* cmd); + bool processCheckCmdPhoneLocation(SIM::CommandDef* cmd); + bool processCheckCmdUnread(SIM::CommandDef* cmd); + bool processCheckCmdSendSMS(SIM::CommandDef* cmd); + bool processCheckCmdShowPanel(SIM::CommandDef* cmd); + bool processCheckCmdCommonStatus(SIM::CommandDef* cmd); + + bool processExecMenuEncoding(SIM::CommandDef* cmd); + bool processExecMenuMessage(SIM::CommandDef* cmd); + bool processExecMenuMsgCommand(SIM::CommandDef* cmd); + bool processExecCmdGrantAuth(SIM::CommandDef* cmd); + bool processExecCmdRefuseAuth(SIM::CommandDef* cmd); + bool processExecCmdSeparate(SIM::CommandDef* cmd); + bool processExecCmdSendSMS(SIM::CommandDef* cmd); + bool processExecCmdHistory(SIM::CommandDef* cmd); + bool processExecCmdConfigure(SIM::CommandDef* cmd); + bool processExecCmdSearch(SIM::CommandDef* cmd); + bool processExecMenuPhoneState(SIM::CommandDef* cmd); + bool processExecMenuPhoneLocation(SIM::CommandDef* cmd); + bool processExecCmdSetup(SIM::CommandDef* cmd); + bool processExecCmdPhoneBook(SIM::CommandDef* cmd); + bool processExecCmdCommonStatus(SIM::CommandDef* cmd); + + bool processStatusChange(int clientnum, SIM::CommandDef* cmd); + + void createCommand(int id, const QString& text, const QString& icon, int menu_id, + int menu_grp, int bar_id, int bar_grp, int flags, const QString& accel); + + friend class MainWindow; + friend class UserView; + friend class UserConfig; + friend class SearchDialog; + friend class LangConfig; + friend class CommonStatus; + friend class LoginDialog; + friend class StatusWnd; + friend class InterfaceConfig; + friend class ConnectionManager; + friend class Container; + friend class UserWnd; + friend class MsgEdit; + friend class HistoryWindow; + friend class Tmpl; +}; + +#define GET_CorePlugin() ( static_cast(SIM::getPluginManager()->plugin("_core").data()) ) + +#endif + +// vim: set expandtab: + diff --git a/plugins/_core/core.rc b/plugins/_core/core.rc new file mode 100644 index 0000000..a687f4c --- /dev/null +++ b/plugins/_core/core.rc @@ -0,0 +1,97 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,9,6,0 + PRODUCTVERSION 0,9,6,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Vladimir Shutoff\0" + VALUE "FileDescription", "Core plugin\0" + VALUE "FileVersion", "0, 9, 6, 0\0" + VALUE "InternalName", "_core\0" + VALUE "LegalCopyright", "Copyright © 2002-2003\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "_core.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "SIM\0" + VALUE "ProductVersion", "0, 9, 6, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/_core/core_consts.h b/plugins/_core/core_consts.h new file mode 100644 index 0000000..f98b40c --- /dev/null +++ b/plugins/_core/core_consts.h @@ -0,0 +1,198 @@ +/*************************************************************************** + core_consts.h + + This file defines constants for Command IDs, Menu IDs and ToolBar + IDs. + + Command ID (const named CmdXXXXX) is an unic int number which is + associated with certain command. In most cases commands are + associtated with menu(or toolbar) items, so one may say that CmdXXXXXX + is an unique id of menu(or toolbar) item. + + Menu ID (const named MenuXXXXX) is a unique number which is + associated with each menu(main menu, context menu, etc... any menu in + Sim-IM has it's own Menu ID). It is used for creating and showing + certain menu, and, as well, to specify pull down menu for certain menu + item. + + ToolBar ID (const namedToolBarXXXXXX) - an unique number that + identifies certain toolbar. + + ------------------- + begin : Tue Nov 30 2008 + based on : core.h of Sim-IM by Vladimir Shutoff + and Sim-IM team + copyright : (C) 2002 - 2004 Vladimir Shutoff + (C) 2004 - 2008 Sim-IM Development Team + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _CORE_CONSTS_H +#define _CORE_CONSTS_H + +const unsigned long CmdBase = 0x00020000; +const unsigned long CmdInfo = (CmdBase + 0x001); +const unsigned long CmdSearch = (CmdBase + 0x002); +const unsigned long CmdConnections = (CmdBase + 0x003); +const unsigned long CmdCM = (CmdBase + 0x004); +const unsigned long CmdProfileChange = (CmdBase + 0x005); +const unsigned long CmdShowPanel = (CmdBase + 0x006); +const unsigned long CmdCommonStatus = (CmdBase + 0x007); +const unsigned long CmdTitle = (CmdBase + 0x008); +const unsigned long CmdSetup = (CmdBase + 0x009); +const unsigned long CmdMainWindow = (CmdBase + 0x00B); // 11 +const unsigned long CmdUserView = (CmdBase + 0x00C); // 12 +const unsigned long CmdContainer = (CmdBase + 0x00D); // 13 +const unsigned long CmdClose = (CmdBase + 0x00E); // 14 +const unsigned long CmdContainerContact = (CmdBase + 0x00F); // 15 +const unsigned long CmdContainerContacts = (CmdBase + 0x010); // 16 +const unsigned long CmdSendMessage = (CmdBase + 0x011); // 17 +const unsigned long CmdSend = (CmdBase + 0x012); // 18 +const unsigned long CmdStatusMenu = (CmdBase + 0x014); // 20 +const unsigned long CmdStatusBar = (CmdBase + 0x015); // 21 +const unsigned long CmdMenu = (CmdBase + 0x017); // 23 +const unsigned long CmdOnline = (CmdBase + 0x018); // 24 //FIXME: Rename to CmdShowOfflineContacts to make code more sensible +const unsigned long CmdGroup = (CmdBase + 0x019); // 25 +const unsigned long CmdGrpOff = (CmdBase + 0x01A); // 26 +const unsigned long CmdGrpMode1 = (CmdBase + 0x01B); // 27 +const unsigned long CmdGrpMode2 = (CmdBase + 0x01C); // 28 +const unsigned long CmdGrpCreate = (CmdBase + 0x01D); // 29 +const unsigned long CmdGrpRename = (CmdBase + 0x01E); // 30 +const unsigned long CmdGrpDelete = (CmdBase + 0x01F); // 31 +const unsigned long CmdGrpTitle = (CmdBase + 0x020); // 32 +const unsigned long CmdGrpUp = (CmdBase + 0x021); // 33 +const unsigned long CmdGrpDown = (CmdBase + 0x022); // 34 +const unsigned long CmdContactTitle = (CmdBase + 0x023); // 35 +const unsigned long CmdContactRename = (CmdBase + 0x024); // 36 +const unsigned long CmdContactDelete = (CmdBase + 0x025); // 37 +const unsigned long CmdConfigure = (CmdBase + 0x026); // 38 +const unsigned long CmdMessageType = (CmdBase + 0x027); // 39 +const unsigned long CmdSendClose = (CmdBase + 0x028); // 40 +const unsigned long CmdSmile = (CmdBase + 0x029); // 41 +const unsigned long CmdMultiply = (CmdBase + 0x02A); // 42 +const unsigned long CmdSendSMS = (CmdBase + 0x02B); // 43 +const unsigned long CmdInvisible = (CmdBase + 0x02C); // 44 +const unsigned long CmdHistory = (CmdBase + 0x02D); // 45 +const unsigned long CmdHistorySave = (CmdBase + 0x02E); // 46 +const unsigned long CmdHistoryDirection = (CmdBase + 0x02F); // 47 +const unsigned long CmdHistoryNext = (CmdBase + 0x030); // 48 +const unsigned long CmdHistoryPrev = (CmdBase + 0x031); // 49 +const unsigned long CmdMsgOpen = (CmdBase + 0x033); // 51 +const unsigned long CmdMsgQuote = (CmdBase + 0x035); // 53 +const unsigned long CmdMsgAnswer = (CmdBase + 0x036); // 54 +const unsigned long CmdMsgForward = (CmdBase + 0x037); // 55 +const unsigned long CmdCopy = (CmdBase + 0x038); // 56 +const unsigned long CmdCut = (CmdBase + 0x039); // 57 +const unsigned long CmdPaste = (CmdBase + 0x03A); // 58 +const unsigned long CmdSelectAll = (CmdBase + 0x03B); // 59 +const unsigned long CmdUndo = (CmdBase + 0x03C); // 60 +const unsigned long CmdRedo = (CmdBase + 0x03D); // 61 +const unsigned long CmdClear = (CmdBase + 0x03E); // 62 +const unsigned long CmdSeparate = (CmdBase + 0x03F); // 63 +const unsigned long CmdNextMessage = (CmdBase + 0x041); // 65 +const unsigned long CmdGrantAuth = (CmdBase + 0x042); // 66 +const unsigned long CmdRefuseAuth = (CmdBase + 0x043); // 67 +const unsigned long CmdPhones = (CmdBase + 0x047); // 71 +const unsigned long CmdPhoneLocation = (CmdBase + 0x048); // 72 +const unsigned long CmdPhoneState = (CmdBase + 0x049); // 73 +const unsigned long CmdPhoneNoShow = (CmdBase + 0x04A); // 74 +const unsigned long CmdPhoneAvailable = (CmdBase + 0x04B); // 75 +const unsigned long CmdPhoneBusy = (CmdBase + 0x04C); // 76 +const unsigned long CmdPhoneBook = (CmdBase + 0x04D); // 77 +const unsigned long CmdShowAlways = (CmdBase + 0x04E); // 78 +const unsigned long CmdFileAccept = (CmdBase + 0x04F); // 79 +const unsigned long CmdFileDecline = (CmdBase + 0x050); // 80 +const unsigned long CmdDeclineWithoutReason = (CmdBase + 0x051); // 81 +const unsigned long CmdDeclineReasonInput = (CmdBase + 0x052); // 82 +const unsigned long CmdDeclineReasonBusy = (CmdBase + 0x053); // 83 +const unsigned long CmdDeclineReasonLater = (CmdBase + 0x054); // 84 +const unsigned long CmdHistoryFind = (CmdBase + 0x055); // 85 +const unsigned long CmdFileName = (CmdBase + 0x056); // 86 +const unsigned long CmdPhoneNumber = (CmdBase + 0x057); // 87 +const unsigned long CmdTranslit = (CmdBase + 0x058); // 88 +const unsigned long CmdUrlInput = (CmdBase + 0x059); // 89 +const unsigned long CmdCutHistory = (CmdBase + 0x05A); // 90 +const unsigned long CmdDeleteMessage = (CmdBase + 0x05B); // 91 +const unsigned long CmdEditList = (CmdBase + 0x05C); // 92 +const unsigned long CmdRemoveList = (CmdBase + 0x05D); // 93 +const unsigned long CmdStatusWnd = (CmdBase + 0x05E); // 94 +const unsigned long CmdEmptyGroup = (CmdBase + 0x05F); // 95 +const unsigned long CmdEnableSpell = (CmdBase + 0x060); // 96 +const unsigned long CmdSpell = (CmdBase + 0x061); // 97 +const unsigned long CmdChangeEncoding = (CmdBase + 0x062); // 98 +const unsigned long CmdAllEncodings = (CmdBase + 0x063); // 99 +const unsigned long CmdSearchInfo = (CmdBase + 0x065); // 101 +const unsigned long CmdSearchMsg = (CmdBase + 0x066); // 102 +const unsigned long CmdSearchOptions = (CmdBase + 0x067); // 103 +const unsigned long CmdFetchAway = (CmdBase + 0x068); // 104 +const unsigned long CmdHistoryAvatar = (CmdBase + 0x069); // 105 +const unsigned long CmdQuit = (CmdBase + 0x070); // 106 +const unsigned long CmdGroupToolbarButton = (CmdBase + 0x071); // 107 + +const unsigned long CmdContactGroup = (CmdBase + 0x100); +const unsigned long CmdUnread = (CmdBase + 0x200); +const unsigned long CmdContactClients = (CmdBase + 0x300); +const unsigned long CmdMsgSpecial = (CmdBase + 0x400); +const unsigned long CmdClient = (CmdBase + 0x500); +const unsigned long CmdContactResource = (CmdBase + 0x600); +const unsigned long CmdReceived = 0x600; //FIXME: Why it does not have CmdBase in it? + +// These consts are really defined at textshow.h, but listed here +// as a comments, in order to have a full comand list in one file: +// +//const unsigned TextCmdBase = 0x00030000; +//const unsigned CmdBgColor = TextCmdBase; +//const unsigned CmdFgColor = TextCmdBase + 1; +//const unsigned CmdBold = TextCmdBase + 2; +//const unsigned CmdItalic = TextCmdBase + 3; +//const unsigned CmdUnderline = TextCmdBase + 4; +//const unsigned CmdFont = TextCmdBase + 5; + +// *** Here we defines ids for all menus used in _core plugin *** + +// Main menu and it's submenus +const unsigned MenuMain = 0x0001; +const unsigned MenuStatus = 0x0002; +const unsigned MenuGroups = 0x0003; +const unsigned MenuPhones = 0x0004; +const unsigned MenuPhoneLocation = 0x0005; +const unsigned MenuPhoneState = 0x0006; +const unsigned MenuConnections = 0x0007; +// other menus +const unsigned MenuGroup = 0x1001; // Context menu for Group item in userlist +const unsigned MenuContact = 0x1002; // Context menu for Contact item in userlist +const unsigned MenuContactGroup = 0x1003; +const unsigned MenuContainer = 0x1004; +const unsigned MenuMessage = 0x1005; +const unsigned MenuContainerContact = 0x1006; +const unsigned MenuMsgView = 0x1007; +const unsigned MenuTextEdit = 0x1008; +const unsigned MenuMsgCommand = 0x1009; +const unsigned MenuFileDecline = 0x100A; +const unsigned MenuMailList = 0x100B; +const unsigned MenuPhoneList = 0x100C; +const unsigned MenuStatusWnd = 0x100D; +const unsigned MenuEncoding = 0x100E; +const unsigned MenuSearchItem = 0x100F; +const unsigned MenuSearchGroups = 0x1010; +const unsigned MenuSearchOptions = 0x1011; + +// *** Here we defines ids for all toolbars used in _core plugin *** + +const unsigned ToolBarMain = 1; +const unsigned ToolBarContainer = 2; +const unsigned ToolBarTextEdit = 3; +const unsigned ToolBarMsgEdit = 4; +const unsigned ToolBarHistory = 5; +const unsigned ToolBarHistoryAvatar = 6; + + +#endif diff --git a/plugins/_core/core_events.h b/plugins/_core/core_events.h new file mode 100644 index 0000000..9d371c3 --- /dev/null +++ b/plugins/_core/core_events.h @@ -0,0 +1,269 @@ +#ifndef _CORE_EVENTS_H +#define _CORE_EVENTS_H + +#include "event.h" + +class Tmpl; +class MsgEdit; + +struct CutHistory; + +// EventARRequest +struct ARRequest +{ + SIM::Contact *contact; + unsigned status; + SIM::EventReceiver *receiver; + void *param; +}; + +class EventCreateMessageType : public SIM::Event +{ +public: + EventCreateMessageType(SIM::CommandDef *def) + : Event(SIM::eEventCreateMessageType), m_def(def) {}; + + SIM::CommandDef *def() const { return m_def; } +protected: + SIM::CommandDef *m_def; +}; + +class EventRemoveMessageType : public SIM::Event +{ +public: + EventRemoveMessageType(unsigned long id) + : Event(SIM::eEventRemoveMessageType), m_id(id) {}; + + unsigned long id() const { return m_id; } +protected: + unsigned long m_id; +}; + +class EventRealSendMessage : public SIM::EventMessage +{ +public: + EventRealSendMessage(SIM::Message *msg, MsgEdit *edit) + : EventMessage(SIM::eEventRealSendMessage, msg), m_edit(edit) {} + + MsgEdit *edit() const { return m_edit; } +protected: + MsgEdit *m_edit; +}; + +class EventHistoryConfig : public SIM::Event +{ +public: + EventHistoryConfig(unsigned long contact_id) + : Event(SIM::eEventHistoryConfig), m_id(contact_id) {} + + unsigned long id() const { return m_id; } +protected: + unsigned long m_id; +}; + +class EventHistoryColors : public SIM::Event +{ +public: + EventHistoryColors() : Event(SIM::eEventHistoryColors) {} +}; + +class EventTemplate : public SIM::Event +{ +public: + struct TemplateExpand { + QString tmpl; + SIM::Contact *contact; + SIM::EventReceiver *receiver; + void *param; + }; +public: + EventTemplate(SIM::SIMEvent e, TemplateExpand *te) + : Event(e), m_te(te) {} + + TemplateExpand *templateExpand() const { return m_te; } +protected: + TemplateExpand *m_te; +}; + +class EventTemplateExpand : public EventTemplate +{ +public: + EventTemplateExpand(TemplateExpand *te) + : EventTemplate(SIM::eEventTemplateExpand, te) {} +}; + +class EventTemplateExpanded : public EventTemplate +{ +public: + EventTemplateExpanded(TemplateExpand *te) + : EventTemplate(SIM::eEventTemplateExpanded, te) {} +}; + +class EventARRequest : public SIM::Event +{ +public: + EventARRequest(ARRequest *ar) + : Event(SIM::eEventARRequest), m_ar(ar){} + + ARRequest *request() const { return m_ar; } +protected: + ARRequest *m_ar; +}; + +class EventClientStatus : public SIM::Event +{ +public: + EventClientStatus() : Event(SIM::eEventClientStatus) {} +}; + +class EventLoadMessage : public SIM::Event +{ +public: + EventLoadMessage(unsigned long id, const QString &client, unsigned long contact) + : Event(SIM::eEventLoadMessage), m_id(id), m_client(client), + m_contact(contact), m_msg(NULL) {} + + unsigned long id() const { return m_id; } + const QString client() const { return m_client; } + unsigned long contact() const { return m_contact; } + // out + void setMessage(SIM::Message *msg) { m_msg = msg; } + SIM::Message *message() const { return m_msg; } +protected: + unsigned long m_id; + QString m_client; + unsigned long m_contact; + SIM::Message *m_msg; +}; + +class EventDefaultAction : public SIM::Event +{ +public: + EventDefaultAction(unsigned long contact_id) + : Event(SIM::eEventDefaultAction), m_id(contact_id) {} + + unsigned long id() const { return m_id; } +protected: + unsigned long m_id; +}; + +class EventContactClient : public SIM::Event +{ +public: + EventContactClient(SIM::Contact *contact) + : Event(SIM::eEventContactClient), m_contact(contact) {} + + SIM::Contact *contact() const { return m_contact; } +protected: + SIM::Contact *m_contact; +}; + +class EventActiveContact : public SIM::Event +{ +public: + EventActiveContact() + : Event(SIM::eEventActiveContact), m_id(0) {} + + // out + void setContactID(unsigned long id) { m_id = id; } + unsigned long contactID() const { return m_id; } +protected: + unsigned long m_id; +}; + +class EventMessageRetry : public SIM::Event +{ +public: + struct MsgSend + { + SIM::Message *msg; + MsgEdit *edit; + }; +public: + EventMessageRetry(MsgSend *msgRetry) + : Event(SIM::eEventMessageRetry), m_msgRetry(msgRetry) {} + + MsgSend *msgRetry() const { return m_msgRetry; } +protected: + MsgSend *m_msgRetry; +}; + +class EventCheckSend : public SIM::Event +{ +public: + // FIXME: void *data + EventCheckSend(unsigned long id, SIM::Client *client, void *data) + : Event(SIM::eEventCheckSend), m_id(id), m_client(client), m_data(data) {} + + unsigned long id() const { return m_id; } + SIM::Client *client() const { return m_client; } + void *data() const { return m_data; } +protected: + unsigned long m_id; + SIM::Client *m_client; + void *m_data; +}; + +class EventCutHistory : public SIM::Event +{ +public: + EventCutHistory(CutHistory *cut) + : Event(SIM::eEventCutHistory), m_cut(cut) {} + + CutHistory *cut() const { return m_cut; } +protected: + CutHistory *m_cut; +}; + +class EventTmplHelp : public SIM::Event +{ +public: + EventTmplHelp(const QString &helpString) + : Event(SIM::eEventTmplHelp), m_help(helpString) {} + + // in & out + void setHelp(const QString &help) { m_help = help; } + const QString &help() const { return m_help; } +protected: + QString m_help; +}; + +class EventTmplHelpList : public SIM::Event +{ +public: + EventTmplHelpList() : Event(SIM::eEventTmplHelpList) {} + + // out, fixme - use QStringList + void setHelpList(const char **helpList) { m_helpList = helpList; } + const char **helpList() const { return m_helpList; } +protected: + const char **m_helpList; +}; + +class EventJoinAlert : public SIM::Event +{ +public: + EventJoinAlert(SIM::Client *client) + : Event(SIM::eEventJoinAlert), m_client(client) {} + + SIM::Client *client() const { return m_client; } +protected: + SIM::Client *m_client; +}; + +class EventDeleteMessage : public SIM::EventMessage +{ +public: + EventDeleteMessage(SIM::Message *msg) + : EventMessage(SIM::eEventDeleteMessage, msg) {} +}; + +class EventRewriteMessage : public SIM::EventMessage +{ +public: + EventRewriteMessage(SIM::Message *msg) + : EventMessage(SIM::eEventRewriteMessage, msg) {} +}; + +#endif + diff --git a/plugins/_core/core_pch.h b/plugins/_core/core_pch.h new file mode 100644 index 0000000..f6fdce7 --- /dev/null +++ b/plugins/_core/core_pch.h @@ -0,0 +1,119 @@ +#pragma once + +#include +#include + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//Fixme: +//#ifndef NO_QT_MOC_HEADER +#include +/*#include +#include +#endif*/ + +#include "arcfg.h" +#include "ui_arcfgbase.h" +#include "autoreply.h" +#include "ui_autoreplybase.h" +#include "cfgdlg.h" +#include "ui_cfgdlgbase.h" +#include "cmenu.h" +#include "commands.h" +#include "connectionsettings.h" +#include "ui_connectionsettingsbase.h" +#include "connectwnd.h" +#include "ui_connectwndbase.h" +#include "container.h" +#include "core.h" +#include "declinedlg.h" +#include "ui_declinedlgbase.h" +#include "editmail.h" +#include "ui_editmailbase.h" +#include "editphone.h" +#include "ui_editphonebase.h" +#include "filecfg.h" +#include "ui_filecfgbase.h" +#include "filetransfer.h" +#include "ui_filetransferbase.h" +#include "history.h" +#include "historycfg.h" +#include "ui_historycfgbase.h" +#include "historywnd.h" +#include "interfacecfg.h" +#include "ui_interfacecfgbase.h" +#include "maininfo.h" +#include "ui_maininfobase.h" +#include "mainwin.h" +#include "manager.h" +#include "ui_managerbase.h" +#include "msgauth.h" +#include "msgcfg.h" +#include "ui_msgcfgbase.h" +#include "msgcontacts.h" +#include "msgedit.h" +#include "msgfile.h" +#include "msggen.h" +#include "msgrecv.h" +#include "msgsms.h" +#include "msgurl.h" +#include "msgview.h" +#include "newprotocol.h" +#include "ui_newprotocolbase.h" +#include "nonim.h" +#include "ui_nonimbase.h" +#include "ui_pagerbase.h" +#include "pagerdetails.h" +#include "ui_phonebase.h" +#include "phonedetails.h" +#include "plugincfg.h" +#include "ui_plugincfgbase.h" +#include "prefcfg.h" +#include "ui_prefcfgbase.h" +#include "search.h" +#include "searchall.h" +#include "ui_searchallbase.h" +#include "ui_searchbase.h" +#include "smscfg.h" +#include "ui_smscfgbase.h" +#include "status.h" +#include "statuswnd.h" +#include "tmpl.h" +#include "toolbarcfg.h" +#include "toolsetup.h" +#include "ui_toolsetupbase.h" +#include "usercfg.h" +#include "userhistorycfg.h" +#include "ui_userhistorycfgbase.h" +#include "userlist.h" +#include "userview.h" +#include "userviewcfg.h" +#include "ui_userviewcfgbase.h" +#include "userwnd.h" +#include "logindlg.h" +#include "ui_logindlgbase.h" \ No newline at end of file diff --git a/plugins/_core/declinedlg.cpp b/plugins/_core/declinedlg.cpp new file mode 100644 index 0000000..3d56a10 --- /dev/null +++ b/plugins/_core/declinedlg.cpp @@ -0,0 +1,66 @@ +/*************************************************************************** + declinedlg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "icons.h" +#include "misc.h" +#include "declinedlg.h" + +#include +#include + +using namespace SIM; + +DeclineDlg::DeclineDlg(Message *msg) + : QDialog(NULL) + , m_msg (msg) + //: DeclineDlgBase(NULL, NULL, false, Qt::WDestructiveClose) +{ + setupUi(this); + + SET_WNDPROC("decline") + setWindowIcon(Icon("file")); + setButtonsPict(this); +} + +DeclineDlg::~DeclineDlg() +{ +} + +void DeclineDlg::accept() +{ + EventMessageDecline(m_msg, edtReason->text()); + QDialog::accept(); +} + +bool DeclineDlg::processEvent(Event *e) +{ + if (e->type() == eEventMessageDeleted) + { + EventMessage *em = static_cast(e); + Message *msg = em->msg(); + if (msg->id() == m_msg->id()) + close(); + } + return false; +} + +/* +#ifndef NO_MOC_INCLUDES +#include "declinedlg.moc" +#endif +*/ + diff --git a/plugins/_core/declinedlg.h b/plugins/_core/declinedlg.h new file mode 100644 index 0000000..11763ba --- /dev/null +++ b/plugins/_core/declinedlg.h @@ -0,0 +1,38 @@ +/*************************************************************************** + declinedlg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _DECLINEDLG_H +#define _DECLINEDLG_H + +#include "ui_declinedlgbase.h" +#include "event.h" + +class DeclineDlg : public QDialog, public Ui::DeclineDlgBase, public SIM::EventReceiver +{ + Q_OBJECT +public: + DeclineDlg(SIM::Message *msg); + ~DeclineDlg(); + SIM::Message *message() { return m_msg; } +protected: + virtual bool processEvent(SIM::Event*); + void accept(); + SIM::Message *m_msg; +}; + +#endif + diff --git a/plugins/_core/declinedlgbase.ui b/plugins/_core/declinedlgbase.ui new file mode 100644 index 0000000..4251781 --- /dev/null +++ b/plugins/_core/declinedlgbase.ui @@ -0,0 +1,123 @@ + + + + + DeclineDlgBase + + + + 0 + 0 + 438 + 112 + + + + Decline reason + + + true + + + + 11 + + + 6 + + + + + Enter decline reason: + + + false + + + + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Vertical + + + + + + + 0 + + + 6 + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Horizontal + + + + + + + &OK + + + true + + + true + + + + + + + &Cancel + + + true + + + + + + + + qPixmapFromMimeSource + + + buttonOk + clicked() + DeclineDlg + accept() + + + buttonCancel + clicked() + DeclineDlg + reject() + + + diff --git a/plugins/_core/editmail.cpp b/plugins/_core/editmail.cpp new file mode 100644 index 0000000..f47a0ac --- /dev/null +++ b/plugins/_core/editmail.cpp @@ -0,0 +1,61 @@ +/*************************************************************************** + editmail.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "icons.h" +#include "misc.h" +#include "editmail.h" + +#include +#include +#include +#include + +using namespace SIM; + +EditMail::EditMail(QWidget *parent, const QString &mail, bool bPublish, bool bShowPublish) + : QDialog(parent) +{ + setupUi(this); + setObjectName("editmail"); + SET_WNDPROC("editmail") + setWindowIcon(Icon("mail_generic")); + setButtonsPict(this); + setWindowTitle(mail.isEmpty() ? i18n("Add mail address") : i18n("Edit mail address")); + edtMail->setText(mail); + connect(edtMail, SIGNAL(textChanged(const QString&)), this, SLOT(textChanged(const QString&))); + textChanged(mail); + edtMail->setFocus(); + publish = bPublish; + if (bShowPublish) + { + chkPublish->setChecked(publish); + return; + } + chkPublish->hide(); +} + +void EditMail::textChanged(const QString &text) +{ + buttonOk->setEnabled(!text.isEmpty()); +} + +void EditMail::accept() +{ + res = edtMail->text(); + publish = chkPublish->isChecked(); + QDialog::accept(); +} diff --git a/plugins/_core/editmail.h b/plugins/_core/editmail.h new file mode 100644 index 0000000..7143ab0 --- /dev/null +++ b/plugins/_core/editmail.h @@ -0,0 +1,37 @@ +/*************************************************************************** + editmail.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _EDITMAIL_H +#define _EDITMAIL_H + +#include "ui_editmailbase.h" + +class EditMail : public QDialog, public Ui::EditMailBase +{ + Q_OBJECT +public: + EditMail(QWidget *parent, const QString &mail, bool bPublish, bool bShowPublish); + QString res; + bool publish; +protected slots: + void textChanged(const QString&); +protected: + void accept(); +}; + +#endif + diff --git a/plugins/_core/editmailbase.ui b/plugins/_core/editmailbase.ui new file mode 100644 index 0000000..eb4330b --- /dev/null +++ b/plugins/_core/editmailbase.ui @@ -0,0 +1,152 @@ + + + + + EditMailBase + + + + 0 + 0 + 315 + 174 + + + + + 5 + 5 + + + + EditMail + + + true + + + + 11 + + + 6 + + + + + Enter Email address: + + + Qt::AlignVCenter|Qt::AlignLeft + + + false + + + + + + + + + + &Publish + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Vertical + + + + + + + QFrame::HLine + + + QFrame::Sunken + + + QFrame::HLine + + + + + + + 0 + + + 6 + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Horizontal + + + + + + + &OK + + + true + + + true + + + + + + + &Cancel + + + true + + + + + + + + qPixmapFromMimeSource + + + buttonOk + clicked() + EditMail + accept() + + + buttonCancel + clicked() + EditMail + reject() + + + diff --git a/plugins/_core/editphone.cpp b/plugins/_core/editphone.cpp new file mode 100644 index 0000000..80efc8d --- /dev/null +++ b/plugins/_core/editphone.cpp @@ -0,0 +1,161 @@ +/*************************************************************************** + editphone.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "country.h" +#include "icons.h" +#include "misc.h" + +#include "editphone.h" +#include "phonedetails.h" +#include "pagerdetails.h" + +#include +#include +#include +#include +#include + +using namespace SIM; + +extern ext_info phoneIcons[]; +extern const char *phoneTypeNames[]; + +EditPhone::EditPhone(QWidget *parent, const QString &number, const QString &type, unsigned icon, bool bPublish, bool bShowPublish) + : QDialog(parent) + , m_ok (false) + , m_phone (new PhoneDetails(wndDetails, (icon == PAGER) ? QString() : number ) ) + , m_pager (new PagerDetails(wndDetails, (icon == PAGER) ? number : QString() ) ) +{ + setObjectName("editphone"); + setupUi(this); + SET_WNDPROC("editphone") + setWindowIcon(Icon("phone")); + setButtonsPict(this); + setWindowTitle(number.isEmpty() ? i18n("Add phone number") : i18n("Edit phone number")); + wndDetails->addWidget(m_phone); + wndDetails->addWidget(m_pager); + connect(m_phone, SIGNAL(numberChanged(const QString&, bool)), this, SLOT(numberChanged(const QString&, bool))); + connect(m_pager, SIGNAL(numberChanged(const QString&, bool)), this, SLOT(numberChanged(const QString&, bool))); + edtDetails->setReadOnly(true); + for (const ext_info *icons = phoneIcons; icons->szName; icons++) + cmbType->insertItem(INT_MAX,Icon(icons->szName),QString()); + + for (const char **names = phoneTypeNames; *names; names++) + cmbName->insertItem(INT_MAX,i18n(*names)); + + cmbName->setEditable(true); + cmbName->lineEdit()->setText(type); + connect(cmbType, SIGNAL(activated(int)), this, SLOT(typeChanged(int))); + connect(cmbName, SIGNAL(textChanged(const QString&)), this, SLOT(nameChanged(const QString&))); + cmbType->setCurrentIndex(icon); + typeChanged(icon); + publish = bPublish; + if (bShowPublish) + chkPublish->setChecked(publish); + else + chkPublish->hide(); +} + +void EditPhone::typeChanged(int) +{ + switch (cmbType->currentIndex()) + { + case 0: + wndDetails->setCurrentWidget(m_phone); + m_phone->setExtensionShow(true); + m_phone->getNumber(); + break; + case 1: + case 2: + wndDetails->setCurrentWidget(m_phone); + m_phone->setExtensionShow(false); + m_phone->getNumber(); + break; + case 3: + wndDetails->setCurrentWidget(m_pager); + m_pager->getNumber(); + break; + } +} + +void EditPhone::numberChanged(const QString &number, bool isOK) +{ + edtDetails->setText(number); + m_ok = isOK; + changed(); +} + +void EditPhone::nameChanged(const QString &name) +{ + unsigned i = 0; + for (const char **p = phoneTypeNames; *p; p++, i++) + if (name == i18n(*p)) + break; + switch (i) + { + case 0: + case 2: + cmbType->setCurrentIndex(0); + typeChanged(0); + break; + case 1: + case 3: + cmbType->setCurrentIndex(1); + typeChanged(1); + break; + case 4: + cmbType->setCurrentIndex(2); + typeChanged(2); + break; + case 5: + cmbType->setCurrentIndex(3); + typeChanged(3); + break; + } + changed(); +} + +void EditPhone::changed() +{ + buttonOk->setEnabled(m_ok && !cmbName->lineEdit()->text().isEmpty()); +} + +void EditPhone::accept() +{ + number = edtDetails->text(); + type = cmbName->lineEdit()->text(); + for (const char **names = phoneTypeNames; *names; names++) + { + if (type != i18n(*names)) + continue; + + type = *names; + break; + } + icon = cmbType->currentIndex(); + publish = chkPublish->isChecked(); + QDialog::accept(); +} + +/* +#ifndef NO_MOC_INCLUDES +#include "editphone.moc" +#endif +*/ + +// vim: set expandtab: + diff --git a/plugins/_core/editphone.h b/plugins/_core/editphone.h new file mode 100644 index 0000000..6647501 --- /dev/null +++ b/plugins/_core/editphone.h @@ -0,0 +1,48 @@ +/*************************************************************************** + editphone.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _EDITPHONE_H +#define _EDITPHONE_H + +#include "ui_editphonebase.h" + +class PhoneDetails; +class PagerDetails; + +class EditPhone : public QDialog, public Ui::EditPhone +{ + Q_OBJECT +public: + EditPhone(QWidget *parent, const QString &number, const QString &type, unsigned icon, bool bPublish, bool bShowPublish); + QString number; + QString type; + unsigned icon; + bool publish; +protected slots: + void numberChanged(const QString&, bool); + void nameChanged(const QString&); + void typeChanged(int); +protected: + void accept(); + void changed(); + bool m_ok; + PhoneDetails *m_phone; + PagerDetails *m_pager; +}; + +#endif + diff --git a/plugins/_core/editphonebase.ui b/plugins/_core/editphonebase.ui new file mode 100644 index 0000000..0fe87df --- /dev/null +++ b/plugins/_core/editphonebase.ui @@ -0,0 +1,182 @@ + + + EditPhone + + + + 0 + 0 + 402 + 242 + + + + EditPhone + + + true + + + + 6 + + + 11 + + + + + Number details: + + + false + + + + + + + + + + 6 + + + 0 + + + + + Type: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + + 0 + 0 + + + + + + + + + + + + + + + + &Publish + + + + + + + 6 + + + 0 + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + &OK + + + true + + + true + + + + + + + &Cancel + + + true + + + + + + + + + edtDetails + cmbType + cmbName + chkPublish + buttonOk + buttonCancel + + + + + buttonOk + clicked() + EditPhone + accept() + + + 20 + 20 + + + 20 + 20 + + + + + buttonCancel + clicked() + EditPhone + reject() + + + 20 + 20 + + + 20 + 20 + + + + + diff --git a/plugins/_core/emoticons_prebuilt/SIM-icons-Crystal-full.jisp b/plugins/_core/emoticons_prebuilt/SIM-icons-Crystal-full.jisp new file mode 100644 index 0000000..e5aa108 Binary files /dev/null and b/plugins/_core/emoticons_prebuilt/SIM-icons-Crystal-full.jisp differ diff --git a/plugins/_core/emoticons_prebuilt/SIM-icons-Crystal-full.jisp.license b/plugins/_core/emoticons_prebuilt/SIM-icons-Crystal-full.jisp.license new file mode 100644 index 0000000..0b4c764 --- /dev/null +++ b/plugins/_core/emoticons_prebuilt/SIM-icons-Crystal-full.jisp.license @@ -0,0 +1,4 @@ +LGPL + +http://www.everaldo.com/crystal/?action=license +The Crystal Project are released under LGPL diff --git a/plugins/_core/emoticons_prebuilt/SIM-icons-Nuvola-full.jisp b/plugins/_core/emoticons_prebuilt/SIM-icons-Nuvola-full.jisp new file mode 100644 index 0000000..a5f33b0 Binary files /dev/null and b/plugins/_core/emoticons_prebuilt/SIM-icons-Nuvola-full.jisp differ diff --git a/plugins/_core/emoticons_prebuilt/SIM-icons-Nuvola-full.jisp.license b/plugins/_core/emoticons_prebuilt/SIM-icons-Nuvola-full.jisp.license new file mode 100644 index 0000000..c689cf1 --- /dev/null +++ b/plugins/_core/emoticons_prebuilt/SIM-icons-Nuvola-full.jisp.license @@ -0,0 +1,4 @@ +LGPL + +http://icon-king.com/?p=15 +The Nuvola icons are licensed under the LGPL \ No newline at end of file diff --git a/plugins/_core/emoticons_prebuilt/SIM-icons-XP-full.jisp b/plugins/_core/emoticons_prebuilt/SIM-icons-XP-full.jisp new file mode 100644 index 0000000..0d83aa5 Binary files /dev/null and b/plugins/_core/emoticons_prebuilt/SIM-icons-XP-full.jisp differ diff --git a/plugins/_core/emoticons_prebuilt/SIM-icons-XP-full.jisp.license b/plugins/_core/emoticons_prebuilt/SIM-icons-XP-full.jisp.license new file mode 100644 index 0000000..72c3cae --- /dev/null +++ b/plugins/_core/emoticons_prebuilt/SIM-icons-XP-full.jisp.license @@ -0,0 +1 @@ +Unknown-proprietary diff --git a/plugins/_core/emoticons_prebuilt/additional.jisp b/plugins/_core/emoticons_prebuilt/additional.jisp new file mode 100644 index 0000000..21ae443 Binary files /dev/null and b/plugins/_core/emoticons_prebuilt/additional.jisp differ diff --git a/plugins/_core/emoticons_prebuilt/additional.jisp.license b/plugins/_core/emoticons_prebuilt/additional.jisp.license new file mode 100644 index 0000000..72c3cae --- /dev/null +++ b/plugins/_core/emoticons_prebuilt/additional.jisp.license @@ -0,0 +1 @@ +Unknown-proprietary diff --git a/plugins/_core/emoticons_prebuilt/amibulb.jisp b/plugins/_core/emoticons_prebuilt/amibulb.jisp new file mode 100644 index 0000000..135c88b Binary files /dev/null and b/plugins/_core/emoticons_prebuilt/amibulb.jisp differ diff --git a/plugins/_core/emoticons_prebuilt/amibulb.jisp.license b/plugins/_core/emoticons_prebuilt/amibulb.jisp.license new file mode 100644 index 0000000..d5d21ff --- /dev/null +++ b/plugins/_core/emoticons_prebuilt/amibulb.jisp.license @@ -0,0 +1 @@ +Public Domain diff --git a/plugins/_core/emoticons_prebuilt/apple_ichat.jisp b/plugins/_core/emoticons_prebuilt/apple_ichat.jisp new file mode 100644 index 0000000..a739ccc Binary files /dev/null and b/plugins/_core/emoticons_prebuilt/apple_ichat.jisp differ diff --git a/plugins/_core/emoticons_prebuilt/apple_ichat.jisp.license b/plugins/_core/emoticons_prebuilt/apple_ichat.jisp.license new file mode 100644 index 0000000..72c3cae --- /dev/null +++ b/plugins/_core/emoticons_prebuilt/apple_ichat.jisp.license @@ -0,0 +1 @@ +Unknown-proprietary diff --git a/plugins/_core/emoticons_prebuilt/gants.jisp b/plugins/_core/emoticons_prebuilt/gants.jisp new file mode 100644 index 0000000..69e70ef Binary files /dev/null and b/plugins/_core/emoticons_prebuilt/gants.jisp differ diff --git a/plugins/_core/emoticons_prebuilt/gants.jisp.license b/plugins/_core/emoticons_prebuilt/gants.jisp.license new file mode 100644 index 0000000..72c3cae --- /dev/null +++ b/plugins/_core/emoticons_prebuilt/gants.jisp.license @@ -0,0 +1 @@ +Unknown-proprietary diff --git a/plugins/_core/emoticons_prebuilt/icq5.1.jisp b/plugins/_core/emoticons_prebuilt/icq5.1.jisp new file mode 100644 index 0000000..cf2f55e Binary files /dev/null and b/plugins/_core/emoticons_prebuilt/icq5.1.jisp differ diff --git a/plugins/_core/emoticons_prebuilt/icq5.1.jisp.license b/plugins/_core/emoticons_prebuilt/icq5.1.jisp.license new file mode 100644 index 0000000..72c3cae --- /dev/null +++ b/plugins/_core/emoticons_prebuilt/icq5.1.jisp.license @@ -0,0 +1 @@ +Unknown-proprietary diff --git a/plugins/_core/emoticons_prebuilt/icq5.jisp b/plugins/_core/emoticons_prebuilt/icq5.jisp new file mode 100644 index 0000000..86e9e26 Binary files /dev/null and b/plugins/_core/emoticons_prebuilt/icq5.jisp differ diff --git a/plugins/_core/emoticons_prebuilt/icq5.jisp.license b/plugins/_core/emoticons_prebuilt/icq5.jisp.license new file mode 100644 index 0000000..72c3cae --- /dev/null +++ b/plugins/_core/emoticons_prebuilt/icq5.jisp.license @@ -0,0 +1 @@ +Unknown-proprietary diff --git a/plugins/_core/emoticons_prebuilt/icqlite.jisp b/plugins/_core/emoticons_prebuilt/icqlite.jisp new file mode 100644 index 0000000..66181e9 Binary files /dev/null and b/plugins/_core/emoticons_prebuilt/icqlite.jisp differ diff --git a/plugins/_core/emoticons_prebuilt/icqlite.jisp.license b/plugins/_core/emoticons_prebuilt/icqlite.jisp.license new file mode 100644 index 0000000..72c3cae --- /dev/null +++ b/plugins/_core/emoticons_prebuilt/icqlite.jisp.license @@ -0,0 +1 @@ +Unknown-proprietary diff --git a/plugins/_core/emoticons_prebuilt/lovenmoney.jisp b/plugins/_core/emoticons_prebuilt/lovenmoney.jisp new file mode 100644 index 0000000..293631f Binary files /dev/null and b/plugins/_core/emoticons_prebuilt/lovenmoney.jisp differ diff --git a/plugins/_core/emoticons_prebuilt/lovenmoney.jisp.license b/plugins/_core/emoticons_prebuilt/lovenmoney.jisp.license new file mode 100644 index 0000000..72c3cae --- /dev/null +++ b/plugins/_core/emoticons_prebuilt/lovenmoney.jisp.license @@ -0,0 +1 @@ +Unknown-proprietary diff --git a/plugins/_core/emoticons_prebuilt/msn.jisp b/plugins/_core/emoticons_prebuilt/msn.jisp new file mode 100644 index 0000000..e45edaa Binary files /dev/null and b/plugins/_core/emoticons_prebuilt/msn.jisp differ diff --git a/plugins/_core/emoticons_prebuilt/msn.jisp.license b/plugins/_core/emoticons_prebuilt/msn.jisp.license new file mode 100644 index 0000000..60e5f0d --- /dev/null +++ b/plugins/_core/emoticons_prebuilt/msn.jisp.license @@ -0,0 +1,3 @@ +GPL + +http://amsn.svn.sourceforge.net/viewvc/amsn/tags/Release-0_97/amsn/skins/default/license?view=markup diff --git a/plugins/_core/emoticons_prebuilt/sim.jisp b/plugins/_core/emoticons_prebuilt/sim.jisp new file mode 100644 index 0000000..8384dcc Binary files /dev/null and b/plugins/_core/emoticons_prebuilt/sim.jisp differ diff --git a/plugins/_core/emoticons_prebuilt/sim.jisp.license b/plugins/_core/emoticons_prebuilt/sim.jisp.license new file mode 100644 index 0000000..72c3cae --- /dev/null +++ b/plugins/_core/emoticons_prebuilt/sim.jisp.license @@ -0,0 +1 @@ +Unknown-proprietary diff --git a/plugins/_core/emoticons_prebuilt/sim2.jisp b/plugins/_core/emoticons_prebuilt/sim2.jisp new file mode 100644 index 0000000..723a10f Binary files /dev/null and b/plugins/_core/emoticons_prebuilt/sim2.jisp differ diff --git a/plugins/_core/emoticons_prebuilt/sim2.jisp.license b/plugins/_core/emoticons_prebuilt/sim2.jisp.license new file mode 100644 index 0000000..72c3cae --- /dev/null +++ b/plugins/_core/emoticons_prebuilt/sim2.jisp.license @@ -0,0 +1 @@ +Unknown-proprietary diff --git a/plugins/_core/emoticons_prebuilt/smiles.jisp b/plugins/_core/emoticons_prebuilt/smiles.jisp new file mode 100644 index 0000000..575627f Binary files /dev/null and b/plugins/_core/emoticons_prebuilt/smiles.jisp differ diff --git a/plugins/_core/emoticons_prebuilt/smiles.jisp.license b/plugins/_core/emoticons_prebuilt/smiles.jisp.license new file mode 100644 index 0000000..72c3cae --- /dev/null +++ b/plugins/_core/emoticons_prebuilt/smiles.jisp.license @@ -0,0 +1 @@ +Unknown-proprietary diff --git a/plugins/_core/emoticons_prebuilt/yahoo.jisp b/plugins/_core/emoticons_prebuilt/yahoo.jisp new file mode 100644 index 0000000..c3d6623 Binary files /dev/null and b/plugins/_core/emoticons_prebuilt/yahoo.jisp differ diff --git a/plugins/_core/emoticons_prebuilt/yahoo.jisp.license b/plugins/_core/emoticons_prebuilt/yahoo.jisp.license new file mode 100644 index 0000000..72c3cae --- /dev/null +++ b/plugins/_core/emoticons_prebuilt/yahoo.jisp.license @@ -0,0 +1 @@ +Unknown-proprietary diff --git a/plugins/_core/filecfg.cpp b/plugins/_core/filecfg.cpp new file mode 100644 index 0000000..939ea4e --- /dev/null +++ b/plugins/_core/filecfg.cpp @@ -0,0 +1,71 @@ +/*************************************************************************** + filecfg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "filecfg.h" +#include "simgui/editfile.h" +#include "smscfg.h" +#include "core.h" + +#include +#include + +using namespace SIM; + +FileConfig::FileConfig(QWidget *parent, SIM::PropertyHubPtr data) + : QWidget(parent) +{ + setupUi(this); + edtPath->setDirMode(true); + edtPath->setText(user_file(data->value("IncomingPath").toString())); + switch (data->value("AcceptMode").toUInt()) + { + case 0: + btnDialog->setChecked(true); + break; + case 1: + btnAccept->setChecked(true); + chkOverwrite->setEnabled(true); + break; + case 2: + btnDecline->setChecked(true); + edtDecline->setEnabled(true); + break; + } + chkOverwrite->setChecked(data->value("OverwriteFiles").toBool()); + edtDecline->setPlainText(data->value("DeclineMessage").toString()); +} + +void FileConfig::apply(SIM::PropertyHubPtr data) +{ + QString def = edtPath->text().isEmpty() ? "Incoming Files" : edtPath->text(); + data->setValue("IncomingPath", def); + edtPath->setText(user_file(data->value("IncomingPath").toString())); + data->setValue("AcceptMode", 0); + if (btnAccept->isChecked()) + { + data->setValue("AcceptMode", 1); + data->setValue("OverwriteFiles", chkOverwrite->isChecked()); + } + if (btnDecline->isChecked()) + { + data->setValue("AcceptMode", 2); + data->setValue("DeclineMessage", edtDecline->toPlainText()); + } +} + +// vim: set expandtab: + diff --git a/plugins/_core/filecfg.h b/plugins/_core/filecfg.h new file mode 100644 index 0000000..4666fe9 --- /dev/null +++ b/plugins/_core/filecfg.h @@ -0,0 +1,36 @@ +/*************************************************************************** + filecfg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _FILECFG_H +#define _FILECFG_H + +#include "propertyhub.h" +#include "ui_filecfgbase.h" + +class QCheckBox; + +class FileConfig : public QWidget, public Ui::FileConfigBase +{ + Q_OBJECT +public: + FileConfig(QWidget *parent, SIM::PropertyHubPtr data); +public slots: + void apply(SIM::PropertyHubPtr); +}; + +#endif + diff --git a/plugins/_core/filecfgbase.ui b/plugins/_core/filecfgbase.ui new file mode 100644 index 0000000..7e44c98 --- /dev/null +++ b/plugins/_core/filecfgbase.ui @@ -0,0 +1,140 @@ + + + FileConfigBase + + + + 0 + 0 + 553 + 363 + + + + Form1 + + + + + + Path for incoming files: + + + false + + + + + + + + + + Accept mode + + + + + + Show response + + + + + + + Auto accept + + + + + + + false + + + Overwrite files + + + 100 + + + + + + + Auto decline + + + 2 + + + + + + + false + + + + + + + + + + Qt::Vertical + + + + 20 + 50 + + + + + + + + + EditFile + QWidget +
simgui/editfile.h
+
+
+ + + + btnAccept + toggled(bool) + chkOverwrite + setEnabled(bool) + + + 131 + 92 + + + 316 + 89 + + + + + btnDecline + toggled(bool) + edtDecline + setEnabled(bool) + + + 85 + 119 + + + 86 + 167 + + + + +
diff --git a/plugins/_core/filetransfer.cpp b/plugins/_core/filetransfer.cpp new file mode 100644 index 0000000..f6fcbe6 --- /dev/null +++ b/plugins/_core/filetransfer.cpp @@ -0,0 +1,554 @@ +/*************************************************************************** + filetransfer.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "simapi.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "simgui/ballonmsg.h" +#include "icons.h" +#include "unquot.h" +#include "contacts/contact.h" + +#include "filetransfer.h" +#include "core.h" + +using namespace SIM; + +const unsigned MAX_AVERAGE = 40; +const unsigned SHOW_AVERAGE = 5; + +class FileTransferDlgNotify : public FileTransferNotify +{ +public: + FileTransferDlgNotify(FileTransferDlg *dlg); + ~FileTransferDlgNotify(); + void skip(); + void replace(); + void resume(); +protected: + void process(); + void transfer(bool); + void createFile(const QString &name, unsigned size, bool bCanResume); + QString m_name; + QString m_fn; + unsigned m_size; + FileTransferDlg *m_dlg; +}; + +FileTransferDlgNotify::FileTransferDlgNotify(FileTransferDlg *dlg) + : m_dlg (dlg) +{ +} + +FileTransferDlgNotify::~FileTransferDlgNotify() +{ + m_dlg->notifyDestroyed(); +} + +void FileTransferDlgNotify::process() +{ + m_dlg->process(); +} + +void FileTransferDlgNotify::transfer(bool bState) +{ + m_dlg->transfer(bState); +} + +void FileTransferDlgNotify::createFile(const QString &name, unsigned size, bool bCanResume) +{ + m_name = name; + m_size = size; + m_name = m_name.replace('\\', '/'); + + + FileTransfer *ft = m_dlg->m_msg->m_transfer; + int n = m_name.lastIndexOf('/'); + if (n >= 0) + { + QString path; + QString p(m_name.left(n)); + m_fn = m_name.right(m_name.length()-n); + m_fn = m_fn.replace(QRegExp("/"), ""); + + while (!p.isEmpty()) + { + QString pp = getToken(p, '/'); + if (!path.isEmpty()) + path += '/'; + if (pp == "..") + { + QString errMsg = i18n("Bad path: %1") .arg(m_name); + m_dlg->m_msg->setError(errMsg); + ft->setError(); + return; + } + path += pp; + QDir dd(ft->dir() /* + '/' + path */); + QDir d(ft->dir()); + if (dd.exists() || d.mkdir(path)) + continue; + + QString errMsg = i18n("Can't create: %1") .arg(path); + m_dlg->m_msg->setError(errMsg); + ft->setError(); + return; + } + } + m_dlg->m_msg->addFile(m_name, size); + if (m_name.isEmpty() || m_name[(int)(m_name.length() - 1)] == '/') + { + ft->startReceive(0); + return; + } + + QString shortName = m_name; + //m_name = ft->dir() + m_name; Quickfix, noragen + if (m_fn.isEmpty()) + m_fn=m_name; + + m_name = ft->dir() + m_fn; + + if (ft->m_file) + delete ft->m_file; + m_dlg->process(); + ft->m_file = new QFile(m_name); + if (!ft->m_file->exists()) + { + if (ft->m_file->open(QIODevice::WriteOnly)) + { + ft->startReceive(0); + return; + } + } + else switch (ft->overwrite()) + { + case Skip: + skip(); + return; + case Replace: + if (ft->m_file->open(QIODevice::WriteOnly | QIODevice::Truncate)) + { + ft->startReceive(0); + return; + } + break; + case Resume: + if (ft->m_file->open(QIODevice::WriteOnly | QIODevice::Append)) + { + resume(); + return; + } + break; + default: + if (ft->m_file->open(QIODevice::WriteOnly | QIODevice::Append)) + { + QStringList buttons; + QString forAll; + if (ft->files()) + forAll = i18n("For all files"); + buttons.append(i18n("&Replace")); + buttons.append(i18n("&Skip")); + if (bCanResume && (ft->m_file->size() < size)) + buttons.append(i18n("Resu&me")); + m_dlg->m_ask = new BalloonMsg(NULL, quoteString(i18n("File %1 exists") .arg(shortName)), + buttons, m_dlg->lblState, NULL, false, true, 150, forAll); + QObject::connect(m_dlg->m_ask, SIGNAL(action(int, void*)), m_dlg, SLOT(action(int, void*))); + raiseWindow(m_dlg); + m_dlg->m_ask->show(); + return; + } + } + QString errMsg = i18n("Can't create: %1") .arg(m_name); + m_dlg->m_msg->setError(errMsg); + ft->setError(); +} + +void FileTransferDlgNotify::skip() +{ + FileTransfer *ft = m_dlg->m_msg->m_transfer; + delete ft->m_file; + ft->m_file = NULL; + ft->startReceive(NO_FILE); +} + +void FileTransferDlgNotify::replace() +{ + FileTransfer *ft = m_dlg->m_msg->m_transfer; + ft->m_file->close(); + ft->m_file->open(QIODevice::WriteOnly | QIODevice::Truncate); + ft->startReceive(0); +} + +void FileTransferDlgNotify::resume() +{ + FileTransfer *ft = m_dlg->m_msg->m_transfer; + if (ft->m_file->size() < m_size) + { + ft->m_file->seek(ft->m_file->size()); + ft->startReceive(ft->m_file->size()); + return; + } + delete ft->m_file; + ft->m_file = NULL; + ft->startReceive(NO_FILE); + return; +} + +FileTransferDlg::FileTransferDlg(FileMessage *msg) + : QDialog (NULL) + , m_msg (msg) + , m_bTransfer (false) + , m_file (0) + , m_transferTime(0) + , m_displayTime (0) + , m_speed (0) + , m_nAverage (0) + , m_files (0) + , m_bytes (0) + , m_fileSize (0) + , m_totalBytes (0) + , m_totalSize (0) + , m_time (0) + , m_timer (new QTimer(this)) + , m_state (FileTransfer::Unknown) + , m_dir (msg->getFlags() & MESSAGE_RECEIVED ? m_msg->m_transfer->dir() : QString() ) +{ + setupUi(this); + setAttribute(Qt::WA_DeleteOnClose, true); + setWindowIcon(Icon("file")); + setButtonsPict(this); + QString name; + Contact *contact = getContacts()->contact(m_msg->contact()); + if (contact) + { + name = contact->getName(); + name = getToken(name, '/'); + } + setWindowTitle((msg->getFlags() & MESSAGE_RECEIVED) ? + i18n("Receive file from %1") .arg(name) : + i18n("Send file to %1") .arg(name)); + + disableWidget(edtTime); + disableWidget(edtEstimated); + disableWidget(edtSpeed); + btnGo->hide(); + btnGo->setIcon(Icon("file")); + msg->m_transfer->setNotify(new FileTransferDlgNotify(this)); + sldSpeed->setValue(m_msg->m_transfer->speed()); + connect(sldSpeed, SIGNAL(valueChanged(int)), this, SLOT(speedChanged(int))); + + connect(m_timer, SIGNAL(timeout()), this, SLOT(timeout())); + m_timer->start(1000); + printTime(); + + connect(btnCancel, SIGNAL(clicked()), this, SLOT(close())); + chkClose->setChecked(CorePlugin::instance()->value("CloseTransfer").toBool()); + connect(chkClose, SIGNAL(toggled(bool)), this, SLOT(closeToggled(bool))); + connect(btnGo, SIGNAL(clicked()), this, SLOT(goDir())); +} + +FileTransferDlg::~FileTransferDlg() +{ + if (m_msg == NULL) + return; + if (m_msg->m_transfer) + m_msg->m_transfer->setNotify(NULL); + EventMessageCancel(m_msg).process(); +} + +void FileTransferDlg::process() +{ + if (m_msg->m_transfer == NULL) + return; + if (m_msg->m_transfer->state() != m_state || m_msg->m_transfer->file() != m_file) + { + m_state = m_msg->m_transfer->state(); + m_file = m_msg->m_transfer->file(); + QString status; + switch (m_state) + { + case FileTransfer::Listen: + status = i18n("Listen"); + break; + case FileTransfer::Connect: + status = i18n("Connect"); + break; + case FileTransfer::Negotiation: + status = i18n("Negotiation"); + break; + case FileTransfer::Read: + { + m_fn = m_msg->getDescription(); + //const QString *n = it[m_file]; + //if (n) + // m_fn = *n; + status = i18n(QString("Receiving file: %1").arg(m_fn)); + break; + } + case FileTransfer::Write: + m_fn = m_msg->m_transfer->filename(); + status = i18n("Sending file: %1").arg(m_fn); + break; + case FileTransfer::Done: + status = i18n(QString("Transfer done: %1").arg(m_fn)); + edtEstimated->setText("0:00:00"); + if (!m_dir.isEmpty()) + btnGo->show(); + break; + case FileTransfer::Error: + if (!m_msg->getError().isEmpty()) + status = i18n(m_msg->getError()); + break; + default: + break; + } + if (!m_fn.isEmpty()) + { + status += ' '; + status += QDir::convertSeparators(m_fn); + if (m_files > 1) + status += QString(" %1/%2") + .arg(m_file + 1) + .arg(m_msg->m_transfer->files()); + } + lblState->setText(status); + setBars(); + } + calcSpeed(false); + if ((int)m_msg->m_transfer->speed() != sldSpeed->value()) + sldSpeed->setValue(m_msg->m_transfer->speed()); + + if (m_msg->m_transfer->files() == m_files) + return; + + m_files = m_msg->m_transfer->files(); + if (m_files <= 1) + { + if (barFile->isVisible()) + barFile->hide(); + } + else if (!barFile->isVisible()) + barFile->show(); +} + +void FileTransferDlg::transfer(bool bState) +{ + bool bTransfer = m_bTransfer; + m_bTransfer = bState; + if (bState && m_msg->m_transfer) + { + m_transferBytes = m_msg->m_transfer->transferBytes(); + m_transferTime = time(NULL); + } + if (!m_bTransfer && bTransfer) + calcSpeed(true); +} + +void FileTransferDlg::notifyDestroyed() +{ + sldSpeed->hide(); + m_timer->stop(); + btnCancel->setText(i18n("&Close")); + if (m_state == FileTransfer::Done) + { + // EventSent shouldn't be processed here + // Protocol plugin should decide itself when to send it + //EventSent(m_msg).process(); + if (chkClose->isChecked()) + close(); + return; + } + if (!m_msg->getError().isEmpty()) + lblState->setText(i18n(m_msg->getError())); + else + lblState->setText(i18n("Transfer failed")); +} + +void FileTransferDlg::speedChanged(int value) +{ + if (m_msg->m_transfer) + m_msg->m_transfer->setSpeed(value); +} + +void FileTransferDlg::timeout() +{ + m_time++; + printTime(); + calcSpeed(false); + setBars(); +} + +void FileTransferDlg::setBars() +{ + if (m_msg->m_transfer == NULL) + return; + if (m_totalBytes != m_msg->m_transfer->totalBytes() + || m_totalSize != m_msg->m_transfer->totalSize()) + { + m_totalBytes = m_msg->m_transfer->totalBytes(); + m_totalSize = m_msg->m_transfer->totalSize(); + setProgress(barTotal, m_totalBytes, m_totalSize); + } + if (m_files <= 1 || + m_fileSize == m_msg->m_transfer->fileSize() && + m_bytes == m_msg->m_transfer->bytes() ) + return; + + m_fileSize = m_msg->m_transfer->fileSize(); + m_bytes = m_msg->m_transfer->bytes(); + setProgress(barFile, m_bytes, m_fileSize); +} + +void FileTransferDlg::setProgress(QProgressBar *bar, unsigned bytes, unsigned size) +{ + while (size > 0x1000000) + { + size = size >> 1; + bytes = bytes >> 1; + } + if (size == 0) + { + bar->setValue(0); + return; + } + bar->setValue(bytes * 100 / size); +} + +void FileTransferDlg::calcSpeed(bool bTransfer) +{ + if (!m_bTransfer && !bTransfer) + return; + time_t now = time(NULL); + if ((unsigned)now == m_transferTime && !bTransfer) + return; + if (m_nAverage < MAX_AVERAGE) + m_nAverage++; + m_speed = (m_speed * (m_nAverage - 1) + m_msg->m_transfer->transferBytes() - m_transferBytes) / m_nAverage; + if ((unsigned)now == m_displayTime) + return; + m_transferBytes = m_msg->m_transfer->transferBytes(); + m_transferTime = now; + m_displayTime = now; + unsigned n_speed = 0; + double speed = m_speed; + if (speed >= 1024) + { + speed = speed / 1024; + n_speed++; + } + if (m_nAverage < SHOW_AVERAGE) + return; + if (speed == 0) + { + edtEstimated->setText(""); + edtSpeed->setText(i18n("Stalled")); + return; + } + QString speedText; + if (speed >= 100) + speedText = QString::number((unsigned)speed); + else + speedText = QString::number(speed, 'f', 3); + speedText += ' '; + switch (n_speed) + { + case 1: + speedText += i18n("Kb/s"); + break; + case 2: + speedText += i18n("Mb/s"); + break; + default: + speedText += i18n("B/s"); + } + if (edtSpeed->text() != speedText) + edtSpeed->setText(speedText); + unsigned estimate = (m_msg->m_transfer->totalSize() - m_msg->m_transfer->totalBytes()) / m_speed; + unsigned m = estimate / 60; + unsigned h = m / 60; + m = m % 60; + char b[64]; + sprintf(b, "%u:%02u:%02u", h, m, estimate % 60); + edtEstimated->setText(b); +} + +void FileTransferDlg::printTime() +{ + unsigned m = m_time / 60; + unsigned h = m / 60; + m = m % 60; + char b[64]; + sprintf(b, "%u:%02u:%02u", h, m, m_time % 60); + edtTime->setText(b); +} + +void FileTransferDlg::closeToggled(bool bState) +{ + CorePlugin::instance()->setValue("CloseTransfer", bState); +} + +void FileTransferDlg::action(int nAct, void*) +{ + if(!m_msg->m_transfer) + return; + FileTransferDlgNotify *notify = static_cast(m_msg->m_transfer->notify()); + FileTransfer *ft = m_msg->m_transfer; + switch (nAct) + { + case 1: + notify->skip(); + if (m_ask->isChecked()) + ft->setOverwrite(Skip); + break; + case 2: + notify->resume(); + if (m_ask->isChecked()) + ft->setOverwrite(Resume); + break; + default: + notify->replace(); + if (m_ask->isChecked()) + ft->setOverwrite(Replace); + break; + } +} + +void FileTransferDlg::goDir() +{ + if (m_dir.isEmpty()) + return; + QString path = QString("file:") + m_dir; + /* Now replace spaces with %20 so the path isn't truncated + are there any other separators we need to care of ?*/ + //path.replace(' ',"%20"); + + EventGoURL e(path); + e.process(); +} diff --git a/plugins/_core/filetransfer.h b/plugins/_core/filetransfer.h new file mode 100644 index 0000000..e4c8c86 --- /dev/null +++ b/plugins/_core/filetransfer.h @@ -0,0 +1,71 @@ +/*************************************************************************** + filetransfer.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _FILETRANSFER_H +#define _FILETRANSFER_H + +#include "message.h" +#include "ui_filetransferbase.h" + +class QTimer; +class QProgressBar; +class BalloonMsg; + +class FileTransferDlg : public QDialog, public Ui::FileTransferBase +{ + Q_OBJECT +public: + FileTransferDlg(SIM::FileMessage*); + ~FileTransferDlg(); +protected slots: + void speedChanged(int); + void closeToggled(bool); + void timeout(); + void action(int, void*); + void goDir(); +protected: + void setProgress(QProgressBar *bar, unsigned bytes, unsigned size); + void process(); + void notifyDestroyed(); + void printTime(); + void transfer(bool); + void calcSpeed(bool); + void setBars(); + SIM::FileMessage *m_msg; + QTimer *m_timer; + unsigned m_time; + unsigned m_file; + bool m_bTransfer; + unsigned m_displayTime; + unsigned m_transferTime; + unsigned m_transferBytes; + unsigned m_speed; + unsigned m_nAverage; + unsigned m_files; + unsigned m_bytes; + unsigned m_fileSize; + unsigned m_totalBytes; + unsigned m_totalSize; + QString m_dir; + QString m_fn; + BalloonMsg *m_ask; + SIM::FileTransfer::State m_state; + friend class FileTransferDlgNotify; +}; + +#endif + diff --git a/plugins/_core/filetransferbase.ui b/plugins/_core/filetransferbase.ui new file mode 100644 index 0000000..eb53aa8 --- /dev/null +++ b/plugins/_core/filetransferbase.ui @@ -0,0 +1,212 @@ + + FileTransferBase + + + + 0 + 0 + 351 + 270 + + + + File transfer + + + + 11 + + + 6 + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + + + false + + + + + + + + 0 + 0 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + Time: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + Estimated time: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + 0 + 0 + + + + + + + + 1 + + + 100 + + + Qt::Horizontal + + + + + + + Speed: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + 0 + 0 + + + + + + + + 6 + + + 0 + + + + + &Go to dir + + + + + + + Close after &transfer + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + &Cancel + + + + + + + + qPixmapFromMimeSource + + btnCancel + sldSpeed + edtTime + edtEstimated + edtSpeed + chkClose + + + + diff --git a/plugins/_core/fontconfigbase.ui b/plugins/_core/fontconfigbase.ui new file mode 100644 index 0000000..e3c6b8f --- /dev/null +++ b/plugins/_core/fontconfigbase.ui @@ -0,0 +1,122 @@ + + + + + FontConfigBase + + + + 0 + 0 + 377 + 233 + + + + Form1 + + + + 11 + + + 6 + + + + + Use &system fonts + + + + + + + Base font: + + + Qt::AlignVCenter|Qt::AlignLeft + + + false + + + + + + + + + + Menu font: + + + false + + + + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Vertical + + + + + + + + FontEdit + QWidget +
simgui/fontedit.h
+ + -1 + -1 + + 0 + + 7 + 5 + + image0 +
+ + QWidget + QWidget +
QWidget
+ + -1 + -1 + + 0 + + 5 + 5 + + image1 + + text + +
+
+ + + 789c6dd2c10ac2300c00d07bbf2234b7229d1ddec44f503c0ae2a154410f53d0ed20e2bf6bdb656dd6861dd23d9a66591b0587fd1654235ebded6f0edcd53e419d87ae7b1f4f9b8f906d0bfe012317426a70b07bdc2f3ec77f8ed6b89559061a0343d06a124cc105596482585094bc0ae599b04646c9018926491b2205e140c485cace25755c175d0a967b622ff900b8cc9c7d29af594ea722d589167f813aa852ba07d94b9dce296e883fe7bb163f23896753 + + + 789c6dd2c10ac2300c00d07bbf2234b7229d1be245fc04c5a3201e4615f430059d0711ff5ddb2e6bb236ec90eed134cb5a19d8ef36602af5ecdbfeeac05dda0798d3abebde87e3faa374d3807fa0d633a52d38d8de6f679fe33fc776e196f53cd010188256a3600a292882096246517815ca99884606e18044a3a40d91824820924265a7923a2e8bcd05f33db1173e002913175f2a6be6d3294871a2d95fa00e8a94ee017b69d339d90df1e77c57ea072ede6758 + + +
diff --git a/plugins/_core/history.cpp b/plugins/_core/history.cpp new file mode 100644 index 0000000..eb53b44 --- /dev/null +++ b/plugins/_core/history.cpp @@ -0,0 +1,927 @@ +/*************************************************************************** +history.cpp - description +------------------- +begin : Sun Mar 17 2002 +copyright : (C) 2002 by Vladimir Shutoff +email : vovan@shutoff.ru +***************************************************************************/ + +/*************************************************************************** +* * +* 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. * +* * +***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "simapi.h" +#include "buffer.h" +#include "log.h" +#include "contacts/clientdataiterator.h" +#include "contacts/contact.h" +#include "contacts/client.h" + +#include "history.h" +#include "core.h" +#include "msgview.h" + +using namespace std; +using namespace SIM; + +static char HISTORY_PATH[] = "history/"; +static char REMOVED[] = ".removed"; + +const unsigned CUT_BLOCK = 0x4000; +const unsigned LOAD_BLOCK_SIZE = 0x1000; +const unsigned BLOCK_SIZE = 0x4000; +const unsigned TEMP_BASE = 0x80000000; + +unsigned History::s_tempId = TEMP_BASE; +MAP_MSG *History::s_tempMsg = NULL; + +class HistoryFile : public QFile +{ +public: + HistoryFile(const QString &name, unsigned contact); + bool isOpen() { return handle() != -1; } + QString m_name; + unsigned m_contact; + Message *load(unsigned id); +private: + HistoryFile(const HistoryFile&); + void operator = (const HistoryFile&); +}; + +class HistoryFileIterator +{ +public: + HistoryFileIterator(HistoryFile&, unsigned contact); + ~HistoryFileIterator(); + void createMessage(unsigned id, const char *type, Buffer *cfg); + void begin(); + void end(); + void clear(); + Message *operator++(); + Message *operator--(); + Message *message(); + HistoryFile &file; + list msgs; + int m_block; + Message *m_msg; + bool loadBlock(bool bUp); + QString m_filter; +private: + unsigned m_contact; + QTextCodec *m_codec; + HistoryFileIterator(const HistoryFileIterator&); + void operator = (const HistoryFileIterator&); +}; + +static Message *createMessage(unsigned id, const char *type, Buffer *cfg) +{ + if (type == NULL || *type == 0) + return NULL; + Message *msg = CorePlugin::instance()->createMessage(type, cfg); + if (!msg) + return NULL; + + msg->setId(id); + return msg; +} + +HistoryFile::HistoryFile(const QString &file_name, unsigned contact) + : m_name (file_name) + , m_contact (contact) +{ + QString f_name = HISTORY_PATH; + f_name += file_name.isEmpty() ? QString::number(contact) : file_name; + f_name = user_file(f_name); + log(L_DEBUG, "FNAME: %s", f_name.toUtf8().data()); + setFileName(f_name); + QFileInfo fi(*this); + if (!fi.exists()) + // make sure directory exists + makedir(fi.absolutePath() + '/'); + else if (!fi.isFile()) + // FIXME! + log(L_ERROR, "%s is not a file!", qPrintable(fi.filePath())); + QFile bak(fileName().append(REMOVED)); + if (!exists() && bak.exists()) + { + QFileInfo fInfo(fileName()); + fInfo.dir().rename(bak.fileName(), fileName()); + } + open(QIODevice::ReadOnly); +} + +Message *HistoryFile::load(unsigned id) +{ + if (!seek(id)) + return NULL; + Buffer cfg; + cfg = readAll(); + QByteArray type = cfg.getSection(); + Message *msg = CorePlugin::instance()->createMessage(type, &cfg); + if (msg == NULL) + return NULL; + msg->setId(id); + msg->setClient(m_name); + msg->setContact(m_contact); + return msg; +} + +HistoryFileIterator::HistoryFileIterator(HistoryFile &f, unsigned contact) +: file(f) +, m_block(0) +, m_msg(NULL) +, m_contact(contact) +, m_codec(NULL) +{ +} + +HistoryFileIterator::~HistoryFileIterator() +{ + clear(); +} + +void HistoryFileIterator::createMessage(unsigned id, const char *type, Buffer *cfg) +{ + Message m(MessageGeneric, cfg); + QString text = m.data.Text.str(); + if (!m_filter.isEmpty()) + { + if (text.isEmpty()) + { + QByteArray serverText = m.getServerText(); + if (serverText.isEmpty()) + return; + if (m_codec == NULL) + m_codec = getContacts()->getCodec(getContacts()->contact(m_contact)); + text = m_codec->toUnicode(serverText); + } + if (text.isEmpty()) + return; + text = text.toLower(); + if (m.getFlags() & MESSAGE_RICHTEXT) + text = text.replace(QRegExp("<[^>]+>"), " "); + text = text.replace(QRegExp(" +"), " "); + if (text.indexOf(m_filter) < 0) + return; + } + Message *msg = ::createMessage(id, type, cfg); + if (msg) + { + msg->setClient(file.m_name); + msg->setContact(file.m_contact); + msgs.push_back(msg); + } +} + +void HistoryFileIterator::begin() +{ + clear(); + m_block = 0; +} + +void HistoryFileIterator::end() +{ + clear(); + m_block = file.size(); +} + +void HistoryFileIterator::clear() +{ + if (m_msg) + { + delete m_msg; + m_msg = NULL; + } + for (list::iterator it = msgs.begin(); it != msgs.end(); ++it) + delete *it; + msgs.clear(); +} + +Message *HistoryFileIterator::operator ++() +{ + if (m_msg) + { + delete m_msg; + m_msg = NULL; + } + while (msgs.empty()) + if (loadBlock(true)) + break; + if (!msgs.empty()) + { + m_msg = msgs.front(); + msgs.pop_front(); + return m_msg; + } + return NULL; +} + +Message *HistoryFileIterator::operator --() +{ + if (m_msg) + { + delete m_msg; + m_msg = NULL; + } + while (msgs.empty()) + if (loadBlock(false)) + break; + if (msgs.empty()) + return NULL; + + m_msg = msgs.back(); + msgs.pop_back(); + return m_msg; +} + +bool HistoryFileIterator::loadBlock(bool bUp) +{ + unsigned blockEnd = m_block; + if (bUp && !file.seek(m_block)) + { + clear(); + return true; + } + Buffer config; + for (;;) + { + int block = m_block; + if (bUp) + { + if (blockEnd >= file.size()) + return true; + blockEnd += BLOCK_SIZE; + unsigned size = config.size(); + config.resize(BLOCK_SIZE); + int readn = file.read((char*)config.data(size), BLOCK_SIZE); + if (readn < 0) + { + log(L_WARN, "Can't read %s", qPrintable(file.fileName())); + clear(); + return true; + } + config.resize(size + readn); + } + else + { + if (m_block == 0) + return true; + block -= BLOCK_SIZE; + if (block < 0) + block = 0; + if (!file.seek(block)) + { + m_block = 0; + clear(); + return true; + } + unsigned size = m_block - block; + m_block = block; + config.resize(size); + if ((unsigned)file.read(config.data(), size) != size) + { + log(L_WARN, "Can't read %s", qPrintable(file.fileName())); + clear(); + return true; + } + config.setWritePos(0); + } + QByteArray type = config.getSection(!bUp && (m_block != 0)); + if (type.isEmpty() || + ((config.writePos() == (unsigned)config.size()) && + (file.pos() < file.size())) + ) + continue; + unsigned id = m_block; + if (!bUp) + m_block += config.startSection(); + createMessage(id + config.startSection(), type, &config); + unsigned pos = config.writePos(); + for (;;) + { + type = config.getSection(); + if ((!bUp) && (id + config.writePos() > blockEnd) || + type.isEmpty() || + (((config.writePos() == (unsigned)config.size()) && + (file.pos() < file.size())))) + break; + createMessage(id + config.startSection(), type, &config); + pos = config.writePos(); + } + if (bUp) + m_block += pos; + break; + } + return false; +} + +Message *HistoryFileIterator::message() +{ + return m_msg; +} + +History::History(unsigned id) + : m_contact (id) +{ + Contact *contact = getContacts()->contact(id); + if (contact == NULL) + return; + HistoryFile *f = new HistoryFile(QString::number(id), id); + if (f->isOpen()) + files.push_back(f); + else + delete f; + void *data; + ClientDataIterator it(contact->clientData); + QStringList fnames; + while ((data = ++it) != NULL) + { + QString name = it.client()->dataName(data); + if(fnames.contains(name)) + continue; + fnames.append(name); + HistoryFile *f = new HistoryFile(name, id); + f->m_name = name; + if (f->isOpen()) + files.push_back(f); + else delete f; + } +} + +History::~History() +{ + for (list::iterator it = files.begin(); it != files.end(); ++it) + delete *it; +} + +HistoryIterator::HistoryIterator(unsigned contact_id) + : m_bUp (false) + , m_bDown (false) + , m_temp_id (0) + , m_history (contact_id) + , m_it (NULL) +{ + for (list::iterator it = m_history.files.begin(); it != m_history.files.end(); ++it) + iters.push_back(new HistoryFileIterator(**it, contact_id)); +} + +HistoryIterator::~HistoryIterator() +{ + for (list::iterator it = iters.begin(); it != iters.end(); ++it) + delete *it; +} + +void HistoryIterator::begin() +{ + for (list::iterator it = iters.begin(); it != iters.end(); ++it) + (*it)->begin(); + m_temp_id = 0; + m_bUp = m_bDown = false; +} + +void HistoryIterator::end() +{ + for (list::iterator it = iters.begin(); it != iters.end(); ++it) + (*it)->end(); + m_temp_id = 0xFFFFFFFF; + m_bUp = m_bDown = false; +} + +QString HistoryIterator::state() +{ + QString res; + for (list::iterator it = iters.begin(); it != iters.end(); ++it) + { + if (!res.isEmpty()) + res += ';'; + Message *msg = (*it)->message(); + res += msg ? QString::number(msg->id()) : QString::number((*it)->m_block); + res += ','; + res += (*it)->file.m_name; + } + if (!res.isEmpty()) + res += ';'; + res += QString::number(m_temp_id); + res += ",temp"; + return res; +} + +void HistoryIterator::setState(const QString &str) +{ + QString s = str; + while (!s.isEmpty()) + { + QString item = getToken(s, ';'); + unsigned pos = getToken(item, ',').toUInt(); + if (item == "temp") + { + m_temp_id = item.toULong(); + continue; + } + for (list::iterator it = iters.begin(); it != iters.end(); ++it) + { + if ((*it)->file.m_name == item) + { + (*it)->clear(); + (*it)->m_block = pos; + break; + } + } + } + m_bUp = m_bDown = false; +} + +Message *HistoryIterator::operator ++() +{ + if (!m_bUp) + { + m_bUp = true; + m_bDown = false; + for (list::iterator it = iters.begin(); it != iters.end(); ++it) + { + (*it)->clear(); + ++(**it); + } + m_it = NULL; + } + if (m_it) + ++(*m_it); + m_it = NULL; + Message *msg = NULL; + for (list::iterator it = iters.begin(); it != iters.end(); ++it) + { + Message *m = (**it).message(); + if (m == NULL || + (msg != NULL && msg->getTime() <= m->getTime())) + continue; + + msg = m; + m_it = *it; + } + if (msg) + return msg; + if (History::s_tempMsg) + { + MAP_MSG::iterator itm; + for (itm = History::s_tempMsg->begin(); itm != History::s_tempMsg->end(); ++itm) + if (itm->first > m_temp_id) + break; + for (; itm != History::s_tempMsg->end(); ++itm) + { + if (itm->second.contact != m_history.m_contact) + continue; + + m_temp_id = (*itm).first; + Message *msg = History::load(m_temp_id, QString::null, m_history.m_contact); + if (msg) + return msg; + } + m_temp_id = 0xFFFFFFFF; + } + return NULL; +} + +Message *HistoryIterator::operator --() +{ + if (m_temp_id && History::s_tempMsg) + { + MAP_MSG::iterator itm = History::s_tempMsg->end(); + if (itm != History::s_tempMsg->begin()) + { + for (--itm;;--itm) + { + if (itm->first < m_temp_id) + break; + if (itm != History::s_tempMsg->begin()) + continue; + + m_temp_id = 0; + break; + } + if (m_temp_id) + { + for (;; --itm) + { + if (itm->second.contact == m_history.m_contact) + { + m_temp_id = itm->first; + Message *msg = History::load(m_temp_id, QString::null, m_history.m_contact); + if (msg) + return msg; + } + if (itm == History::s_tempMsg->begin()) + break; + } + } + } + } + m_temp_id = 0; + if (!m_bDown) + { + m_bDown = true; + m_bUp = false; + for (list::iterator it = iters.begin(); it != iters.end(); ++it) + { + (*it)->clear(); + --(**it); + } + m_it = NULL; + } + if (m_it) + --(*m_it); + m_it = NULL; + Message *msg = NULL; + for (list::iterator it = iters.begin(); it != iters.end(); ++it) + { + Message *m = (**it).message(); + if (m == NULL || + (msg != NULL && msg->getTime() > m->getTime())) + continue; + msg = m; + m_it = *it; + } + return msg; +} + +void HistoryIterator::setFilter(const QString &filter) +{ + QString f = filter.toLower(); + f = f.replace(QRegExp(" +"), " "); + for (list::iterator it = iters.begin(); it != iters.end(); ++it) + (*it)->m_filter = f; +} + +Message *History::load(unsigned id, const QString &client, unsigned contact) +{ + if (id >= TEMP_BASE) + { + if (s_tempMsg == NULL) + return NULL; + MAP_MSG::iterator it = s_tempMsg->find(id); + if (it == s_tempMsg->end()) + return NULL; + msg_save &ms = it->second; + Buffer config; + config = ms.msg; + config.setWritePos(0); + QByteArray type = config.getSection(); + Message *msg = createMessage(id, type, &config); + if (!msg) + return NULL; + msg->setClient(ms.client); + msg->setContact(ms.contact); + msg->setFlags(msg->getFlags() | MESSAGE_TEMP); + return msg; + } + HistoryFile f(client, contact); + if (!f.isOpen()) + return NULL; + return f.load(id); +} + +void History::add(Message *msg, const QString &type) +{ + QByteArray line = "["; + line += type.toUtf8(); + line += "]\n"; + line += msg->save(); + line += '\n'; + + if (msg->getFlags() & MESSAGE_TEMP) + { + if (s_tempMsg == NULL) + s_tempMsg = new MAP_MSG; + msg_save ms; + ms.msg = line; + ms.contact = msg->contact(); + ms.client = msg->client(); + s_tempMsg->insert(MAP_MSG::value_type(++s_tempId, ms)); + msg->setId(s_tempId); + return; + } + + if (!line.isEmpty() && line.at(line.length() - 1) != '\n') + line += '\n'; + + QString name = msg->client(); + if (name.isEmpty()) + name = QString::number(msg->contact()); + QString f_name = QString(HISTORY_PATH).append(name); + + f_name = user_file(f_name); + + Contact *contact = getContacts()->contact(msg->contact()); + SIM::PropertyHubPtr data; + if (contact) + data = contact->getUserData("history"); + if (!data.isNull() && data->value("CutSize").toBool()) + { + QFileInfo fInfo(f_name); + if (fInfo.exists() && (fInfo.size() >= data->value("MaxSize").toInt() * 0x100000 + CUT_BLOCK)) + { + int pos = fInfo.size() - data->value("MaxSize").toUInt() * 0x100000 + line.size(); + if (pos < 0) + pos = 0; + del(f_name, msg->contact(), pos, false); + } + } + + QFile f(f_name); + if (!f.open(QIODevice::ReadWrite | QIODevice::Append)) + { + log(L_ERROR, "Can't open %s", qPrintable(f_name)); + return; + } + qint64 id = f.pos(); + f.write(line); + + msg->setId(id); +} + +void History::del(Message *msg) +{ + QString name = msg->client(); + if (name.isEmpty()) + name = QString::number(msg->contact()); + del(name, msg->contact(), msg->id(), true); +} + +void History::rewrite(Message *msg) +{ + QString name = msg->client(); + if (name.isEmpty()) + name = QString::number(msg->contact()); + del(name, msg->contact(), msg->id(), true, msg); +} + +typedef map CLIENTS_MAP; + +void History::cut(Message *msg, unsigned contact_id, unsigned date) +{ + QString client; + if (msg) + client = msg->client(); + CLIENTS_MAP clients; + { + HistoryIterator it(msg ? msg->contact() : contact_id); + Message *m; + while ((m = ++it) != NULL) + { + if (date && m->getTime() > date) + break; + CLIENTS_MAP::iterator itm = clients.find(m->client()); + if (itm == clients.end()) + clients.insert(CLIENTS_MAP::value_type(m->client(), m->id())); + else + itm->second = m->id(); + if (!msg || + client != m->client() || + m->id() < msg->id()) + continue; + + break; + } + } + for (CLIENTS_MAP::iterator it = clients.begin(); it != clients.end(); ++it) + del(it->first.str(), msg ? msg->contact() : contact_id, it->second + 1, false); +} + +void History::del(const QString &name, unsigned contact, unsigned id, bool bCopy, Message *msg) +{ + QFile f(user_file(QString(HISTORY_PATH).append(name))); + if (!f.open(QIODevice::ReadOnly)) + { + log(L_ERROR, "Can't open %s", qPrintable(f.fileName())); + return; + } + QFile t(f.fileName() + '~'); + if (!t.open(QIODevice::ReadWrite | QIODevice::Truncate)) + { + log(L_ERROR, "Can't open %s", qPrintable(t.fileName())); + return; + } + unsigned tail = id; + for (; tail > 0; ) + { + char b[LOAD_BLOCK_SIZE]; + int size = sizeof(b); + if (tail < (unsigned)size) + size = tail; + size = f.read(b, size); + if (size == -1) + { + log(L_ERROR, "Read history error"); + return; + } + if (bCopy && t.write(b, size) != size) + { + log(L_ERROR, "Write history error"); + return; + } + tail -= size; + } + Buffer config; + unsigned skip_start = id; + for (;;) + { + unsigned size = config.size(); + config.resize(LOAD_BLOCK_SIZE); + int readn = f.read(config.data(size), LOAD_BLOCK_SIZE); + if (readn < 0) + { + log(L_ERROR, "Read history error"); + return; + } + config.resize(size + readn); + QByteArray section = config.getSection(); + if (section.isEmpty()) + { + if (readn == 0) + return; + continue; + } + if (config.writePos() == (unsigned)config.size() && + readn != 0) + continue; + + break; + } + if (config.startSection()) + { + skip_start += config.startSection(); + if ((unsigned)t.write(config.data(), config.startSection()) != config.startSection()) + { + log(L_ERROR, "Write history error"); + return; + } + } + unsigned skip_size = config.writePos() - config.startSection(); + QByteArray line = "\n"; + if (msg) + { + line += msg->save(); + line += '\n'; + skip_start++; + } + int size = line.length(); + int written = t.write(line, size); + if (written != size) + { + log(L_DEBUG, "Write history error"); + return; + } + skip_size -= line.length(); + if (config.writePos() < (unsigned)config.size()) + { + size = config.size() - config.writePos(); + written = t.write(config.data(config.writePos()), size); + if (written != size) + { + log(L_DEBUG, "Write history error"); + return; + } + } + tail = f.size() - f.pos(); + for (; tail > 0; ) + { + char b[2048]; + size = f.read(b, sizeof(b)); + if (size == -1) + { + log(L_ERROR, "Read history error"); + return; + } + written = t.write(b, size); + if (written != size) + { + log(L_DEBUG, "Write history error"); + return; + } + tail -= size; + } + f.close(); + t.close(); + QFileInfo fInfo(f.fileName()); + QFileInfo tInfo(t.fileName()); + fInfo.dir().remove(fInfo.fileName()); + if (!tInfo.dir().rename(tInfo.fileName(), fInfo.fileName())) + { + log(L_ERROR, "Can't rename file %s to %s", qPrintable(fInfo.fileName()), qPrintable(tInfo.fileName())); + return; + } + CutHistory ch; + ch.contact = contact; + ch.client = name; + if (bCopy) + { + ch.from = skip_start; + ch.size = skip_size; + } + else + { + ch.from = skip_start; + ch.size = skip_start + skip_size; + } + EventCutHistory(&ch).process(); +} + +void History::del(unsigned msg_id) +{ + if (s_tempMsg == NULL) + return; + MAP_MSG::iterator it = s_tempMsg->find(msg_id); + if (it == s_tempMsg->end()) + { + log(L_WARN, "Message %X for remove not found", msg_id); + return; + } + s_tempMsg->erase(it); +} + +void History::remove(Contact *contact) +{ + bool bRename = (contact->getFlags() & CONTACT_NOREMOVE_HISTORY); + QString name = QString::number(contact->id()); + QString f_name = HISTORY_PATH; + f_name += name; + name = user_file(f_name); + QFile f(name); + f.remove(); + + void *data; + ClientDataIterator it(contact->clientData); + while ((data = ++it) != NULL) + { + name = it.client()->dataName(data); + f_name = HISTORY_PATH; + f_name += name; + name = user_file(f_name); + QFile f(name); + if (!f.exists()) + continue; + if (bRename) + { + QFileInfo fInfo(f.fileName()); + fInfo.dir().rename(fInfo.fileName(), QString(fInfo.fileName()).append(REMOVED)); + continue; + } + f.remove(); + } +} + +bool History::save(unsigned id, const QString& file_name, bool bAppend) +{ + QFile f(file_name); + QIODevice::OpenMode mode = QIODevice::WriteOnly | QIODevice::Text; + if (bAppend) + mode |= QIODevice::Append; + if(f.open(mode)) + { + QTextStream stream(&f); + HistoryIterator it(id); + it.begin(); + const QString owner = getContacts()->owner()->getName(), + contact = getContacts()->contact(id)->getName(); + for (;;) + { + Message *msg = ++it; + if (msg == NULL) + break; + QDateTime t = QDateTime::fromTime_t(msg->getTime()); + QString time; + time = t.toString("hh:mm:ss"); + stream << (msg->getFlags() & MESSAGE_RECEIVED ? contact : owner) + << " (" << formatDate(t.date()) << " " << time << "):\n" + << msg->getPlainText() + << "\n\n"; + } + const QFile::FileError status = f.error(); + const QString errorMessage = f.errorString(); + f.close(); + if (status != QFile::NoError) + { + log(L_ERROR, "I/O error during write to file %s : %s", qPrintable(file_name), qPrintable(errorMessage)); + return false; + } + return true; + } + //else deleted: unreachable Code + log(L_ERROR, "Can't open %s for writing", qPrintable(file_name)); + return false; + +} diff --git a/plugins/_core/history.h b/plugins/_core/history.h new file mode 100644 index 0000000..82bf405 --- /dev/null +++ b/plugins/_core/history.h @@ -0,0 +1,89 @@ +/*************************************************************************** + history.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _HISTORY_H +#define _HISTORY_H + +#include +#include +#include +#include + +#include "message.h" + +class CorePlugin; +class QFile; + +class HistoryFile; +class HistoryFileIterator; + +using namespace std; + +struct msg_save +{ + QByteArray msg; + QString client; + unsigned contact; +}; + +typedef map MAP_MSG; + +class History +{ +public: + History(unsigned contact_id); + ~History(); + static void add(SIM::Message*, const QString &type); + static void del(SIM::Message*); + static void rewrite(SIM::Message*); + static void cut(SIM::Message*, unsigned contact_id, unsigned date); + static void del(unsigned msg_id); + static void remove(SIM::Contact *contact); + static bool save(unsigned id, const QString& file_name, bool bAppend = false); + static SIM::Message *load(unsigned id, const QString &client, unsigned contact); +protected: + static void del(const QString &name, unsigned contact, unsigned id, bool bCopy, SIM::Message *msg=NULL); + static unsigned s_tempId; + static MAP_MSG *s_tempMsg; + unsigned m_contact; + list files; + friend class HistoryIterator; +}; + +class HistoryIterator +{ +public: + HistoryIterator(unsigned contact_id); + ~HistoryIterator(); + SIM::Message *operator++(); + SIM::Message *operator--(); + void begin(); + void end(); + QString state(); + void setState(const QString &); + void setFilter(const QString &filter); +protected: + bool m_bUp; + bool m_bDown; + unsigned m_temp_id; + History m_history; + HistoryFileIterator *m_it; + list iters; +}; + +#endif + diff --git a/plugins/_core/historycfg.cpp b/plugins/_core/historycfg.cpp new file mode 100644 index 0000000..bb3abab --- /dev/null +++ b/plugins/_core/historycfg.cpp @@ -0,0 +1,748 @@ +/*************************************************************************** +historycfg.cpp - description +------------------- +begin : Sun Mar 17 2002 +copyright : (C) 2002 by Vladimir Shutoff +email : vovan@shutoff.ru +***************************************************************************/ + +/*************************************************************************** +* * +* 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. * +* * +***************************************************************************/ + +#include "simapi.h" + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef USE_KDE +# include +# include +# include +#endif + + +#include "log.h" +#include "unquot.h" +#include "xsl.h" + +#include "historycfg.h" +#include "core.h" +#include "msgview.h" + +#include "simgui/ballonmsg.h" +#include "simgui/textshow.h" +#include "contacts/contact.h" +#include "contacts/client.h" + +#ifdef __OS2__ +#undef COMMENT +#endif + +static char STYLES[] = "styles/"; +static char EXT[] = ".xsl"; + +//#undef QTextEdit + +using namespace std; +using namespace SIM; + +class XmlHighlighter : public QSyntaxHighlighter +{ +public: + XmlHighlighter(QTextEdit *textEdit) : QSyntaxHighlighter(textEdit) {} + virtual int highlightParagraph( const QString &text, int endStateOfLastPara ) ; + void highlightBlock( const QString &text ) //FIXME whole Method!!! + { + QTextCharFormat myClassFormat; + myClassFormat.setFontWeight(QFont::Bold); + myClassFormat.setForeground(Qt::darkMagenta); + QString pattern = "\\bMy[A-Za-z]+\\b"; + + QRegExp expression(pattern); + int index = text.indexOf(expression); + while (index >= 0) + { + int length = expression.matchedLength(); + setFormat(index, length, myClassFormat); + index = text.indexOf(expression, index + length); + } + } +}; + +const int TEXT = -2; +const int COMMENT = 1; +const int TAG = 2; +const int XML_TAG = 3; +const int XSL_TAG = 4; +const int STRING = 5; +const int XML_STRING = 6; +const int XSL_STRING = 7; + +const unsigned COLOR_COMMENT = 0x808080; +const unsigned COLOR_TAG = 0x008000; +const unsigned COLOR_STRING = 0x000080; +const unsigned COLOR_XSL_TAG = 0x800000; +const unsigned COLOR_XML_TAG = 0x808080; + +int XmlHighlighter::highlightParagraph(const QString &s, int state) +{ + int pos = 0; + for (; pos < (int)(s.length());) + { + int n = pos; + int n1; + QColor c; + switch (state) + { + case TEXT: + n = s.indexOf('<', pos); + if (n == -1) + n = s.length(); + else + { + state = TAG; + if (s.mid(n + 1, 2) == "--") + state = COMMENT; + else if (s.mid(n + 1, 4) == "?xml") + state = XML_TAG; + else if (s.mid(n + 1, 4) == "xsl:") + state = XSL_TAG; + else if (s.mid(n + 1, 5) == "/xsl:") + state = XSL_TAG; + } + break; + case COMMENT: + n = s.indexOf("-->", pos); + if (n == -1) + n = s.length(); + else + state = TEXT; + c = QColor(COLOR_COMMENT); + break; + case TAG: + case XSL_TAG: + case XML_TAG: + switch (state) + { + case XSL_TAG: + c = QColor(COLOR_XSL_TAG); + break; + case XML_TAG: + c = QColor(COLOR_XML_TAG); + break; + default: + c = QColor(COLOR_TAG); + } + n = s.indexOf('>', pos); + n1 = s.indexOf('\"', pos); + if (n >= 0 && (n < n1 || n1 == -1)) + { + state = TEXT; + n++; + } + else if (n1 >= 0 && (n1 < n || n == -1)) + { + switch (state) + { + case XSL_TAG: + state = XSL_STRING; + break; + case XML_TAG: + state = XML_STRING; + break; + default: + state = STRING; + } + n = n1; + } + else n = s.length(); + break; + case STRING: + case XML_STRING: + case XSL_STRING: + n = s.indexOf('\"', pos + 1); + if (n >= 0) + { + switch (state) + { + case XML_STRING: + state = XML_TAG; + break; + case XSL_STRING: + state = XSL_TAG; + break; + default: + state = TAG; + } + n++; + } + else + n = s.length(); + c = QColor(COLOR_STRING); + break; + } + if (n - pos > 0) + setFormat(pos, n - pos, c); + pos = n; + } + return state; +} + + +HistoryConfig::HistoryConfig(QWidget *parent) +: QWidget (parent) +, m_cur (-1) +, m_bDirty (false) +{ + setupUi(this); + chkOwn->setChecked(CorePlugin::instance()->value("OwnColors").toBool()); + chkSmile->setChecked(CorePlugin::instance()->value("UseSmiles").toBool()); + chkExtViewer->setChecked(CorePlugin::instance()->value("UseExtViewer").toBool()); + edtExtViewer->setText(CorePlugin::instance()->value("ExtViewer").toString()); + chkAvatar->setChecked(CorePlugin::instance()->value("ShowAvatarInHistory").toBool()); + cmbPage->setEditable(true); + QLineEdit *edit = cmbPage->lineEdit(); + edit->setValidator(new QIntValidator(1, 10000, edit)); + edit->setText(QString::number(CorePlugin::instance()->value("HistoryPage").toUInt())); + QString str1 = i18n("Show %1 messages per page"); + QString str2; + int n = str1.indexOf("%1"); + if (n >= 0) + { + str2 = str1.mid(n + 2); + str1 = str1.left(n); + } + lblPage1->setText(str1); + lblPage2->setText(str2); + //edtStyle->setWordWrap(QTextEdit::NoWrap); + edtStyle->setWordWrapMode(QTextOption::NoWrap); + highlighter = new XmlHighlighter(edtStyle); + addStyles(user_file(STYLES), true); + str1 = i18n("Use external viewer"); + chkExtViewer->setText(str1); + str1 = i18n("Show user avatar"); + chkAvatar->setText(str1); +#ifdef USE_KDE + QStringList lst = KGlobal::dirs()->findDirs("data", "sim"); + for (QStringList::Iterator it = lst.begin(); it != lst.end(); ++it){ + QFile fi(*it + STYLES); + if (!fi.exists()) + continue; + addStyles(fi.name(), false); + } +#else + addStyles(app_file(STYLES), false); +#endif + fillCombo(CorePlugin::instance()->value("HistoryStyle").toString()); + connect(cmbStyle, SIGNAL(activated(int)), this, SLOT(styleSelected(int))); + connect(btnCopy, SIGNAL(clicked()), this, SLOT(copy())); + connect(btnRename, SIGNAL(clicked()), this, SLOT(rename())); + connect(btnDelete, SIGNAL(clicked()), this, SLOT(del())); + connect(tabStyle, SIGNAL(currentChanged(QWidget*)), this, SLOT(viewChanged(QWidget*))); + connect(edtStyle, SIGNAL(textChanged()), this, SLOT(textChanged())); + connect(chkOwn, SIGNAL(toggled(bool)), this, SLOT(toggled(bool))); + connect(chkSmile, SIGNAL(toggled(bool)), this, SLOT(toggled(bool))); + connect(chkDays, SIGNAL(toggled(bool)), this, SLOT(toggledDays(bool))); + connect(chkSize, SIGNAL(toggled(bool)), this, SLOT(toggledSize(bool))); + connect(chkExtViewer, SIGNAL(toggled(bool)), this, SLOT(toggledExtViewer(bool))); + SIM::PropertyHubPtr data = getContacts()->getUserData("history"); + chkDays->setChecked(data->value("CutDays").toBool()); + chkSize->setChecked(data->value("CutSize").toBool()); + edtDays->setValue(data->value("Days").toUInt()); + edtSize->setValue(data->value("MaxSize").toUInt()); + toggledDays(chkDays->isChecked()); + toggledSize(chkSize->isChecked()); + toggledExtViewer(chkExtViewer->isChecked()); +} + +HistoryConfig::~HistoryConfig() +{ + delete highlighter; +} + +static char BACKUP_SUFFIX[] = "~"; + +void HistoryConfig::apply() +{ + bool bChanged = false; + int idxStyle = cmbStyle->currentIndex(); + if (tabStyle->currentWidget() == source && m_bDirty && idxStyle >= 0) + m_styles[idxStyle].text = unquoteText(edtStyle->toHtml()); + for (unsigned i = 0; i < m_styles.size(); i++) + { + if (m_styles[i].text.isEmpty() || !m_styles[i].bCustom) + continue; + if ((int)i == cmbStyle->currentIndex()) + bChanged = true; + QString name = STYLES; + name += m_styles[i].name; + name += EXT; + name = user_file(name); + QFile f(QString(name).append(BACKUP_SUFFIX)); // use backup file for this ... + if (f.open(QIODevice::WriteOnly | QIODevice::Truncate)) + { + QString s; + s = m_styles[i].text; + f.write(s.toUtf8()); + + const QFile::FileError status = f.error(); + const QString errorMessage = f.errorString(); + f.close(); + if (status != QFile::NoError) + { + log(L_ERROR, "IO error writing to file %s : %s", qPrintable(f.fileName()), qPrintable(errorMessage)); + continue; + } + // rename to normal file + QFileInfo fileInfo(f.fileName()); + QString desiredFileName = fileInfo.fileName(); + desiredFileName = desiredFileName.left(desiredFileName.length() - strlen(BACKUP_SUFFIX)); + fileInfo.dir().remove(desiredFileName); + if (fileInfo.dir().rename(fileInfo.fileName(), desiredFileName)) + continue; + + log(L_ERROR, "Can't rename file %s to %s", qPrintable(fileInfo.fileName()), qPrintable(desiredFileName)); + continue; + } + log(L_WARN, "[1]Can't create %s", qPrintable(name)); + } + int cur = cmbStyle->currentIndex(); + if ((cur >= 0) && m_styles.size() && + (m_styles[cur].bChanged || + (m_styles[cur].name != CorePlugin::instance()->value("HistoryStyle").toString()))){ + CorePlugin::instance()->setValue("HistoryStyle", m_styles[cur].name); + bChanged = true; + delete CorePlugin::instance()->historyXSL; + CorePlugin::instance()->historyXSL = new XSL(m_styles[cur].name); + } + + if (chkOwn->isChecked() != CorePlugin::instance()->value("OwnColors").toBool()){ + bChanged = true; + CorePlugin::instance()->setValue("OwnColors", chkOwn->isChecked()); + } + if (chkSmile->isChecked() != CorePlugin::instance()->value("UseSmiles").toBool()){ + bChanged = true; + CorePlugin::instance()->setValue("UseSmiles", chkSmile->isChecked()); + } + if (chkExtViewer->isChecked() != CorePlugin::instance()->value("UseExtViewer").toBool()){ + bChanged = true; + CorePlugin::instance()->setValue("UseExtViewer", chkExtViewer->isChecked()); + } + if (chkAvatar->isChecked() != CorePlugin::instance()->value("ShowAvatarInHistory").toBool()){ + bChanged = true; + CorePlugin::instance()->setValue("ShowAvatarInHistory", chkAvatar->isChecked()); + } + CorePlugin::instance()->setValue("ExtViewer", edtExtViewer->text().toLocal8Bit()); + CorePlugin::instance()->setValue("HistoryPage", (uint)cmbPage->lineEdit()->text().toULong()); + if (bChanged){ + EventHistoryConfig(0).process(); + } + fillPreview(); + SIM::PropertyHubPtr data = getContacts()->getUserData("history"); + data->setValue("CutDays", chkDays->isChecked()); + data->setValue("CutSize", chkSize->isChecked()); + data->setValue("Days", edtDays->text().toUInt()); + data->setValue("MaxSize", edtSize->text().toUInt()); +} + +void HistoryConfig::addStyles(const QString &dir, bool bCustom) +{ + QDir d(dir); + QStringList files = d.entryList(QStringList("*.xsl"), QDir::Files, QDir::Name); + for (QStringList::Iterator it = files.begin(); it != files.end(); ++it){ + QString name = *it; + int n = name.lastIndexOf('.'); + name = name.left(n); + vector::iterator its; + for (its = m_styles.begin(); its != m_styles.end(); ++its){ + if (name == (*its).name) + break; + } + if (its == m_styles.end()){ + StyleDef s; + s.name = name; + s.bCustom = bCustom; + s.bChanged = false; + m_styles.push_back(s); + } + } +} + +void HistoryConfig::toggled(bool) +{ + if (tabStyle->currentWidget() == preview) + fillPreview(); +} + +void HistoryConfig::styleSelected(int n) +{ + if (n == m_cur) + return; + if (m_styles.size() == 0) return; + if (m_bDirty && (m_cur >= 0)) + m_styles[m_cur].text = unquoteText(edtStyle->toHtml()); + m_cur = n; + bool bCustom = m_styles[n].bCustom; + btnRename->setEnabled(bCustom); + btnDelete->setEnabled(bCustom); + edtStyle->setReadOnly(!bCustom); + fillPreview(); + if (tabStyle->currentWidget() == source) + viewChanged(source); +} + +void HistoryConfig::copy() +{ + int cur = cmbStyle->currentIndex(); + if ((cur < 0) || (!m_styles.size())) + return; + QString name = m_styles[cur].name; + QString newName; + QRegExp re("\\.[0-9]+$"); + unsigned next = 0; + for (vector::iterator it = m_styles.begin(); it != m_styles.end(); ++it){ + QString nn = it->name; + int n = nn.indexOf(re); + if (n < 0) + continue; + nn = nn.mid(n + 1); + next = qMax(next, nn.toUInt()); + } + int nn = name.indexOf(re); + if (nn >= 0){ + newName = name.left(nn); + }else{ + newName = name; + } + newName += '.'; + newName += QString::number(next + 1); + QString n; + n = STYLES; + n += name; + n += EXT; + if (m_styles[cur].bCustom){ + n = user_file(n); + }else{ + n = app_file(n); + } + QFile from(n); + if (!from.open(QIODevice::ReadOnly)){ + log(L_WARN, "Can't open %s", qPrintable(n)); + return; + } + n = STYLES; + n += newName; + n += EXT; + n = user_file(n); + QFile to(QString(n).append(BACKUP_SUFFIX)); + if (!to.open(QIODevice::WriteOnly | QIODevice::Truncate)){ + log(L_WARN, "Cam't create %s", qPrintable(n)); + return; + } + QDataStream ds1(&from); + QDataStream ds2(&to); + ds2 << ds1; + from.close(); + + const QFile::FileError status = to.error(); + const QString errorMessage = to.errorString(); + to.close(); + if (status != QFile::NoError) { + log(L_ERROR, "IO error writing to file %s : %s", qPrintable(to.fileName()), qPrintable(errorMessage)); + return; + } + + // rename to normal file + QFileInfo fileInfo(to.fileName()); + QString desiredFileName = fileInfo.fileName(); + desiredFileName = desiredFileName.left(desiredFileName.length() - strlen(BACKUP_SUFFIX)); + fileInfo.dir().remove(desiredFileName); + if (!fileInfo.dir().rename(fileInfo.fileName(), desiredFileName)) { + log(L_ERROR, "Can't rename file %s to %s", qPrintable(fileInfo.fileName()), qPrintable(desiredFileName)); + return; + } + + StyleDef d; + d.name = newName; + d.bCustom = true; + m_styles.push_back(d); + fillCombo(newName); +} + +void HistoryConfig::fillCombo(const QString ¤t) +{ + sort(m_styles.begin(), m_styles.end()); + unsigned cur = 0; + cmbStyle->clear(); + for (unsigned i = 0; i < m_styles.size(); i++){ + QString name = m_styles[i].name; + cmbStyle->insertItem(INT_MAX,name); + if (name == current) + cur = i; + } + cmbStyle->setCurrentIndex(cur); + styleSelected(cur); +} + +void HistoryConfig::del() +{ + int cur = cmbStyle->currentIndex(); + if ((cur < 0) || (!m_styles.size())) + return; + if (!m_styles[cur].bCustom) + return; + BalloonMsg::ask(NULL, i18n("Remove style '%1'?") .arg(m_styles[cur].name), + btnDelete, SLOT(realDelete()), NULL, NULL, this); +} + +void HistoryConfig::realDelete() +{ + int cur = cmbStyle->currentIndex(); + if ((cur < 0) || (!m_styles.size())) + return; + if (!m_styles[cur].bCustom) + return; + QString name = m_styles[cur].name; + vector::iterator it; + for (it = m_styles.begin(); it != m_styles.end(); ++it) + if (cur-- == 0) + break; + m_styles.erase(it); + QString n; + n = STYLES; + n += name; + n += EXT; + n = user_file(n); + QFile::remove(n); + fillCombo(CorePlugin::instance()->value("HistoryStyle").toString()); +} + +void HistoryConfig::rename() +{ + int cur = cmbStyle->currentIndex(); + if ((cur < 0) || (!m_styles.size())) + return; + if (!m_styles[cur].bCustom) + return; + m_edit = cur; + cmbStyle->setEditable(true); + cmbStyle->lineEdit()->setText(m_styles[cur].name); + cmbStyle->lineEdit()->setFocus(); + cmbStyle->lineEdit()->installEventFilter(this); +} + +void HistoryConfig::cancelRename() +{ + cmbStyle->lineEdit()->removeEventFilter(this); + cmbStyle->setEditable(false); +} + +void HistoryConfig::realRename() +{ + QString newName = cmbStyle->lineEdit()->text(); + cmbStyle->lineEdit()->removeEventFilter(this); + cmbStyle->setEditable(false); + if (newName != m_styles[m_edit].name){ + int n = 0; + vector::iterator it; + for (it = m_styles.begin(); it != m_styles.end(); ++it, n++){ + if (it->name == newName){ + if (n < m_edit) + m_edit--; + m_styles.erase(it); + break; + } + } + QString nn; + nn = STYLES; + nn += m_styles[m_edit].name; + nn += EXT; + nn = user_file(nn); + if (m_styles[m_edit].text.isEmpty()){ + QFile f(nn); + if (f.open(QIODevice::ReadOnly)){ + QTextStream ts(&f); + m_styles[m_edit].text = ts.readAll(); + } + } + QFile::remove(nn); + m_styles[m_edit].name = newName; + } + fillCombo(newName); +} + +bool HistoryConfig::eventFilter(QObject *o, QEvent *e) +{ + if(e->type() == QEvent::FocusOut) + { + QTimer::singleShot(0, this, SLOT(realRename())); + } + if (e->type() == QEvent::KeyPress) + { + QKeyEvent *ke = static_cast(e); + switch (ke->key()){ + case Qt::Key_Enter: + case Qt::Key_Return: + QTimer::singleShot(0, this, SLOT(realRename())); + return true; + case Qt::Key_Escape: + QTimer::singleShot(0, this, SLOT(cancelRename())); + return true; + } + } + return QWidget::eventFilter(o, e); +} + +void HistoryConfig::viewChanged(QWidget *w) +{ + int cur = cmbStyle->currentIndex(); + if ((cur < 0) || (!m_styles.size())) + return; + if (w == preview){ + if (!m_styles[cur].bCustom) + return; + if (m_bDirty){ + m_styles[cur].text = unquoteText(edtStyle->toHtml()); + fillPreview(); + } + }else{ + QString xsl; + if (m_styles[cur].text.isEmpty()){ + QString name = STYLES; + name += m_styles[cur].name; + name += EXT; + name = m_styles[cur].bCustom ? user_file(name) : app_file(name); + QFile f(name); + if (f.open(QIODevice::ReadOnly)){ + QTextStream ts(&f); + xsl = ts.readAll(); + }else{ + log(L_WARN, "Can't open %s", qPrintable(name)); + } + }else{ + xsl = m_styles[cur].text; + } + edtStyle->setText(quoteString(xsl)); + QTimer::singleShot(0, this, SLOT(sync())); + } +} + +void HistoryConfig::textChanged() +{ + m_bDirty = true; + int cur = cmbStyle->currentIndex(); + if ((cur < 0) || (!m_styles.size())) + return; + m_styles[cur].bChanged = true; +} + +void HistoryConfig::fillPreview() +{ + m_bDirty = false; + int cur = cmbStyle->currentIndex(); + if ((cur < 0) || (cur >= (int)m_styles.size())) + return; + XSL *xsl = new XSL(m_styles[cur].name); + if (!m_styles[cur].text.isEmpty()) + xsl->setXSL(m_styles[cur].text); + Contact *contact = getContacts()->contact(0, true); + contact->setName("Buddy"); + contact->setFlags(CONTACT_TEMP); + edtPreview->clear(); + edtPreview->setXSL(xsl); + time_t now = time(NULL); + bool saveSmiles = CorePlugin::instance()->value("UseSmiles").toBool(); + bool saveOwn = CorePlugin::instance()->value("OwnColors").toBool(); + CorePlugin::instance()->setValue("UseSmiles", chkSmile->isChecked()); + CorePlugin::instance()->setValue("OwnColors", chkOwn->isChecked()); + Message m1; + m1.setId((unsigned)(-1)); + m1.setFlags(MESSAGE_RECEIVED | MESSAGE_LIST); + m1.setText(i18n("Hi! ;)")); + m1.setTime(now - 360); + m1.setContact(contact->id()); + edtPreview->addMessage(&m1); + Message m2; + m2.setId((unsigned)(-2)); + m2.setText(i18n("Hi!")); + m2.setTime(now - 300); + m2.setContact(contact->id()); + edtPreview->addMessage(&m2); + Message m3; + m3.setId((unsigned)(-3)); + m3.setText(i18n("Colored message")); + m3.setTime(now - 120); + m3.setFlags(MESSAGE_SECURE | MESSAGE_URGENT | MESSAGE_RICHTEXT); + m3.setBackground(0xC0C0C0); + m3.setForeground(0x008000); + m3.setContact(contact->id()); + edtPreview->addMessage(&m3); + Message m4; + m4.setId((unsigned)(-4)); + m4.setText(i18n("New message")); + m4.setFlags(MESSAGE_RECEIVED); + m4.setTime(now - 60); + m4.setContact(contact->id()); + edtPreview->addMessage(&m4, true); + StatusMessage m5; + m5.setId((unsigned)(-5)); + m5.setStatus(STATUS_OFFLINE); + m5.setTime(now); + m5.setContact(contact->id()); + if (getContacts()->nClients()) + m5.setClient((getContacts()->getClient(0)->name() + '.')); + edtPreview->addMessage(&m5); + delete contact; + CorePlugin::instance()->setValue("UseSmiles", saveSmiles); + CorePlugin::instance()->setValue("OwnColors", saveOwn); +} + +void HistoryConfig::toggledDays(bool bState) +{ + lblDays->setEnabled(bState); + lblDays1->setEnabled(bState); + edtDays->setEnabled(bState); +} + +void HistoryConfig::toggledSize(bool bState) +{ + lblSize->setEnabled(bState); + lblSize1->setEnabled(bState); + edtSize->setEnabled(bState); +} + +void HistoryConfig::toggledExtViewer(bool bState) +{ + edtExtViewer->setEnabled(bState); +} + +/* +#ifndef NO_MOC_INCLUDES +#include "historycfg.moc" +#endif +*/ + diff --git a/plugins/_core/historycfg.h b/plugins/_core/historycfg.h new file mode 100644 index 0000000..6c4b77e --- /dev/null +++ b/plugins/_core/historycfg.h @@ -0,0 +1,73 @@ +/*************************************************************************** + historycfg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _HISTORYCFG_H +#define _HISTORYCFG_H + +#include + +#include "simgui/qcolorbutton.h" +#include +#include "ui_historycfgbase.h" + +class CorePlugin; +class QSyntaxHighlighter; + +struct StyleDef +{ + QString name; + QString text; + bool bCustom; + bool bChanged; + bool operator < (const StyleDef &s) const { return name < s.name; } +}; + +class HistoryConfig : public QWidget, public Ui::HistoryConfigBase +{ + Q_OBJECT +public: + HistoryConfig(QWidget *parent); + ~HistoryConfig(); +public slots: + void apply(); + void styleSelected(int); + void copy(); + void rename(); + void del(); + void realDelete(); + void realRename(); + void cancelRename(); + void viewChanged(QWidget*); + void textChanged(); + void toggled(bool); + void toggledDays(bool); + void toggledSize(bool); + void toggledExtViewer(bool); +protected: + void fillPreview(); + bool eventFilter(QObject *o, QEvent *e); + void addStyles(const QString &dir, bool bName); + void fillCombo(const QString ¤t); + bool m_bDirty; + int m_cur; + int m_edit; + std::vector m_styles; + QSyntaxHighlighter* highlighter; +}; + +#endif + diff --git a/plugins/_core/historycfgbase.ui b/plugins/_core/historycfgbase.ui new file mode 100644 index 0000000..16fa904 --- /dev/null +++ b/plugins/_core/historycfgbase.ui @@ -0,0 +1,372 @@ + + + + + HistoryConfigBase + + + + 0 + 0 + 587 + 340 + + + + Form1 + + + + 11 + + + 6 + + + + + + + + + + + + 1000 + + + + + + + Mb + + + false + + + + + + + + + + + + + + 1000 + + + + + + + days + + + false + + + + + + + 0 + + + 6 + + + + + + 7 + 0 + + + + true + + + + + + + &Copy + + + + + + + &Rename + + + + + + + &Delete + + + + + + + + + + &Preview + + + + 11 + + + 6 + + + + + + + + + &Source + + + + 0 + + + 0 + + + + + + + + + + + + Keep history + + + Qt::AlignVCenter|Qt::AlignRight + + + false + + + + + + + Use &own colors and fonts settings + + + + + + + Max history file size + + + Qt::AlignVCenter|Qt::AlignRight + + + false + + + + + + + 0 + + + 6 + + + + + Use external viewer + + + + + + + + 3 + 0 + + + + + + + + + + 0 + + + 6 + + + + + + + + false + + + + + + + + 100 + + + + + 50 + + + + + 20 + + + + + + + + + 7 + 1 + + + + + + + false + + + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Horizontal + + + + + + + Use emotional &icons + + + + + + + Show user avatar + + + + + + + + QWidget + QWidget +
QWidget
+ + -1 + -1 + + 0 + + 5 + 5 + + image0 + + text + +
+ + TextEdit + QWidget +
simgui/textshow.h
+ + -1 + -1 + + 0 + + 7 + 7 + + image1 +
+ + MsgViewBase + QWidget +
msgview.h
+ + -1 + -1 + + 0 + + 7 + 7 + + image1 +
+
+ + chkOwn + chkSmile + chkSize + chkDays + edtSize + edtDays + cmbPage + cmbStyle + btnCopy + btnRename + btnDelete + tabStyle + + + + 789c6dd2c10ac2300c00d07bbf2234b7229d1be245fc04c5a3201e4615f430059d0711ff5ddb2e6bb236ec90eed134cb5a19d8ef36602af5ecdbfeeac05dda0798d3abebde87e3faa374d3807fa0d633a52d38d8de6f679fe33fc776e196f53cd010188256a3600a292882096246517815ca99884606e18044a3a40d91824820924265a7923a2e8bcd05f33db1173e002913175f2a6be6d3294871a2d95fa00e8a94ee017b69d339d90df1e77c57ea072ede6758 + + + 789c6dd2c10ac2300c00d07bbf2234b7229d1ddec44f503c0ae2a154410f53d0ed20e2bf6bdb656dd6861dd23d9a66591b0587fd1654235ebded6f0edcd53e419d87ae7b1f4f9b8f906d0bfe012317426a70b07bdc2f3ec77f8ed6b89559061a0343d06a124cc105596482585094bc0ae599b04646c9018926491b2205e140c485cace25755c175d0a967b622ff900b8cc9c7d29af594ea722d589167f813aa852ba07d94b9dce296e883fe7bb163f23896753 + + +
diff --git a/plugins/_core/historywnd.cpp b/plugins/_core/historywnd.cpp new file mode 100644 index 0000000..f1af2f5 --- /dev/null +++ b/plugins/_core/historywnd.cpp @@ -0,0 +1,464 @@ +/*************************************************************************** +historywnd.cpp - description +------------------- +begin : Sun Mar 17 2002 +copyright : (C) 2002 by Vladimir Shutoff +email : vovan@shutoff.ru +***************************************************************************/ + +/*************************************************************************** +* * +* 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. * +* * +***************************************************************************/ + +#include "simapi.h" + +#include "icons.h" +#include "log.h" + +#include "historywnd.h" +#include "core.h" +#include "msgview.h" +#include "history.h" +#include "contacts/contact.h" +#include "contacts/client.h" +#include "simgui/toolbtn.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef USE_KDE +#include +#define QFileDialog KFileDialog +#else +#include +#endif + +#include + +using namespace SIM; + +class HistoryProgressBar : public QWidget +{ +public: + HistoryProgressBar(QWidget *parent); + void setTotalSteps(unsigned); + void setProgress(unsigned); +protected: + QProgressBar *m_bar; + QHBoxLayout *m_lay; + QLabel *m_label; +}; + +HistoryProgressBar::HistoryProgressBar(QWidget *parent) +: QWidget(parent) +, m_bar (new QProgressBar(this)) +, m_lay (new QHBoxLayout(this)) +, m_label (new QLabel(i18n("Loading"), this)) +{ + m_lay->setSpacing(4); + m_lay->addSpacing(4); + m_lay->addWidget(m_label); + m_lay->addWidget(m_bar); +} + +void HistoryProgressBar::setTotalSteps(unsigned n) +{ + m_bar->setMaximum(n); +} + +void HistoryProgressBar::setProgress(unsigned n) +{ + m_bar->setValue(n); +} + +HistoryWindow::HistoryWindow(unsigned long id) +: m_status(statusBar()) +, m_view(new MsgViewBase(this, NULL, id)) +, m_avatar_bar(NULL) +, m_progress(NULL) +, m_it(NULL) +, m_id(id) +, m_page(0) + +{ + m_history_page_count=CorePlugin::instance()->value("HistoryPage").toUInt(); + + setAttribute(Qt::WA_DeleteOnClose, true); + setWindowIcon(Icon("history")); + setName(); + setCentralWidget(m_view); + + setIconSize(QSize(16,16)); + + EventToolbar eHistoryBar(ToolBarHistory, this); + eHistoryBar.process(); + + m_bar=eHistoryBar.toolBar(); + m_bar->setParam((void*)m_id); //UAAARGH turns my stomach, Fixme + + //restoreToolbar(m_bar, CorePlugin::instance()->data.HistoryBar); + connect(m_bar, SIGNAL(movableChanged(bool)), this, SLOT(toolbarChanged(bool))); + addToolBar(m_bar); + + Command cmdHistory; + cmdHistory->id = CmdHistoryFind; + cmdHistory->param = (void*)m_id; //Fixme ... + EventCommandWidget eHistoryWidget(cmdHistory); + eHistoryWidget.process(); + + CToolCombo *cmbFind = qobject_cast(eHistoryWidget.widget()); + if(cmbFind) + { + const QStringList history = CorePlugin::instance()->value("HistorySearch").toString().split(';'); + cmbFind->addItems(history); + cmbFind->setText(QString()); + } + + m_bDirection = CorePlugin::instance()->value("HistoryDirection").toBool(); + m_bar->checkState(); + m_bar->show(); + + if(CorePlugin::instance()->value("ShowAvatarInHistory").toBool()) + { + unsigned j = 0; + QImage img; + while(j < getContacts()->nClients()) + { + Client *client = getContacts()->getClient(j++); + img = client->userPicture(id); + if (!img.isNull()) + break; + } + + if(!img.isNull()) + { + EventToolbar(ToolBarHistoryAvatar, EventToolbar::eAdd).process(); + EventToolbar e(ToolBarHistoryAvatar, this); + e.process(); + m_avatar_bar = e.toolBar(); + m_avatar_bar->setOrientation(Qt::Vertical); + addToolBar(m_avatar_bar); + + //m_avatar_bar->setHorizontalStretchable(false); + //m_avatar_bar->setVerticalStretchable(false); + m_avatar_bar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + //restoreToolbar(m_avatar_bar, CorePlugin::instance()->data.HistoryAvatarBar); + + Command cmd; + cmd->id = CmdHistoryAvatar; + cmd->bar_id = ToolBarHistoryAvatar; + cmd->bar_grp = 0x2000; + cmd->text = QString::null; + cmd->icon = "empty"; + cmd->flags = BTN_LABEL; + + EventCommandCreate(cmd).process(); + + Command cmdw; + cmdw->id = CmdHistoryAvatar; + EventCommandWidget eWidget(cmdw); + eWidget.process(); + CToolLabel *lblAvatar = qobject_cast(eWidget.widget()); + + if(lblAvatar) + { + lblAvatar->setPixmap(QPixmap::fromImage(img)); + } + m_avatar_bar->checkState(); + m_avatar_bar->show(); + //m_avatar_bar->area()->moveDockWindow(m_avatar_bar, 0); + } + } + + fill(); +} + +HistoryWindow::~HistoryWindow() +{ + delete m_avatar_bar; + delete m_it; + delete m_progress; //?? + delete m_bar; //?? + delete m_view; //?? +} + +void HistoryWindow::setName() +{ + QString name; + Contact *contact = getContacts()->contact(m_id); + if (contact) + name = contact->getName(); + setWindowTitle(i18n("History") + ' ' + name); +} + +bool HistoryWindow::processEvent(Event *e) +{ + switch(e->type()) { +case eEventContact: + { + EventContact *ec = static_cast(e); + Contact *contact = ec->contact(); + if (contact->id() != m_id) + break; + switch(ec->action()) + { + case EventContact::eDeleted: + QTimer::singleShot(0, this, SLOT(close())); + break; + case EventContact::eChanged: + setName(); + break; + default: + break; + } + break; + } +case eEventCheckCommandState: + { + EventCheckCommandState *ecs = static_cast(e); + CommandDef *cmd = ecs->cmd(); + if (cmd->id == CmdHistoryDirection && (unsigned long)(cmd->param) == m_id) + { + cmd->flags &= ~COMMAND_CHECKED; + if (m_bDirection) + cmd->flags |= COMMAND_CHECKED; + return true; + } + if (cmd->id != CmdDeleteMessage && cmd->id != CmdCutHistory || cmd->param != m_view || !m_view->currentMessage()) + return false; + + cmd->flags &= ~COMMAND_CHECKED; + return true; + } +case eEventCommandExec: + { + EventCommandExec *ece = static_cast(e); + CommandDef *cmd = ece->cmd(); + if ((unsigned long)(cmd->param) != m_id) + return false; + if (cmd->id == CmdHistoryDirection) + { + bool bDirection = ((cmd->flags & COMMAND_CHECKED) != 0); + CorePlugin::instance()->setValue("HistoryDirection", bDirection); + if (bDirection != m_bDirection) + { + m_bDirection = bDirection; + m_page = 0; + m_states.clear(); + fill(); + } + return true; + } + if (cmd->id == CmdHistoryNext) + { + if (m_page + 1 < m_states.size()) + { + m_page++; + fill(); + } + return true; + } + if (cmd->id == CmdHistoryPrev) + { + if (m_page > 0) + { + m_page--; + fill(); + } + return true; + } + if (cmd->id == CmdHistorySave) + { + QString str = QFileDialog::getSaveFileName(this, QString::null, QString::null, i18n("Textfile (*.txt)")); + if(!str.isEmpty()) + { + bool res = true; + if (QFile::exists(str)) + { + QMessageBox mb(i18n("Error"), i18n("File already exists. Overwrite?"), + QMessageBox::Warning, + QMessageBox::Yes | QMessageBox::Default, + QMessageBox::No, + QMessageBox::Cancel | QMessageBox::Escape); + mb.setButtonText(QMessageBox::Yes, i18n("&Overwrite")); + mb.setButtonText(QMessageBox::No, i18n("&Append")); + switch (mb.exec()) + { + case QMessageBox::Yes: + res = History::save(m_id, str, false); + break; + case QMessageBox::No: + res = History::save(m_id, str, true); + break; + case QMessageBox::Cancel: + break; + } + }else + res = History::save(m_id, str); + if (!res) + QMessageBox::critical(this, i18n("Error"), i18n("Save failed"), QMessageBox::Ok, Qt::NoButton, Qt::NoButton); + } + return true; + } + if (cmd->id == CmdHistoryFind) + { + m_filter.clear(); + if (cmd->flags & COMMAND_CHECKED) + { + Command cmd; + cmd->id = CmdHistoryFind; + cmd->param = (void*)m_id; + EventCommandWidget eWidget(cmd); + eWidget.process(); + CToolCombo *cmbFind = qobject_cast(eWidget.widget()); + QString text = cmbFind->lineEdit()->text(); + if (cmbFind && !text.isEmpty()) + { + addHistory(text); + m_filter = text; + } + } + m_page = 0; + m_states.clear(); + m_view->setSelect(m_filter); + fill(); + return true; + } + break; + } + default: + break; + } + return false; +} + +void HistoryWindow::resizeEvent(QResizeEvent *e) +{ + QMainWindow::resizeEvent(e); + //CorePlugin::instance()->data.HistorySize[0].asULong() = width(); + //CorePlugin::instance()->data.HistorySize[1].asULong() = height(); +} + +void HistoryWindow::toolbarChanged(QToolBar*) +{ + //saveToolbar(m_bar, CorePlugin::instance()->data.HistoryBar); + //saveToolbar(m_avatar_bar, CorePlugin::instance()->data.HistoryAvatarBar); +} + +void HistoryWindow::fill() +{ + log(L_DEBUG, "Fill"); + if (m_it == NULL) + m_it = new HistoryIterator(m_id); + if (m_progress == NULL) + { + m_progress = new HistoryProgressBar(m_status); + m_status->addWidget(m_progress, 1); + } + m_it->setFilter(m_filter); + m_progress->setTotalSteps(m_history_page_count); + m_progress->setProgress(0); + m_progress->show(); + m_nMessages = 0; + if (m_bDirection) + m_it->end(); + else + m_it->begin(); + if (m_states.size()) + m_it->setState(m_states[m_page]); + else + m_states.push_back(m_it->state()); + m_view->setText(QString::null); + QTimer::singleShot(0, this, SLOT(next())); + Command cmd; + cmd->id = CmdHistoryNext; + cmd->flags = COMMAND_DISABLED; + cmd->param = (void*)m_id; + EventCommandDisabled(cmd).process(); + cmd->id = CmdHistoryPrev; + cmd->flags = (m_page > 0) ? 0 : COMMAND_DISABLED; + EventCommandDisabled(cmd).process(); +} + +void HistoryWindow::next() +{ + if ( m_it == NULL ) + return; + + //Quickfix Noragen, Stop at 1000 Messages, if there are Problems with storing the size. + if (m_history_page_count > 1000) + m_history_page_count=1000; + + m_progress->setTotalSteps(m_history_page_count); + + for (;;) + { + QString state = m_it->state(); + Message *msg = NULL; + if (m_bDirection) + msg = --(*m_it); + else + msg = ++(*m_it); + + if (++m_nMessages > m_history_page_count && msg) + { + Command cmd; + cmd->id = CmdHistoryNext; + cmd->flags = 0; + cmd->param = (void*)m_id; + EventCommandDisabled(cmd).process(); + msg = NULL; + if (m_page+1>=m_states.size()) + m_states.push_back(state); + } + + if (msg == NULL) + break; + + m_view->addMessage(msg, false, false); + m_progress->setProgress(m_nMessages); + } + + delete m_progress; + delete m_it; + m_it = NULL; + m_progress = NULL; + log(L_DEBUG, "Stop"); +} + +const unsigned MAX_HISTORY = 10; + +void HistoryWindow::addHistory(const QString &str) +{ + QStringList l = CorePlugin::instance()->value("HistorySearch").toString().split(';'); + l.removeAll(str); + l.prepend(str); + + QString res; + unsigned i = 0; + Q_FOREACH(const QString &str, l) + { + if (i++ > MAX_HISTORY) + break; + if (!res.isEmpty()) + res += ';'; + res += quoteChars(str, ";"); + } + CorePlugin::instance()->setValue("HistorySearch", res); +} + diff --git a/plugins/_core/historywnd.h b/plugins/_core/historywnd.h new file mode 100644 index 0000000..18668c6 --- /dev/null +++ b/plugins/_core/historywnd.h @@ -0,0 +1,67 @@ +/*************************************************************************** + historywnd.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _HISTORYWND_H +#define _HISTORYWND_H + +#include +#include "event.h" + +#include +#include +#include +#include + +class MsgViewBase; +class CToolBar; +class QToolButton; +class QComboBox; +class HistoryProgressBar; +class HistoryIterator; + +class HistoryWindow : public QMainWindow, public SIM::EventReceiver +{ + Q_OBJECT +public: + HistoryWindow(unsigned long id); + ~HistoryWindow(); + unsigned long id() { return m_id; } +protected slots: + void toolbarChanged(QToolBar*); + void fill(); + void next(); +protected: + virtual bool processEvent(SIM::Event*); + void resizeEvent(QResizeEvent*); + void setName(); + void addHistory(const QString &str); + QStatusBar *m_status; + MsgViewBase *m_view; + CToolBar *m_bar; + CToolBar *m_avatar_bar; + QString m_filter; + HistoryProgressBar *m_progress; + HistoryIterator *m_it; + bool m_bDirection; + unsigned m_nMessages; + unsigned long m_id; + unsigned m_page; + std::vector m_states; + unsigned m_history_page_count; +}; + +#endif diff --git a/plugins/_core/icq5.1/0.png b/plugins/_core/icq5.1/0.png new file mode 100644 index 0000000..070f91a Binary files /dev/null and b/plugins/_core/icq5.1/0.png differ diff --git a/plugins/_core/icq5.1/1.png b/plugins/_core/icq5.1/1.png new file mode 100644 index 0000000..3ac3a8e Binary files /dev/null and b/plugins/_core/icq5.1/1.png differ diff --git a/plugins/_core/icq5.1/10.png b/plugins/_core/icq5.1/10.png new file mode 100644 index 0000000..95cfb2c Binary files /dev/null and b/plugins/_core/icq5.1/10.png differ diff --git a/plugins/_core/icq5.1/11.png b/plugins/_core/icq5.1/11.png new file mode 100644 index 0000000..115a112 Binary files /dev/null and b/plugins/_core/icq5.1/11.png differ diff --git a/plugins/_core/icq5.1/12.png b/plugins/_core/icq5.1/12.png new file mode 100644 index 0000000..63aa14e Binary files /dev/null and b/plugins/_core/icq5.1/12.png differ diff --git a/plugins/_core/icq5.1/13.png b/plugins/_core/icq5.1/13.png new file mode 100644 index 0000000..ba733d4 Binary files /dev/null and b/plugins/_core/icq5.1/13.png differ diff --git a/plugins/_core/icq5.1/14.png b/plugins/_core/icq5.1/14.png new file mode 100644 index 0000000..ee0606b Binary files /dev/null and b/plugins/_core/icq5.1/14.png differ diff --git a/plugins/_core/icq5.1/15.png b/plugins/_core/icq5.1/15.png new file mode 100644 index 0000000..80a92ac Binary files /dev/null and b/plugins/_core/icq5.1/15.png differ diff --git a/plugins/_core/icq5.1/16.png b/plugins/_core/icq5.1/16.png new file mode 100644 index 0000000..a6b9e19 Binary files /dev/null and b/plugins/_core/icq5.1/16.png differ diff --git a/plugins/_core/icq5.1/17.png b/plugins/_core/icq5.1/17.png new file mode 100644 index 0000000..2d2f6d6 Binary files /dev/null and b/plugins/_core/icq5.1/17.png differ diff --git a/plugins/_core/icq5.1/18.png b/plugins/_core/icq5.1/18.png new file mode 100644 index 0000000..723dba7 Binary files /dev/null and b/plugins/_core/icq5.1/18.png differ diff --git a/plugins/_core/icq5.1/19.png b/plugins/_core/icq5.1/19.png new file mode 100644 index 0000000..4be1a3a Binary files /dev/null and b/plugins/_core/icq5.1/19.png differ diff --git a/plugins/_core/icq5.1/2.png b/plugins/_core/icq5.1/2.png new file mode 100644 index 0000000..7b490ef Binary files /dev/null and b/plugins/_core/icq5.1/2.png differ diff --git a/plugins/_core/icq5.1/20.png b/plugins/_core/icq5.1/20.png new file mode 100644 index 0000000..c86b7ff Binary files /dev/null and b/plugins/_core/icq5.1/20.png differ diff --git a/plugins/_core/icq5.1/21.png b/plugins/_core/icq5.1/21.png new file mode 100644 index 0000000..eeac0e9 Binary files /dev/null and b/plugins/_core/icq5.1/21.png differ diff --git a/plugins/_core/icq5.1/22.png b/plugins/_core/icq5.1/22.png new file mode 100644 index 0000000..2289890 Binary files /dev/null and b/plugins/_core/icq5.1/22.png differ diff --git a/plugins/_core/icq5.1/23.png b/plugins/_core/icq5.1/23.png new file mode 100644 index 0000000..30c7a49 Binary files /dev/null and b/plugins/_core/icq5.1/23.png differ diff --git a/plugins/_core/icq5.1/24.png b/plugins/_core/icq5.1/24.png new file mode 100644 index 0000000..e834d58 Binary files /dev/null and b/plugins/_core/icq5.1/24.png differ diff --git a/plugins/_core/icq5.1/25.png b/plugins/_core/icq5.1/25.png new file mode 100644 index 0000000..f2166c6 Binary files /dev/null and b/plugins/_core/icq5.1/25.png differ diff --git a/plugins/_core/icq5.1/26.png b/plugins/_core/icq5.1/26.png new file mode 100644 index 0000000..54a229a Binary files /dev/null and b/plugins/_core/icq5.1/26.png differ diff --git a/plugins/_core/icq5.1/27.png b/plugins/_core/icq5.1/27.png new file mode 100644 index 0000000..0cd050f Binary files /dev/null and b/plugins/_core/icq5.1/27.png differ diff --git a/plugins/_core/icq5.1/3.png b/plugins/_core/icq5.1/3.png new file mode 100644 index 0000000..909288a Binary files /dev/null and b/plugins/_core/icq5.1/3.png differ diff --git a/plugins/_core/icq5.1/4.png b/plugins/_core/icq5.1/4.png new file mode 100644 index 0000000..f075a9d Binary files /dev/null and b/plugins/_core/icq5.1/4.png differ diff --git a/plugins/_core/icq5.1/5.png b/plugins/_core/icq5.1/5.png new file mode 100644 index 0000000..c036cb9 Binary files /dev/null and b/plugins/_core/icq5.1/5.png differ diff --git a/plugins/_core/icq5.1/6.png b/plugins/_core/icq5.1/6.png new file mode 100644 index 0000000..817abb3 Binary files /dev/null and b/plugins/_core/icq5.1/6.png differ diff --git a/plugins/_core/icq5.1/7.png b/plugins/_core/icq5.1/7.png new file mode 100644 index 0000000..2fc84d5 Binary files /dev/null and b/plugins/_core/icq5.1/7.png differ diff --git a/plugins/_core/icq5.1/8.png b/plugins/_core/icq5.1/8.png new file mode 100644 index 0000000..70010e2 Binary files /dev/null and b/plugins/_core/icq5.1/8.png differ diff --git a/plugins/_core/icq5.1/9.png b/plugins/_core/icq5.1/9.png new file mode 100644 index 0000000..e5cea65 Binary files /dev/null and b/plugins/_core/icq5.1/9.png differ diff --git a/plugins/_core/icq5.1/icondef.xml b/plugins/_core/icq5.1/icondef.xml new file mode 100644 index 0000000..8b06544 --- /dev/null +++ b/plugins/_core/icq5.1/icondef.xml @@ -0,0 +1,149 @@ + + + + SIM smiles + 0.9.6 + SIM smiles. + Vladimir Shutoff + 2004-06-11 + http://sim-im.org/ + + + :-) + :) + =) + 0.png + + + :-( + :( + 1.png + + + ;-) + ;) + 2.png + + + :-P + 3.png + + + *JOKINGLY* + 4.png + + + :'-( + :'( + 5.png + + + *KISSED* + 6.png + + + :-{} + :-* + :{} + 7.png + + + :-") + :-[ + :-< + :< + 8.png + + + 0:-) + O:-) + 0-) + O-) + 9.png + + + :-X + :-x + 10.png + + + :-| + :-! + :-$ + 11.png + + + :-@ + >:0 + >:O + >:o + 12.png + + + :-D + :D + 13.png + + + :-/ + :-\ + 14.png + + + :-0 + :-O + :=0 + :=O + =-0 + =-O + 15.png + + + 8-) + 16.png + + + [:-} + 17.png + + + *TIRED* + 18.png + + + :*) + 19.png + + + *STOP* + 20.png + + + *KISSING* + 21.png + + + ]:-> + 22.png + + + @}->-- + 23.png + + + @= + 24.png + + + *THUMBS UP* + 25.png + + + *DRINK* + 26.png + + + *IN LOVE* + 27.png + + diff --git a/plugins/_core/icq5/00.png b/plugins/_core/icq5/00.png new file mode 100644 index 0000000..1730ff3 Binary files /dev/null and b/plugins/_core/icq5/00.png differ diff --git a/plugins/_core/icq5/01.png b/plugins/_core/icq5/01.png new file mode 100644 index 0000000..92ae612 Binary files /dev/null and b/plugins/_core/icq5/01.png differ diff --git a/plugins/_core/icq5/02.png b/plugins/_core/icq5/02.png new file mode 100644 index 0000000..a9ebf26 Binary files /dev/null and b/plugins/_core/icq5/02.png differ diff --git a/plugins/_core/icq5/03.png b/plugins/_core/icq5/03.png new file mode 100644 index 0000000..32a1fcb Binary files /dev/null and b/plugins/_core/icq5/03.png differ diff --git a/plugins/_core/icq5/04.png b/plugins/_core/icq5/04.png new file mode 100644 index 0000000..6f0b627 Binary files /dev/null and b/plugins/_core/icq5/04.png differ diff --git a/plugins/_core/icq5/05.png b/plugins/_core/icq5/05.png new file mode 100644 index 0000000..1879400 Binary files /dev/null and b/plugins/_core/icq5/05.png differ diff --git a/plugins/_core/icq5/06.png b/plugins/_core/icq5/06.png new file mode 100644 index 0000000..7dbf0af Binary files /dev/null and b/plugins/_core/icq5/06.png differ diff --git a/plugins/_core/icq5/07.png b/plugins/_core/icq5/07.png new file mode 100644 index 0000000..1c29635 Binary files /dev/null and b/plugins/_core/icq5/07.png differ diff --git a/plugins/_core/icq5/08.png b/plugins/_core/icq5/08.png new file mode 100644 index 0000000..4e6e61f Binary files /dev/null and b/plugins/_core/icq5/08.png differ diff --git a/plugins/_core/icq5/09.png b/plugins/_core/icq5/09.png new file mode 100644 index 0000000..e6b6177 Binary files /dev/null and b/plugins/_core/icq5/09.png differ diff --git a/plugins/_core/icq5/10.png b/plugins/_core/icq5/10.png new file mode 100644 index 0000000..dbb66ba Binary files /dev/null and b/plugins/_core/icq5/10.png differ diff --git a/plugins/_core/icq5/11.png b/plugins/_core/icq5/11.png new file mode 100644 index 0000000..ff9f4d2 Binary files /dev/null and b/plugins/_core/icq5/11.png differ diff --git a/plugins/_core/icq5/12.png b/plugins/_core/icq5/12.png new file mode 100644 index 0000000..a0d87b6 Binary files /dev/null and b/plugins/_core/icq5/12.png differ diff --git a/plugins/_core/icq5/13.png b/plugins/_core/icq5/13.png new file mode 100644 index 0000000..f3a838c Binary files /dev/null and b/plugins/_core/icq5/13.png differ diff --git a/plugins/_core/icq5/14.png b/plugins/_core/icq5/14.png new file mode 100644 index 0000000..c952876 Binary files /dev/null and b/plugins/_core/icq5/14.png differ diff --git a/plugins/_core/icq5/15.png b/plugins/_core/icq5/15.png new file mode 100644 index 0000000..1e71f2e Binary files /dev/null and b/plugins/_core/icq5/15.png differ diff --git a/plugins/_core/icq5/16.png b/plugins/_core/icq5/16.png new file mode 100644 index 0000000..83f5d06 Binary files /dev/null and b/plugins/_core/icq5/16.png differ diff --git a/plugins/_core/icq5/17.png b/plugins/_core/icq5/17.png new file mode 100644 index 0000000..c5c2528 Binary files /dev/null and b/plugins/_core/icq5/17.png differ diff --git a/plugins/_core/icq5/18.png b/plugins/_core/icq5/18.png new file mode 100644 index 0000000..47b5210 Binary files /dev/null and b/plugins/_core/icq5/18.png differ diff --git a/plugins/_core/icq5/19.png b/plugins/_core/icq5/19.png new file mode 100644 index 0000000..f62522d Binary files /dev/null and b/plugins/_core/icq5/19.png differ diff --git a/plugins/_core/icq5/20.png b/plugins/_core/icq5/20.png new file mode 100644 index 0000000..767c1ab Binary files /dev/null and b/plugins/_core/icq5/20.png differ diff --git a/plugins/_core/icq5/21.png b/plugins/_core/icq5/21.png new file mode 100644 index 0000000..0fb6003 Binary files /dev/null and b/plugins/_core/icq5/21.png differ diff --git a/plugins/_core/icq5/22.png b/plugins/_core/icq5/22.png new file mode 100644 index 0000000..54ae480 Binary files /dev/null and b/plugins/_core/icq5/22.png differ diff --git a/plugins/_core/icq5/23.png b/plugins/_core/icq5/23.png new file mode 100644 index 0000000..c45ef0b Binary files /dev/null and b/plugins/_core/icq5/23.png differ diff --git a/plugins/_core/icq5/24.png b/plugins/_core/icq5/24.png new file mode 100644 index 0000000..aba0c48 Binary files /dev/null and b/plugins/_core/icq5/24.png differ diff --git a/plugins/_core/icq5/25.png b/plugins/_core/icq5/25.png new file mode 100644 index 0000000..f8167f2 Binary files /dev/null and b/plugins/_core/icq5/25.png differ diff --git a/plugins/_core/icq5/26.png b/plugins/_core/icq5/26.png new file mode 100644 index 0000000..5cc1ad0 Binary files /dev/null and b/plugins/_core/icq5/26.png differ diff --git a/plugins/_core/icq5/27.png b/plugins/_core/icq5/27.png new file mode 100644 index 0000000..1c38c9c Binary files /dev/null and b/plugins/_core/icq5/27.png differ diff --git a/plugins/_core/icq5/icondef.xml b/plugins/_core/icq5/icondef.xml new file mode 100644 index 0000000..0401519 --- /dev/null +++ b/plugins/_core/icq5/icondef.xml @@ -0,0 +1,149 @@ + + + + ICQ5 smiles for SIM + 1 + ICQ5 smiles for SIM + yrtimiD + 2005-10-12 + + + + :-) + :) + =) + 00.png + + + :-( + :( + 01.png + + + ;-) + ;) + 02.png + + + :-P + 03.png + + + *JOKINGLY* + 04.png + + + :'-( + :'( + 05.png + + + *KISSED* + 06.png + + + :-{} + :-* + :{} + 07.png + + + :-") + :-[ + :-< + :< + 08.png + + + 0:-) + O:-) + 0-) + O-) + 09.png + + + :-X + :-x + 10.png + + + :-| + :-! + :-$ + 11.png + + + :-@ + >:0 + >:O + >:o + 12.png + + + :-D + :D + 13.png + + + :-/ + :-\ + 14.png + + + :-0 + :-O + :=0 + :=O + =-0 + =-O + 15.png + + + 8-) + 16.png + + + [:-} + 17.png + + + *TIRED* + 18.png + + + :*) + 19.png + + + *STOP* + 20.png + + + *KISSING* + 21.png + + + ]:-> + 22.png + + + @}->-- + 23.png + + + @= + 24.png + + + *THUMBS UP* + 25.png + + + *DRINK* + 26.png + + + *IN LOVE* + 27.png + + diff --git a/plugins/_core/icqlite/0.png b/plugins/_core/icqlite/0.png new file mode 100644 index 0000000..f773dc3 Binary files /dev/null and b/plugins/_core/icqlite/0.png differ diff --git a/plugins/_core/icqlite/1.png b/plugins/_core/icqlite/1.png new file mode 100644 index 0000000..13f283e Binary files /dev/null and b/plugins/_core/icqlite/1.png differ diff --git a/plugins/_core/icqlite/10.png b/plugins/_core/icqlite/10.png new file mode 100644 index 0000000..d4ea4c6 Binary files /dev/null and b/plugins/_core/icqlite/10.png differ diff --git a/plugins/_core/icqlite/11.png b/plugins/_core/icqlite/11.png new file mode 100644 index 0000000..5cbaabc Binary files /dev/null and b/plugins/_core/icqlite/11.png differ diff --git a/plugins/_core/icqlite/12.png b/plugins/_core/icqlite/12.png new file mode 100644 index 0000000..0cb7983 Binary files /dev/null and b/plugins/_core/icqlite/12.png differ diff --git a/plugins/_core/icqlite/13.png b/plugins/_core/icqlite/13.png new file mode 100644 index 0000000..63ba8ec Binary files /dev/null and b/plugins/_core/icqlite/13.png differ diff --git a/plugins/_core/icqlite/14.png b/plugins/_core/icqlite/14.png new file mode 100644 index 0000000..5e03f7b Binary files /dev/null and b/plugins/_core/icqlite/14.png differ diff --git a/plugins/_core/icqlite/15.png b/plugins/_core/icqlite/15.png new file mode 100644 index 0000000..484dce0 Binary files /dev/null and b/plugins/_core/icqlite/15.png differ diff --git a/plugins/_core/icqlite/16.png b/plugins/_core/icqlite/16.png new file mode 100644 index 0000000..3633cea Binary files /dev/null and b/plugins/_core/icqlite/16.png differ diff --git a/plugins/_core/icqlite/17.png b/plugins/_core/icqlite/17.png new file mode 100644 index 0000000..1b01221 Binary files /dev/null and b/plugins/_core/icqlite/17.png differ diff --git a/plugins/_core/icqlite/18.png b/plugins/_core/icqlite/18.png new file mode 100644 index 0000000..27bc482 Binary files /dev/null and b/plugins/_core/icqlite/18.png differ diff --git a/plugins/_core/icqlite/19.png b/plugins/_core/icqlite/19.png new file mode 100644 index 0000000..bbccc87 Binary files /dev/null and b/plugins/_core/icqlite/19.png differ diff --git a/plugins/_core/icqlite/2.png b/plugins/_core/icqlite/2.png new file mode 100644 index 0000000..c0e896e Binary files /dev/null and b/plugins/_core/icqlite/2.png differ diff --git a/plugins/_core/icqlite/20.png b/plugins/_core/icqlite/20.png new file mode 100644 index 0000000..90a4d5a Binary files /dev/null and b/plugins/_core/icqlite/20.png differ diff --git a/plugins/_core/icqlite/21.png b/plugins/_core/icqlite/21.png new file mode 100644 index 0000000..10c9326 Binary files /dev/null and b/plugins/_core/icqlite/21.png differ diff --git a/plugins/_core/icqlite/22.png b/plugins/_core/icqlite/22.png new file mode 100644 index 0000000..c60b2b9 Binary files /dev/null and b/plugins/_core/icqlite/22.png differ diff --git a/plugins/_core/icqlite/23.png b/plugins/_core/icqlite/23.png new file mode 100644 index 0000000..baa215f Binary files /dev/null and b/plugins/_core/icqlite/23.png differ diff --git a/plugins/_core/icqlite/24.png b/plugins/_core/icqlite/24.png new file mode 100644 index 0000000..29f894b Binary files /dev/null and b/plugins/_core/icqlite/24.png differ diff --git a/plugins/_core/icqlite/25.png b/plugins/_core/icqlite/25.png new file mode 100644 index 0000000..7254558 Binary files /dev/null and b/plugins/_core/icqlite/25.png differ diff --git a/plugins/_core/icqlite/26.png b/plugins/_core/icqlite/26.png new file mode 100644 index 0000000..59d948b Binary files /dev/null and b/plugins/_core/icqlite/26.png differ diff --git a/plugins/_core/icqlite/27.png b/plugins/_core/icqlite/27.png new file mode 100644 index 0000000..599645d Binary files /dev/null and b/plugins/_core/icqlite/27.png differ diff --git a/plugins/_core/icqlite/3.png b/plugins/_core/icqlite/3.png new file mode 100644 index 0000000..7db47b2 Binary files /dev/null and b/plugins/_core/icqlite/3.png differ diff --git a/plugins/_core/icqlite/4.png b/plugins/_core/icqlite/4.png new file mode 100644 index 0000000..2d915d2 Binary files /dev/null and b/plugins/_core/icqlite/4.png differ diff --git a/plugins/_core/icqlite/5.png b/plugins/_core/icqlite/5.png new file mode 100644 index 0000000..76d13f2 Binary files /dev/null and b/plugins/_core/icqlite/5.png differ diff --git a/plugins/_core/icqlite/6.png b/plugins/_core/icqlite/6.png new file mode 100644 index 0000000..8bbc1f3 Binary files /dev/null and b/plugins/_core/icqlite/6.png differ diff --git a/plugins/_core/icqlite/7.png b/plugins/_core/icqlite/7.png new file mode 100644 index 0000000..43f0199 Binary files /dev/null and b/plugins/_core/icqlite/7.png differ diff --git a/plugins/_core/icqlite/8.png b/plugins/_core/icqlite/8.png new file mode 100644 index 0000000..19fc0c0 Binary files /dev/null and b/plugins/_core/icqlite/8.png differ diff --git a/plugins/_core/icqlite/9.png b/plugins/_core/icqlite/9.png new file mode 100644 index 0000000..ed6876a Binary files /dev/null and b/plugins/_core/icqlite/9.png differ diff --git a/plugins/_core/icqlite/icondef.xml b/plugins/_core/icqlite/icondef.xml new file mode 100644 index 0000000..8b06544 --- /dev/null +++ b/plugins/_core/icqlite/icondef.xml @@ -0,0 +1,149 @@ + + + + SIM smiles + 0.9.6 + SIM smiles. + Vladimir Shutoff + 2004-06-11 + http://sim-im.org/ + + + :-) + :) + =) + 0.png + + + :-( + :( + 1.png + + + ;-) + ;) + 2.png + + + :-P + 3.png + + + *JOKINGLY* + 4.png + + + :'-( + :'( + 5.png + + + *KISSED* + 6.png + + + :-{} + :-* + :{} + 7.png + + + :-") + :-[ + :-< + :< + 8.png + + + 0:-) + O:-) + 0-) + O-) + 9.png + + + :-X + :-x + 10.png + + + :-| + :-! + :-$ + 11.png + + + :-@ + >:0 + >:O + >:o + 12.png + + + :-D + :D + 13.png + + + :-/ + :-\ + 14.png + + + :-0 + :-O + :=0 + :=O + =-0 + =-O + 15.png + + + 8-) + 16.png + + + [:-} + 17.png + + + *TIRED* + 18.png + + + :*) + 19.png + + + *STOP* + 20.png + + + *KISSING* + 21.png + + + ]:-> + 22.png + + + @}->-- + 23.png + + + @= + 24.png + + + *THUMBS UP* + 25.png + + + *DRINK* + 26.png + + + *IN LOVE* + 27.png + + diff --git a/plugins/_core/interfacecfg.cpp b/plugins/_core/interfacecfg.cpp new file mode 100644 index 0000000..35f2374 --- /dev/null +++ b/plugins/_core/interfacecfg.cpp @@ -0,0 +1,351 @@ +/*************************************************************************** + interfacecfg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "simapi.h" + +#ifdef WIN32 +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" + +#include "interfacecfg.h" +#include "userviewcfg.h" +#include "historycfg.h" +#include "msgcfg.h" +#include "smscfg.h" +#include "core.h" + +#ifdef WIN32 +static WCHAR key_name[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Run"; +static WCHAR value_name[] = L"SIM"; +#endif + +using namespace std; +using namespace SIM; + +#ifndef USE_KDE + +struct language +{ + const char *code; + const char *name; +}; + +static language langs[] = + { + { "-", I18N_NOOP("English") }, + { "bg", I18N_NOOP("Bulgarian") }, + { "ca", I18N_NOOP("Catalan") }, + { "cs", I18N_NOOP("Czech") }, + { "de", I18N_NOOP("German") }, + { "el", I18N_NOOP("Greek") }, + { "es", I18N_NOOP("Spanish") }, + { "fr", I18N_NOOP("French") }, + { "he", I18N_NOOP("Hebrew") }, + { "hu", I18N_NOOP("Hungarian") }, + { "it", I18N_NOOP("Italian") }, + { "nl", I18N_NOOP("Dutch") }, + { "pl", I18N_NOOP("Polish") }, + { "pt_BR", I18N_NOOP("Portuguese") }, + { "ru", I18N_NOOP("Russian") }, + { "sk", I18N_NOOP("Slovak") }, + { "sw", I18N_NOOP("Swabian") }, + { "th", I18N_NOOP("Thai") }, + { "tr", I18N_NOOP("Turkish") }, + { "uk", I18N_NOOP("Ukrainian") }, + { "zh_TW", I18N_NOOP("Chinese") }, + { NULL, NULL } + }; +#endif + +InterfaceConfig::InterfaceConfig(QWidget *parent) + : QWidget(parent) +{ + setupUi(this); + connectControls(); + + for(QObject *p = parent; p != NULL; p = p->parent()) + { + if (!p->inherits("QTabWidget")) + continue; + QTabWidget *tab = static_cast(p); + userview_cfg = new UserViewConfig(tab); + tab->addTab(userview_cfg, i18n("Contact list")); + history_cfg = new HistoryConfig(tab); + tab->addTab(history_cfg, i18n("History")); + SIM::PropertyHubPtr data = getContacts()->getUserData("_core"); + msg_cfg = new MessageConfig(tab, data); + tab->addTab(msg_cfg, i18n("Messages")); + data = getContacts()->getUserData("SMS"); + sms_cfg = new SMSConfig(tab, data); + tab->addTab(sms_cfg, i18n("SMS")); + break; + } +#ifndef USE_KDE + QString cur = CorePlugin::instance()->value("Lang").toString(); + cmbLang->insertItem(INT_MAX,i18n("System")); + cmbLang->addItems(getLangItems()); + int nCurrent = 0; + if(!cur.isEmpty()) + { + const language *l; + for (l = langs; l->code; l++) + if (cur == l->code) + break; + if (l->code) + nCurrent = cmbLang->findText(i18n(l->name)); + } + cmbLang->setCurrentIndex(nCurrent); +#else + TextLabel1_2->hide(); + cmbLang->hide(); +#endif + + if (CorePlugin::instance()->getContainerMode()) + { + optChat->setChecked(true); + if (CorePlugin::instance()->getContainerMode()==1) + optNew->setChecked(true); + if (CorePlugin::instance()->getContainerMode()==2) + optGroup->setChecked(true); + if (CorePlugin::instance()->getContainerMode()==3) + optOne->setChecked(true); + chkEnter->setChecked(CorePlugin::instance()->value("SendOnEnter").toBool()); + } + else + { + optSimple->setChecked(true); + grpContainer->setEnabled(false); + } + chkSaveFont->setChecked(CorePlugin::instance()->value("EditSaveFont").toBool()); + QString copy2; + QString copy1 = i18n("Copy %1 messages from history"); + int n = copy1.indexOf("%1"); + if (n >= 0) + { + copy2 = copy1.mid(n + 2); + copy1 = copy1.left(n); + } + lblCopy1->setText(copy1); + lblCopy2->setText(copy2); + spnCopy->setValue(CorePlugin::instance()->value("CopyMessages").toUInt()); + chkOwnerName->setText(i18n("Show own nickname in window title")); + chkOwnerName->setChecked(CorePlugin::instance()->value("ShowOwnerName").toBool()); + chkAvatar->setText(i18n("Show user avatar")); + chkAvatar->setChecked(CorePlugin::instance()->value("ShowAvatarInContainer").toBool()); +#ifdef WIN32 + HKEY subKey; + if (RegOpenKeyExW(HKEY_CURRENT_USER, key_name, 0, + KEY_READ | KEY_QUERY_VALUE, &subKey) == ERROR_SUCCESS){ + DWORD vType = REG_SZ; + DWORD vCount = 0; + if (RegQueryValueExW(subKey, value_name, NULL, &vType, NULL, &vCount) == ERROR_SUCCESS) + chkStart->setChecked(true); + RegCloseKey(subKey); + } +#else + chkStart->hide(); +#endif +} + +InterfaceConfig::~InterfaceConfig() +{ +} + +#ifndef USE_KDE + +QStringList InterfaceConfig::getLangItems() +{ + QStringList items; + const language *l; + for (l = langs; l->code; l++) + { + if (strcmp(l->code, "-") == 0) + { + items.append(i18n(l->name)); + continue; + } + QString ts = CorePlugin::instance()->tsFile(l->code); + if (ts.isEmpty()) + continue; + items.append(i18n(l->name)); + } + items.sort(); + return items; +} + +#endif + +void InterfaceConfig::modeChanged(int mode) +{ + if (mode==1) + setOpenEachContactInContainer(true); + if (mode==2) + setOpenGroupInContainer(true); + if (mode==3) + setOpenAllContactsInOneContainer(true); +} + +void InterfaceConfig::setSimpleMode(bool) +{ + disconnectControls(); + grpContainer->setEnabled(false); + connectControls(); +} + +void InterfaceConfig::setChatMode(bool) +{ + disconnectControls(); + grpContainer->setEnabled(true); + chkEnter->setChecked(false); + connectControls(); + setOpenAllContactsInOneContainer(true); +} + +void InterfaceConfig::setOpenEachContactInContainer(bool) +{ + disconnectControls(); + grpContainer->setEnabled(true); + optNew->setChecked(true); + chkEnter->setChecked(false); + connectControls(); +} + +void InterfaceConfig::setOpenGroupInContainer(bool) +{ + disconnectControls(); + optGroup->setChecked(true); + chkEnter->setChecked(false); + connectControls(); + +} + +void InterfaceConfig::setOpenAllContactsInOneContainer(bool) +{ + disconnectControls(); + optOne->setChecked(true); + chkEnter->setChecked(false); + connectControls(); +} + +void InterfaceConfig::connectControls() +{ + connect(optSimple, SIGNAL(toggled(bool)), this, SLOT(setSimpleMode (bool))); + connect(optChat, SIGNAL(toggled(bool)), this, SLOT(setChatMode (bool))); + connect(optNew, SIGNAL(toggled(bool)), this, SLOT(setOpenEachContactInContainer (bool))); + connect(optGroup, SIGNAL(toggled(bool)), this, SLOT(setOpenGroupInContainer (bool))); + connect(optOne, SIGNAL(toggled(bool)), this, SLOT(setOpenAllContactsInOneContainer(bool))); + connect(CorePlugin::instance(),SIGNAL(modeChanged(int)), this, SLOT( modeChanged(int))); +} + +void InterfaceConfig::disconnectControls() +{ + disconnect(optSimple, SIGNAL(toggled(bool)), this, SLOT(setSimpleMode (bool))); + disconnect(optChat, SIGNAL(toggled(bool)), this, SLOT(setChatMode (bool))); + disconnect(optNew, SIGNAL(toggled(bool)), this, SLOT(setOpenEachContactInContainer (bool))); + disconnect(optGroup, SIGNAL(toggled(bool)), this, SLOT(setOpenGroupInContainer (bool))); + disconnect(optOne, SIGNAL(toggled(bool)), this, SLOT(setOpenAllContactsInOneContainer(bool))); + disconnect(CorePlugin::instance(),SIGNAL(modeChanged(int)), this, SLOT( modeChanged(int))); +} + +void InterfaceConfig::apply() +{ + userview_cfg->apply(); + history_cfg->apply(); + SIM::PropertyHubPtr data = getContacts()->getUserData("_core"); + msg_cfg->apply(data); + data = getContacts()->getUserData("SMS"); + sms_cfg->apply(data); + CorePlugin::instance()->setValue("EditSaveFont", chkSaveFont->isChecked()); +#ifndef USE_KDE + int res = cmbLang->currentIndex(); + const char *lang = ""; + if (res > 0) + { + QStringList items = getLangItems(); + QString name = items[res - 1]; + const language *l; + for (l = langs; l->code; l++) + { + if (name == i18n(l->name)) + { + lang = l->code; + break; + } + } + } +#endif + int mode = 0; + if (optSimple->isChecked()) + { + CorePlugin::instance()->setContainerMode(mode); + CorePlugin::instance()->setValue("SendOnEnter", false); + } + else + { + + if (optNew->isChecked()) + mode = 1; + if (optGroup->isChecked()) + mode = 2; + if (optOne->isChecked()) + mode = 3; + CorePlugin::instance()->setContainerMode(mode); + CorePlugin::instance()->setValue("SendOnEnter", chkEnter->isChecked()); + CorePlugin::instance()->setValue("CopyMessages", (uint)spnCopy->text().toULong()); + } + + CorePlugin::instance()->setValue("ShowOwnerName", chkOwnerName->isChecked()); + CorePlugin::instance()->setValue("ShowAvatarInContainer", chkAvatar->isChecked()); +#ifndef USE_KDE + if (lang != CorePlugin::instance()->value("Lang").toString()) + { + CorePlugin::instance()->removeTranslator(); + CorePlugin::instance()->setValue("Lang", lang); + CorePlugin::instance()->installTranslator(); + } +#endif +#ifdef WIN32 + HKEY subKey; + if (RegOpenKeyExW(HKEY_CURRENT_USER, key_name, 0, + KEY_WRITE | KEY_QUERY_VALUE, &subKey) == ERROR_SUCCESS){ + if (chkStart->isChecked()) + { + QString path = app_file("sim.exe"); + DWORD res = RegSetValueExW(subKey, value_name, 0, REG_SZ, (BYTE*)path.utf16(), (path.length() + 1) * 2); + if (res != ERROR_SUCCESS) + log(L_WARN, "RegSetValue fail %u", (unsigned int)res); + } + else + { + DWORD res = RegDeleteValueW(subKey, value_name); + if (res!=ERROR_SUCCESS && res!=ERROR_FILE_NOT_FOUND) + log(L_WARN, "RegDeleteValue fail %u", (unsigned int)res); + } + } + RegCloseKey(subKey); +#endif +} diff --git a/plugins/_core/interfacecfg.h b/plugins/_core/interfacecfg.h new file mode 100644 index 0000000..10c681f --- /dev/null +++ b/plugins/_core/interfacecfg.h @@ -0,0 +1,58 @@ +/*************************************************************************** + interfacecfg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _INTERFACECFG_H +#define _INTERFACECFG_H + +#include "simapi.h" + +#include "ui_interfacecfgbase.h" + +class UserViewConfig; +class HistoryConfig; +class MessageConfig; +class SMSConfig; + +class InterfaceConfig : public QWidget, public Ui_Interface +{ + Q_OBJECT +public: + InterfaceConfig(QWidget *parent); + ~InterfaceConfig(); +public slots: + void apply(); + void modeChanged(int); + void setSimpleMode(bool); + void setChatMode(bool); + void setOpenEachContactInContainer(bool); + void setOpenGroupInContainer(bool); + void setOpenAllContactsInOneContainer(bool); + void connectControls(); + void disconnectControls(); + +protected: +#ifndef USE_KDE + QStringList getLangItems(); +#endif + UserViewConfig *userview_cfg; + HistoryConfig *history_cfg; + MessageConfig *msg_cfg; + SMSConfig *sms_cfg; +}; + +#endif + diff --git a/plugins/_core/interfacecfgbase.ui b/plugins/_core/interfacecfgbase.ui new file mode 100644 index 0000000..8a68b36 --- /dev/null +++ b/plugins/_core/interfacecfgbase.ui @@ -0,0 +1,229 @@ + + + Interface + + + + 0 + 0 + 355 + 447 + + + + Form1 + + + + 6 + + + 11 + + + + + Language: + + + false + + + + + + + + 0 + 0 + + + + + + + + Message window + + + + 6 + + + 11 + + + + + &Simple mode + + + + + + + &Chat mode + + + + + + + &Using last selected font + + + + + + + + + + Container mode + + + + 6 + + + 11 + + + + + Open each contact in &new container + + + + + + + Open one container for &group + + + + + + + Open all contacts in &one container + + + + + + + Use "&Enter" for send message + + + + + + + 6 + + + 0 + + + + + + + + false + + + + + + + 20 + + + + + + + + 0 + 0 + + + + + + + false + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + + Show own nickname in window title + + + + + + + Show user avatar + + + + + + + + + + Start SIM on every &windows startup + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + + setSimpleMode(bool) + setChatMode(bool) + setOpenEachContactInContainer(bool) + setOpenGroupInContainer(bool) + setOpenAllContactsInOneContainer(bool) + + diff --git a/plugins/_core/jisp/1downarrow.png b/plugins/_core/jisp/1downarrow.png new file mode 100644 index 0000000..31722b4 Binary files /dev/null and b/plugins/_core/jisp/1downarrow.png differ diff --git a/plugins/_core/jisp/1leftarrow.png b/plugins/_core/jisp/1leftarrow.png new file mode 100644 index 0000000..b894b42 Binary files /dev/null and b/plugins/_core/jisp/1leftarrow.png differ diff --git a/plugins/_core/jisp/1rightarrow.png b/plugins/_core/jisp/1rightarrow.png new file mode 100644 index 0000000..2a1430f Binary files /dev/null and b/plugins/_core/jisp/1rightarrow.png differ diff --git a/plugins/_core/jisp/1uparrow.png b/plugins/_core/jisp/1uparrow.png new file mode 100644 index 0000000..06d2a9c Binary files /dev/null and b/plugins/_core/jisp/1uparrow.png differ diff --git a/plugins/_core/jisp/add.png b/plugins/_core/jisp/add.png new file mode 100644 index 0000000..db0da7c Binary files /dev/null and b/plugins/_core/jisp/add.png differ diff --git a/plugins/_core/jisp/aim.png b/plugins/_core/jisp/aim.png new file mode 100644 index 0000000..91ed6a8 Binary files /dev/null and b/plugins/_core/jisp/aim.png differ diff --git a/plugins/_core/jisp/alert.png b/plugins/_core/jisp/alert.png new file mode 100644 index 0000000..e1ab9f0 Binary files /dev/null and b/plugins/_core/jisp/alert.png differ diff --git a/plugins/_core/jisp/auth.png b/plugins/_core/jisp/auth.png new file mode 100644 index 0000000..bcff062 Binary files /dev/null and b/plugins/_core/jisp/auth.png differ diff --git a/plugins/_core/jisp/away.png b/plugins/_core/jisp/away.png new file mode 100644 index 0000000..22910b9 Binary files /dev/null and b/plugins/_core/jisp/away.png differ diff --git a/plugins/_core/jisp/bgcolor.png b/plugins/_core/jisp/bgcolor.png new file mode 100644 index 0000000..00453b2 Binary files /dev/null and b/plugins/_core/jisp/bgcolor.png differ diff --git a/plugins/_core/jisp/birthday.png b/plugins/_core/jisp/birthday.png new file mode 100644 index 0000000..4a36c70 Binary files /dev/null and b/plugins/_core/jisp/birthday.png differ diff --git a/plugins/_core/jisp/button_cancel.png b/plugins/_core/jisp/button_cancel.png new file mode 100644 index 0000000..1fc23e3 Binary files /dev/null and b/plugins/_core/jisp/button_cancel.png differ diff --git a/plugins/_core/jisp/button_ok.png b/plugins/_core/jisp/button_ok.png new file mode 100644 index 0000000..5908dc9 Binary files /dev/null and b/plugins/_core/jisp/button_ok.png differ diff --git a/plugins/_core/jisp/cancel.png b/plugins/_core/jisp/cancel.png new file mode 100644 index 0000000..b8cda9b Binary files /dev/null and b/plugins/_core/jisp/cancel.png differ diff --git a/plugins/_core/jisp/cell.png b/plugins/_core/jisp/cell.png new file mode 100644 index 0000000..21c2de3 Binary files /dev/null and b/plugins/_core/jisp/cell.png differ diff --git a/plugins/_core/jisp/chat.png b/plugins/_core/jisp/chat.png new file mode 100644 index 0000000..1d4307b Binary files /dev/null and b/plugins/_core/jisp/chat.png differ diff --git a/plugins/_core/jisp/collapsed.png b/plugins/_core/jisp/collapsed.png new file mode 100644 index 0000000..28012f0 Binary files /dev/null and b/plugins/_core/jisp/collapsed.png differ diff --git a/plugins/_core/jisp/configure.png b/plugins/_core/jisp/configure.png new file mode 100644 index 0000000..b537386 Binary files /dev/null and b/plugins/_core/jisp/configure.png differ diff --git a/plugins/_core/jisp/connect.png b/plugins/_core/jisp/connect.png new file mode 100644 index 0000000..3464920 Binary files /dev/null and b/plugins/_core/jisp/connect.png differ diff --git a/plugins/_core/jisp/contacts.png b/plugins/_core/jisp/contacts.png new file mode 100644 index 0000000..eed6421 Binary files /dev/null and b/plugins/_core/jisp/contacts.png differ diff --git a/plugins/_core/jisp/dnd.png b/plugins/_core/jisp/dnd.png new file mode 100644 index 0000000..8f357ac Binary files /dev/null and b/plugins/_core/jisp/dnd.png differ diff --git a/plugins/_core/jisp/editcopy.png b/plugins/_core/jisp/editcopy.png new file mode 100644 index 0000000..b9e4511 Binary files /dev/null and b/plugins/_core/jisp/editcopy.png differ diff --git a/plugins/_core/jisp/editcut.png b/plugins/_core/jisp/editcut.png new file mode 100644 index 0000000..798eb20 Binary files /dev/null and b/plugins/_core/jisp/editcut.png differ diff --git a/plugins/_core/jisp/editpaste.png b/plugins/_core/jisp/editpaste.png new file mode 100644 index 0000000..e5f8eef Binary files /dev/null and b/plugins/_core/jisp/editpaste.png differ diff --git a/plugins/_core/jisp/empty.png b/plugins/_core/jisp/empty.png new file mode 100644 index 0000000..f144576 Binary files /dev/null and b/plugins/_core/jisp/empty.png differ diff --git a/plugins/_core/jisp/encoding.png b/plugins/_core/jisp/encoding.png new file mode 100644 index 0000000..677da85 Binary files /dev/null and b/plugins/_core/jisp/encoding.png differ diff --git a/plugins/_core/jisp/encrypted.png b/plugins/_core/jisp/encrypted.png new file mode 100644 index 0000000..2f17879 Binary files /dev/null and b/plugins/_core/jisp/encrypted.png differ diff --git a/plugins/_core/jisp/error.png b/plugins/_core/jisp/error.png new file mode 100644 index 0000000..32f948f Binary files /dev/null and b/plugins/_core/jisp/error.png differ diff --git a/plugins/_core/jisp/exit.png b/plugins/_core/jisp/exit.png new file mode 100644 index 0000000..6233a16 Binary files /dev/null and b/plugins/_core/jisp/exit.png differ diff --git a/plugins/_core/jisp/expanded.png b/plugins/_core/jisp/expanded.png new file mode 100644 index 0000000..eb2d94a Binary files /dev/null and b/plugins/_core/jisp/expanded.png differ diff --git a/plugins/_core/jisp/fax.png b/plugins/_core/jisp/fax.png new file mode 100644 index 0000000..43739a9 Binary files /dev/null and b/plugins/_core/jisp/fax.png differ diff --git a/plugins/_core/jisp/ffc.png b/plugins/_core/jisp/ffc.png new file mode 100644 index 0000000..223c0f2 Binary files /dev/null and b/plugins/_core/jisp/ffc.png differ diff --git a/plugins/_core/jisp/fgcolor.png b/plugins/_core/jisp/fgcolor.png new file mode 100644 index 0000000..bec35e0 Binary files /dev/null and b/plugins/_core/jisp/fgcolor.png differ diff --git a/plugins/_core/jisp/file.png b/plugins/_core/jisp/file.png new file mode 100644 index 0000000..9f09461 Binary files /dev/null and b/plugins/_core/jisp/file.png differ diff --git a/plugins/_core/jisp/fileclose.png b/plugins/_core/jisp/fileclose.png new file mode 100644 index 0000000..edf1f27 Binary files /dev/null and b/plugins/_core/jisp/fileclose.png differ diff --git a/plugins/_core/jisp/fileopen.png b/plugins/_core/jisp/fileopen.png new file mode 100644 index 0000000..055785c Binary files /dev/null and b/plugins/_core/jisp/fileopen.png differ diff --git a/plugins/_core/jisp/filesave.png b/plugins/_core/jisp/filesave.png new file mode 100644 index 0000000..7d48a9d Binary files /dev/null and b/plugins/_core/jisp/filesave.png differ diff --git a/plugins/_core/jisp/filter.png b/plugins/_core/jisp/filter.png new file mode 100644 index 0000000..bdaef68 Binary files /dev/null and b/plugins/_core/jisp/filter.png differ diff --git a/plugins/_core/jisp/find.png b/plugins/_core/jisp/find.png new file mode 100644 index 0000000..01a90ff Binary files /dev/null and b/plugins/_core/jisp/find.png differ diff --git a/plugins/_core/jisp/floating.png b/plugins/_core/jisp/floating.png new file mode 100644 index 0000000..5f63bde Binary files /dev/null and b/plugins/_core/jisp/floating.png differ diff --git a/plugins/_core/jisp/gadu.png b/plugins/_core/jisp/gadu.png new file mode 100644 index 0000000..b826b97 Binary files /dev/null and b/plugins/_core/jisp/gadu.png differ diff --git a/plugins/_core/jisp/gadu_away.png b/plugins/_core/jisp/gadu_away.png new file mode 100644 index 0000000..df49dcc Binary files /dev/null and b/plugins/_core/jisp/gadu_away.png differ diff --git a/plugins/_core/jisp/gadu_dnd.png b/plugins/_core/jisp/gadu_dnd.png new file mode 100644 index 0000000..df49dcc Binary files /dev/null and b/plugins/_core/jisp/gadu_dnd.png differ diff --git a/plugins/_core/jisp/gadu_invisible.png b/plugins/_core/jisp/gadu_invisible.png new file mode 100644 index 0000000..53e62ce Binary files /dev/null and b/plugins/_core/jisp/gadu_invisible.png differ diff --git a/plugins/_core/jisp/gadu_na.png b/plugins/_core/jisp/gadu_na.png new file mode 100644 index 0000000..df49dcc Binary files /dev/null and b/plugins/_core/jisp/gadu_na.png differ diff --git a/plugins/_core/jisp/gadu_offline.png b/plugins/_core/jisp/gadu_offline.png new file mode 100644 index 0000000..2d467fe Binary files /dev/null and b/plugins/_core/jisp/gadu_offline.png differ diff --git a/plugins/_core/jisp/grp_collapse.png b/plugins/_core/jisp/grp_collapse.png new file mode 100644 index 0000000..da6193a Binary files /dev/null and b/plugins/_core/jisp/grp_collapse.png differ diff --git a/plugins/_core/jisp/grp_create.png b/plugins/_core/jisp/grp_create.png new file mode 100644 index 0000000..82075ec Binary files /dev/null and b/plugins/_core/jisp/grp_create.png differ diff --git a/plugins/_core/jisp/grp_expand.png b/plugins/_core/jisp/grp_expand.png new file mode 100644 index 0000000..0eae21c Binary files /dev/null and b/plugins/_core/jisp/grp_expand.png differ diff --git a/plugins/_core/jisp/grp_off.png b/plugins/_core/jisp/grp_off.png new file mode 100644 index 0000000..9ae57b2 Binary files /dev/null and b/plugins/_core/jisp/grp_off.png differ diff --git a/plugins/_core/jisp/grp_on.png b/plugins/_core/jisp/grp_on.png new file mode 100644 index 0000000..5aa62f9 Binary files /dev/null and b/plugins/_core/jisp/grp_on.png differ diff --git a/plugins/_core/jisp/grp_rename.png b/plugins/_core/jisp/grp_rename.png new file mode 100644 index 0000000..9c77ed9 Binary files /dev/null and b/plugins/_core/jisp/grp_rename.png differ diff --git a/plugins/_core/jisp/help.png b/plugins/_core/jisp/help.png new file mode 100644 index 0000000..1257e8d Binary files /dev/null and b/plugins/_core/jisp/help.png differ diff --git a/plugins/_core/jisp/history.png b/plugins/_core/jisp/history.png new file mode 100644 index 0000000..8f748ab Binary files /dev/null and b/plugins/_core/jisp/history.png differ diff --git a/plugins/_core/jisp/home.png b/plugins/_core/jisp/home.png new file mode 100644 index 0000000..b496db6 Binary files /dev/null and b/plugins/_core/jisp/home.png differ diff --git a/plugins/_core/jisp/icondef.xml b/plugins/_core/jisp/icondef.xml new file mode 100644 index 0000000..ac7a221 --- /dev/null +++ b/plugins/_core/jisp/icondef.xml @@ -0,0 +1,363 @@ + + + + SIM Icons + 0.9.6 + SIM icons. + Vladimir Shutoff + 2004-06-11 + http://sim-im.org/ + + + sim.png + + + + + icq.png + + + msn.png + + + aim.png + + + yahoo.png + + + yahoo_offline.png + + + yahoo_away.png + + + yahoo_na.png + + + yahoo_dnd.png + + + gadu.png + + + gadu_away.png + + + gadu_na.png + + + gadu_dnd.png + + + gadu_invisible.png + + + gadu_offline.png + + + away.png + + + na.png + + + dnd.png + + + occupied.png + + + ffc.png + + + exit.png + + + button_ok.png + + + button_cancel.png + + + 1downarrow.png + + + 1uparrow.png + + + 1leftarrow.png + + + 1rightarrow.png + + + configure.png + + + fileopen.png + + + filesave.png + + + remove.png + + + error.png + + + collapsed.png + + + expanded.png + + + mail_generic.png + + + info.png + + + text.png + + + phone.png + + + fax.png + + + cell.png + + + pager.png + + + nophone.png + + + webpress.png + + + find.png + + + nonim.png + + + online_on.png + + + online_off.png + + + grp_on.png + + + grp_off.png + + + grp_create.png + + + grp_rename.png + + + home.png + + + work.png + + + security.png + + + run.png + + + network.png + + + message.png + + + file.png + + + sms.png + + + url.png + + + contacts.png + + + auth.png + + + empty.png + + + translit.png + + + bgcolor.png + + + fgcolor.png + + + pict.png + + + text_bold.png + + + text_italic.png + + + text_under.png + + + text_strike.png + + + cancel.png + + + filter.png + + + history.png + + + editcut.png + + + editcopy.png + + + editpaste.png + + + undo.png + + + redo.png + + + typing.png + + + fileclose.png + + + encrypted.png + + + listmsg.png + + + urgentmsg.png + + + help.png + + + btn_more.png + ; + + chat.png + ; + + encoding.png + + + add.png + + + new.png + + + ignorelist.png + + + floating.png + + + + + cell.png + + + birthday.png + + + more.png + + + interest.png + + + past.png + + + useronline.png + + + useroffline.png + + + userunknown.png + + + web.png + + + mailpager.png + + + icqphone.png + + + icqphonebusy.png + + + sharedfiles.png + + + jabber.png + + + register.png + + + connect.png + + + lunch.png + + + onback.png + + + onphone.png + + + alert.png + + + sound.png + + + nosound.png + + + livejournal.png + + + simcard.png + + diff --git a/plugins/_core/jisp/icq.png b/plugins/_core/jisp/icq.png new file mode 100644 index 0000000..7d56cfd Binary files /dev/null and b/plugins/_core/jisp/icq.png differ diff --git a/plugins/_core/jisp/icqphone.png b/plugins/_core/jisp/icqphone.png new file mode 100644 index 0000000..bef07ff Binary files /dev/null and b/plugins/_core/jisp/icqphone.png differ diff --git a/plugins/_core/jisp/icqphonebusy.png b/plugins/_core/jisp/icqphonebusy.png new file mode 100644 index 0000000..7df350d Binary files /dev/null and b/plugins/_core/jisp/icqphonebusy.png differ diff --git a/plugins/_core/jisp/ignorelist.png b/plugins/_core/jisp/ignorelist.png new file mode 100644 index 0000000..3c45109 Binary files /dev/null and b/plugins/_core/jisp/ignorelist.png differ diff --git a/plugins/_core/jisp/info.png b/plugins/_core/jisp/info.png new file mode 100644 index 0000000..a3808be Binary files /dev/null and b/plugins/_core/jisp/info.png differ diff --git a/plugins/_core/jisp/interest.png b/plugins/_core/jisp/interest.png new file mode 100644 index 0000000..f00b6b7 Binary files /dev/null and b/plugins/_core/jisp/interest.png differ diff --git a/plugins/_core/jisp/jabber.png b/plugins/_core/jisp/jabber.png new file mode 100644 index 0000000..4395d5d Binary files /dev/null and b/plugins/_core/jisp/jabber.png differ diff --git a/plugins/_core/jisp/license b/plugins/_core/jisp/license new file mode 100644 index 0000000..72c3cae --- /dev/null +++ b/plugins/_core/jisp/license @@ -0,0 +1 @@ +Unknown-proprietary diff --git a/plugins/_core/jisp/listmsg.png b/plugins/_core/jisp/listmsg.png new file mode 100644 index 0000000..1bc311e Binary files /dev/null and b/plugins/_core/jisp/listmsg.png differ diff --git a/plugins/_core/jisp/livejournal.png b/plugins/_core/jisp/livejournal.png new file mode 100644 index 0000000..87a1aa0 Binary files /dev/null and b/plugins/_core/jisp/livejournal.png differ diff --git a/plugins/_core/jisp/lunch.png b/plugins/_core/jisp/lunch.png new file mode 100644 index 0000000..1a81203 Binary files /dev/null and b/plugins/_core/jisp/lunch.png differ diff --git a/plugins/_core/jisp/mail_generic.png b/plugins/_core/jisp/mail_generic.png new file mode 100644 index 0000000..47715c4 Binary files /dev/null and b/plugins/_core/jisp/mail_generic.png differ diff --git a/plugins/_core/jisp/mailpager.png b/plugins/_core/jisp/mailpager.png new file mode 100644 index 0000000..a7fc5fd Binary files /dev/null and b/plugins/_core/jisp/mailpager.png differ diff --git a/plugins/_core/jisp/message.png b/plugins/_core/jisp/message.png new file mode 100644 index 0000000..dc669e8 Binary files /dev/null and b/plugins/_core/jisp/message.png differ diff --git a/plugins/_core/jisp/more.png b/plugins/_core/jisp/more.png new file mode 100644 index 0000000..f4abd06 Binary files /dev/null and b/plugins/_core/jisp/more.png differ diff --git a/plugins/_core/jisp/msn.png b/plugins/_core/jisp/msn.png new file mode 100644 index 0000000..f70d341 Binary files /dev/null and b/plugins/_core/jisp/msn.png differ diff --git a/plugins/_core/jisp/na.png b/plugins/_core/jisp/na.png new file mode 100644 index 0000000..e82efcf Binary files /dev/null and b/plugins/_core/jisp/na.png differ diff --git a/plugins/_core/jisp/network.png b/plugins/_core/jisp/network.png new file mode 100644 index 0000000..43b91a8 Binary files /dev/null and b/plugins/_core/jisp/network.png differ diff --git a/plugins/_core/jisp/new.png b/plugins/_core/jisp/new.png new file mode 100644 index 0000000..a79c0b8 Binary files /dev/null and b/plugins/_core/jisp/new.png differ diff --git a/plugins/_core/jisp/nonim.png b/plugins/_core/jisp/nonim.png new file mode 100644 index 0000000..275b2bb Binary files /dev/null and b/plugins/_core/jisp/nonim.png differ diff --git a/plugins/_core/jisp/nophone.png b/plugins/_core/jisp/nophone.png new file mode 100644 index 0000000..f91c6b2 Binary files /dev/null and b/plugins/_core/jisp/nophone.png differ diff --git a/plugins/_core/jisp/nosound.png b/plugins/_core/jisp/nosound.png new file mode 100644 index 0000000..1fb6947 Binary files /dev/null and b/plugins/_core/jisp/nosound.png differ diff --git a/plugins/_core/jisp/occupied.png b/plugins/_core/jisp/occupied.png new file mode 100644 index 0000000..7a5928e Binary files /dev/null and b/plugins/_core/jisp/occupied.png differ diff --git a/plugins/_core/jisp/onback.png b/plugins/_core/jisp/onback.png new file mode 100644 index 0000000..976fe19 Binary files /dev/null and b/plugins/_core/jisp/onback.png differ diff --git a/plugins/_core/jisp/online_off.png b/plugins/_core/jisp/online_off.png new file mode 100644 index 0000000..1d95664 Binary files /dev/null and b/plugins/_core/jisp/online_off.png differ diff --git a/plugins/_core/jisp/online_on.png b/plugins/_core/jisp/online_on.png new file mode 100644 index 0000000..846c8ca Binary files /dev/null and b/plugins/_core/jisp/online_on.png differ diff --git a/plugins/_core/jisp/onphone.png b/plugins/_core/jisp/onphone.png new file mode 100644 index 0000000..b70262c Binary files /dev/null and b/plugins/_core/jisp/onphone.png differ diff --git a/plugins/_core/jisp/pager.png b/plugins/_core/jisp/pager.png new file mode 100644 index 0000000..01ee69b Binary files /dev/null and b/plugins/_core/jisp/pager.png differ diff --git a/plugins/_core/jisp/past.png b/plugins/_core/jisp/past.png new file mode 100644 index 0000000..a4c9cf8 Binary files /dev/null and b/plugins/_core/jisp/past.png differ diff --git a/plugins/_core/jisp/phone.png b/plugins/_core/jisp/phone.png new file mode 100644 index 0000000..4ee6f4b Binary files /dev/null and b/plugins/_core/jisp/phone.png differ diff --git a/plugins/_core/jisp/pict.png b/plugins/_core/jisp/pict.png new file mode 100644 index 0000000..35b3376 Binary files /dev/null and b/plugins/_core/jisp/pict.png differ diff --git a/plugins/_core/jisp/redo.png b/plugins/_core/jisp/redo.png new file mode 100644 index 0000000..6ffe477 Binary files /dev/null and b/plugins/_core/jisp/redo.png differ diff --git a/plugins/_core/jisp/register.png b/plugins/_core/jisp/register.png new file mode 100644 index 0000000..b68e5de Binary files /dev/null and b/plugins/_core/jisp/register.png differ diff --git a/plugins/_core/jisp/remove.png b/plugins/_core/jisp/remove.png new file mode 100644 index 0000000..4809fc6 Binary files /dev/null and b/plugins/_core/jisp/remove.png differ diff --git a/plugins/_core/jisp/run.png b/plugins/_core/jisp/run.png new file mode 100644 index 0000000..a8c7b4f Binary files /dev/null and b/plugins/_core/jisp/run.png differ diff --git a/plugins/_core/jisp/security.png b/plugins/_core/jisp/security.png new file mode 100644 index 0000000..6f58c92 Binary files /dev/null and b/plugins/_core/jisp/security.png differ diff --git a/plugins/_core/jisp/sharedfiles.png b/plugins/_core/jisp/sharedfiles.png new file mode 100644 index 0000000..5730419 Binary files /dev/null and b/plugins/_core/jisp/sharedfiles.png differ diff --git a/plugins/_core/jisp/sim.png b/plugins/_core/jisp/sim.png new file mode 100644 index 0000000..d774a63 Binary files /dev/null and b/plugins/_core/jisp/sim.png differ diff --git a/plugins/_core/jisp/simcard.png b/plugins/_core/jisp/simcard.png new file mode 100644 index 0000000..1845330 Binary files /dev/null and b/plugins/_core/jisp/simcard.png differ diff --git a/plugins/_core/jisp/sms.png b/plugins/_core/jisp/sms.png new file mode 100644 index 0000000..7beec5b Binary files /dev/null and b/plugins/_core/jisp/sms.png differ diff --git a/plugins/_core/jisp/sound.png b/plugins/_core/jisp/sound.png new file mode 100644 index 0000000..5d88396 Binary files /dev/null and b/plugins/_core/jisp/sound.png differ diff --git a/plugins/_core/jisp/text.png b/plugins/_core/jisp/text.png new file mode 100644 index 0000000..00b5218 Binary files /dev/null and b/plugins/_core/jisp/text.png differ diff --git a/plugins/_core/jisp/text_bold.png b/plugins/_core/jisp/text_bold.png new file mode 100644 index 0000000..da866f4 Binary files /dev/null and b/plugins/_core/jisp/text_bold.png differ diff --git a/plugins/_core/jisp/text_italic.png b/plugins/_core/jisp/text_italic.png new file mode 100644 index 0000000..d89abae Binary files /dev/null and b/plugins/_core/jisp/text_italic.png differ diff --git a/plugins/_core/jisp/text_strike.png b/plugins/_core/jisp/text_strike.png new file mode 100644 index 0000000..e2ca3fe Binary files /dev/null and b/plugins/_core/jisp/text_strike.png differ diff --git a/plugins/_core/jisp/text_under.png b/plugins/_core/jisp/text_under.png new file mode 100644 index 0000000..3c9e0e8 Binary files /dev/null and b/plugins/_core/jisp/text_under.png differ diff --git a/plugins/_core/jisp/translit.png b/plugins/_core/jisp/translit.png new file mode 100644 index 0000000..7f87a27 Binary files /dev/null and b/plugins/_core/jisp/translit.png differ diff --git a/plugins/_core/jisp/typing.png b/plugins/_core/jisp/typing.png new file mode 100644 index 0000000..d4ac4f4 Binary files /dev/null and b/plugins/_core/jisp/typing.png differ diff --git a/plugins/_core/jisp/undo.png b/plugins/_core/jisp/undo.png new file mode 100644 index 0000000..ef24ce3 Binary files /dev/null and b/plugins/_core/jisp/undo.png differ diff --git a/plugins/_core/jisp/urgentmsg.png b/plugins/_core/jisp/urgentmsg.png new file mode 100644 index 0000000..764ebdd Binary files /dev/null and b/plugins/_core/jisp/urgentmsg.png differ diff --git a/plugins/_core/jisp/url.png b/plugins/_core/jisp/url.png new file mode 100644 index 0000000..fa3fc34 Binary files /dev/null and b/plugins/_core/jisp/url.png differ diff --git a/plugins/_core/jisp/useroffline.png b/plugins/_core/jisp/useroffline.png new file mode 100644 index 0000000..8fe1577 Binary files /dev/null and b/plugins/_core/jisp/useroffline.png differ diff --git a/plugins/_core/jisp/useronline.png b/plugins/_core/jisp/useronline.png new file mode 100644 index 0000000..ac93627 Binary files /dev/null and b/plugins/_core/jisp/useronline.png differ diff --git a/plugins/_core/jisp/userunknown.png b/plugins/_core/jisp/userunknown.png new file mode 100644 index 0000000..a44b5ea Binary files /dev/null and b/plugins/_core/jisp/userunknown.png differ diff --git a/plugins/_core/jisp/web.png b/plugins/_core/jisp/web.png new file mode 100644 index 0000000..bb0a0e0 Binary files /dev/null and b/plugins/_core/jisp/web.png differ diff --git a/plugins/_core/jisp/webpress.png b/plugins/_core/jisp/webpress.png new file mode 100644 index 0000000..b6e1842 Binary files /dev/null and b/plugins/_core/jisp/webpress.png differ diff --git a/plugins/_core/jisp/work.png b/plugins/_core/jisp/work.png new file mode 100644 index 0000000..9ca47cb Binary files /dev/null and b/plugins/_core/jisp/work.png differ diff --git a/plugins/_core/jisp/yahoo.png b/plugins/_core/jisp/yahoo.png new file mode 100644 index 0000000..f8b87cd Binary files /dev/null and b/plugins/_core/jisp/yahoo.png differ diff --git a/plugins/_core/jisp/yahoo_away.png b/plugins/_core/jisp/yahoo_away.png new file mode 100644 index 0000000..f5110e8 Binary files /dev/null and b/plugins/_core/jisp/yahoo_away.png differ diff --git a/plugins/_core/jisp/yahoo_dnd.png b/plugins/_core/jisp/yahoo_dnd.png new file mode 100644 index 0000000..745927f Binary files /dev/null and b/plugins/_core/jisp/yahoo_dnd.png differ diff --git a/plugins/_core/jisp/yahoo_offline.png b/plugins/_core/jisp/yahoo_offline.png new file mode 100644 index 0000000..b29fe5e Binary files /dev/null and b/plugins/_core/jisp/yahoo_offline.png differ diff --git a/plugins/_core/libintl.cpp b/plugins/_core/libintl.cpp new file mode 100644 index 0000000..498a787 --- /dev/null +++ b/plugins/_core/libintl.cpp @@ -0,0 +1,423 @@ +/* libintl.cpp -- gettext related functions from glibc-2.0.5 + Copyright (C) 1995 Software Foundation, Inc. + +This file is part of the KDE libraries, but it's derived work out +of glibc. The master sources can be found in + + bindtextdom.c + dcgettext.c + dgettext.c + explodename.c + finddomain.c + gettext.c + gettext.h + gettextP.h + hash-string.h + l10nflist.c + libintl.h + loadinfo.h + loadmsgcat.c + localealias.c + textdomain.c + +which are part of glibc. The license is the same as in GLIBC, which +is the GNU Library General Public License. See COPYING.LIB for more +details. + +*/ + +/* gettext.c -- implementation of gettext(3) function + Copyright (C) 1995 Software Foundation, Inc. + +This file is part of the GNU C Library. Its master source is NOT part of +the C library, however. The master source lives in /gd/gnu/lib. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include "config.h" +#include "qglobal.h" + +#if !defined(USE_KDE) + +#include + +#if defined HAVE_STRING_H +# include +#else +# include +#endif + +#include +#include +#include +#include + +#if defined HAVE_UNISTD_H +# include +#endif + +#if (defined HAVE_MMAP && defined HAVE_MUNMAP) +# include +#endif + +#ifndef W +# define W(flag, data) ((flag) ? SWAP (data) : (data)) +#endif + +typedef quint32 nls_uint32; + +struct loaded_domain +{ + const char *data; +#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) + int use_mmap; + size_t mmap_size; +#endif + int must_swap; + nls_uint32 nstrings; + struct string_desc *orig_tab; + struct string_desc *trans_tab; + nls_uint32 hash_size; + nls_uint32 *hash_tab; +}; + +struct loaded_l10nfile +{ + const char *filename; + int decided; + + const void *data; + + loaded_l10nfile() : filename(0), decided(0), data(0) {} +}; + +void k_nl_load_domain(struct loaded_l10nfile *__domain); + +static inline nls_uint32 +SWAP (nls_uint32 i) +{ + return (i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | (i >> 24); +} + +/* @@ end of prolog @@ */ + +/* The magic number of the GNU message catalog format. */ +#define _MAGIC 0x950412de +#define _MAGIC_SWAPPED 0xde120495 + +/* Revision number of the currently used .mo (binary) file format. */ +#define MO_REVISION_NUMBER 0 + + +/* Defines the so called `hashpjw' function by P.J. Weinberger + [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools, + 1986, 1987 Bell Telephone Laboratories, Inc.] */ +static inline unsigned long hash_string (const char *__str_param); + +/* @@ end of prolog @@ */ + +/* Header for binary .mo file format. */ +struct mo_file_header +{ + /* The magic number. */ + nls_uint32 magic; + /* The revision number of the file format. */ + nls_uint32 revision; + /* The number of strings pairs. */ + nls_uint32 nstrings; + /* Offset of table with start offsets of original strings. */ + nls_uint32 orig_tab_offset; + /* Offset of table with start offsets of translation strings. */ + nls_uint32 trans_tab_offset; + /* Size of hashing table. */ + nls_uint32 hash_tab_size; + /* Offset of first hashing entry. */ + nls_uint32 hash_tab_offset; +}; + +struct string_desc +{ + /* Length of addressed string. */ + nls_uint32 length; + /* Offset of string in file. */ + nls_uint32 offset; +}; + +/* Prototypes for local functions. */ +char *k_nl_find_msg (struct loaded_l10nfile *domain_file, + const char *msgid); + +char * +k_nl_find_msg (struct loaded_l10nfile *domain_file, const char *msgid) +{ + size_t top, act, bottom; + struct loaded_domain *domain; + + if (domain_file->decided == 0) + k_nl_load_domain (domain_file); + + if (domain_file->data == NULL) + return NULL; + + domain = (struct loaded_domain *) domain_file->data; + + /* Locate the MSGID and its translation. */ + if (domain->hash_size > 2 && domain->hash_tab != NULL) + { + /* Use the hashing table. */ + nls_uint32 len = strlen (msgid); + nls_uint32 hash_val = hash_string (msgid); + nls_uint32 idx = hash_val % domain->hash_size; + nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2)); + nls_uint32 nstr = W (domain->must_swap, domain->hash_tab[idx]); + + if (nstr == 0) + /* Hash table entry is empty. */ + return NULL; + + if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) == len + && strcmp (msgid, + domain->data + W (domain->must_swap, + domain->orig_tab[nstr - 1].offset)) == 0) + return (char *) domain->data + W (domain->must_swap, + domain->trans_tab[nstr - 1].offset); + + while (1) + { + if (idx >= domain->hash_size - incr) + idx -= domain->hash_size - incr; + else + idx += incr; + + nstr = W (domain->must_swap, domain->hash_tab[idx]); + if (nstr == 0) + /* Hash table entry is empty. */ + return NULL; + + if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) == len + && strcmp (msgid, + domain->data + W (domain->must_swap, + domain->orig_tab[nstr - 1].offset)) + == 0) + return (char *) domain->data + + W (domain->must_swap, domain->trans_tab[nstr - 1].offset); + } + /* NOTREACHED */ + } + + /* Now we try the default method: binary search in the sorted + array of messages. */ + bottom = 0; + top = domain->nstrings; + act = top; + while (bottom < top) + { + int cmp_val; + + act = (bottom + top) / 2; + cmp_val = strcmp (msgid, domain->data + + W (domain->must_swap, + domain->orig_tab[act].offset)); + if (cmp_val < 0) + top = act; + else if (cmp_val > 0) + bottom = act + 1; + else + break; + } + + /* If an translation is found return this. */ + return bottom >= top ? NULL : (char *) domain->data + + W (domain->must_swap, + domain->trans_tab[act].offset); +} + +/* @@ begin of epilog @@ */ +/* We assume to have `unsigned long int' value with at least 32 bits. */ +#define HASHWORDBITS 32 + +static inline unsigned long +hash_string (const char *str_param) +{ + unsigned long int hval, g; + const char *str = str_param; + + /* Compute the hash value for the given string. */ + hval = 0; + while (*str != '\0') + { + hval <<= 4; + hval += (unsigned long) *str++; + g = hval & ((unsigned long) 0xf << (HASHWORDBITS - 4)); + if (g != 0) + { + hval ^= g >> (HASHWORDBITS - 8); + hval ^= g; + } + } + return hval; +} + +/* Load the message catalogs specified by FILENAME. If it is no valid + message catalog do nothing. */ +void +k_nl_load_domain (struct loaded_l10nfile *domain_file) +{ + int fd; + struct stat st; + struct mo_file_header *data = (struct mo_file_header *) -1; +#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) + int use_mmap = 0; +#endif + struct loaded_domain *domain; + + domain_file->decided = 1; + domain_file->data = NULL; + + /* If the record does not represent a valid locale the FILENAME + might be NULL. This can happen when according to the given + specification the locale file name is different for XPG and CEN + syntax. */ + if (domain_file->filename == NULL) + return; + + /* Try to open the addressed file. */ + fd = open (domain_file->filename, O_RDONLY); + if (fd == -1) + return; + + /* We must know about the size of the file. */ + if (fstat (fd, &st) != 0 + && st.st_size < (off_t) sizeof (struct mo_file_header)) + { + /* Something went wrong. */ + close (fd); + return; + } + +#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) + /* Now we are ready to load the file. If mmap() is available we try + this first. If not available or it failed we try to load it. */ + data = (struct mo_file_header *) mmap (NULL, st.st_size, PROT_READ, + MAP_PRIVATE, fd, 0); + + if (data != (struct mo_file_header *) -1) + { + /* mmap() call was successful. */ + close (fd); + use_mmap = 1; + } +#endif + + /* If the data is not yet available (i.e. mmap'ed) we try to load + it manually. */ + if (data == (struct mo_file_header *) -1) + { + off_t to_read; + char *read_ptr; + + data = (struct mo_file_header *) malloc (st.st_size); + if (data == NULL) + return; + + to_read = st.st_size; + read_ptr = (char *) data; + do + { + long int nb = (long int) read (fd, read_ptr, to_read); + if (nb == -1) + { + close (fd); + return; + } + + read_ptr += nb; + to_read -= nb; + } + while (to_read > 0); + + close (fd); + } + + /* Using the magic number we can test whether it really is a message + catalog file. */ + if (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED) + { + /* The magic number is wrong: not a message catalog file. */ +#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) + if (use_mmap) + munmap ((char *) data, st.st_size); + else +#endif + free (data); + return; + } + + domain_file->data + = (struct loaded_domain *) malloc (sizeof (struct loaded_domain)); + if (domain_file->data == NULL) + return; + + domain = (struct loaded_domain *) domain_file->data; + domain->data = (char *) data; +#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) + domain->use_mmap = use_mmap; + domain->mmap_size = st.st_size; +#endif + domain->must_swap = data->magic != _MAGIC; + + /* Fill in the information about the available tables. */ + switch (W (domain->must_swap, data->revision)) + { + case 0: + domain->nstrings = W (domain->must_swap, data->nstrings); + domain->orig_tab = (struct string_desc *) + ((char *) data + W (domain->must_swap, data->orig_tab_offset)); + domain->trans_tab = (struct string_desc *) + ((char *) data + W (domain->must_swap, data->trans_tab_offset)); + domain->hash_size = W (domain->must_swap, data->hash_tab_size); + domain->hash_tab = (nls_uint32 *) + ((char *) data + W (domain->must_swap, data->hash_tab_offset)); + break; + default: + /* This is an illegal revision. */ +#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) + if (use_mmap) + munmap ((char *) data, st.st_size); + else +#endif + free (data); + free (domain); + domain_file->data = NULL; + return; + } +} + +void +k_nl_unload_domain (struct loaded_domain *domain) +{ +#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) + if (domain->use_mmap) + munmap ((caddr_t) domain->data, domain->mmap_size); + else +# endif + free ((void *) domain->data); + + free (domain); +} + +#endif + diff --git a/plugins/_core/logindlg.cpp b/plugins/_core/logindlg.cpp new file mode 100644 index 0000000..ba599cd --- /dev/null +++ b/plugins/_core/logindlg.cpp @@ -0,0 +1,650 @@ +/*************************************************************************** +logindlg.cpp - description +------------------- +begin : Sun Mar 17 2002 +copyright : (C) 2002 by Vladimir Shutoff +email : vovan@shutoff.ru +***************************************************************************/ + +/*************************************************************************** +* * +* 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. * +* * +***************************************************************************/ + +#include "contacts/client.h" +#include "contacts/protocolmanager.h" +#include "core.h" +#include "icons.h" +#include "log.h" +#include "profilemanager.h" +#include "simgui/ballonmsg.h" +#include "simgui/linklabel.h" +#include "logindlg.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace SIM; + +LoginDialog::LoginDialog(bool bInit, ClientPtr client, const QString &text, const QString &loginProfile) + : QDialog(NULL) + , m_loginProfile(loginProfile) + , m_newProfile(false) + , m_bLogin(false) + , m_bInit(bInit) + , m_bProfileChanged(false) + , m_client(client) + , m_pict(NULL) + , m_vboxlayout(NULL) + , m_hboxlayout(NULL) + , m_txt(NULL) + , m_edt(NULL) + , m_line(NULL) + , m_lnkHelp(NULL) +{ + setupUi(this); + setObjectName("logindlg"); + setModal(client ? false : true); + //setAttribute(Qt::WA_DeleteOnClose, true); + QSettings settings; + m_profile = settings.value("Profile").toString(); + + if(m_loginProfile.isEmpty()) + btnDelete->hide(); + SET_WNDPROC("login") + setButtonsPict(this); + lblMessage->setText(text); + if( text.isEmpty() ) + lblMessage->hide(); + if (m_client) + { + setWindowTitle(windowTitle() + ' ' + client->name()); + setWindowIcon(Icon(m_client->protocol()->description()->icon)); + chkSave->hide(); + chkNoShow->hide(); + btnDelete->hide(); + btnRename->hide(); + cmbProfile->hide(); + lblProfile->hide(); + } + else + { + setWindowTitle(i18n("Select profile")); + setWindowIcon(Icon("SIM")); + } + for(int i = 0; i < cmbProfile->count(); i++) + { + if(cmbProfile->itemText(i) == m_profile) + { + cmbProfile->setCurrentIndex(i); + break; + } + } + + chkSave->setChecked(settings.value("SavePasswd").toBool()); + chkNoShow->setChecked(settings.value("NoShow").toBool()); + connect(chkSave, SIGNAL(toggled(bool)), this, SLOT(saveToggled(bool))); + saveToggled(settings.value("SavePasswd").toBool()); + fill(); + connect(cmbProfile, SIGNAL(activated(int)), this, SLOT(profileChanged(int))); + connect(btnDelete, SIGNAL(clicked()), this, SLOT(profileDelete())); + connect(btnRename, SIGNAL(clicked()), this, SLOT(profileRename())); + + labelNew->hide(); + e_newName->hide(); + profileChanged(cmbProfile->currentIndex()); + connect(e_newName,SIGNAL(textChanged(const QString&)),SLOT(newNameChanged(const QString&))); + + cmbProfile->setFocus(); + + //CorePlugin::m_plugin->setProfile(CorePlugin::m_plugin->getProfile()); //This was a temporary testfix ;) + //init setProfile with QString::null is here a bad idea because f.e. on icq-disconnect or any bad login/password combination this dialog comes up, + //the profile-name is still the same, but get lost if empty initialized, and SIM saves all content, history, styles, pictures not in Profile but in GLOBAL Folder, this has to be prevented. + + //log(L_WARN, QString("PROFILE SET TO QString::null in File: %1 Function: %2 Line: %3").arg(__FILE__).arg(__FUNCTION__).arg(__LINE__)); +} + +LoginDialog::~LoginDialog() +{ +} + +void LoginDialog::saveToggled(bool bState) +{ + if (!bState) + chkNoShow->setChecked(false); + chkNoShow->setEnabled(bState); +} + +void LoginDialog::closeEvent(QCloseEvent *e) +{ + if (m_bLogin) + { + e->ignore(); + stopLogin(); + return; + } + QDialog::closeEvent(e); +} + +void LoginDialog::accept() +{ + if(m_bLogin) + { + stopLogin(); + return; + } + QSettings settings; + if (m_client) + { + startLogin(); + QString prev = m_client->getPreviousPassword(); + if (prev.isEmpty()) + m_client->setPreviousPassword(m_client->getPassword()); + m_client->setPassword(passwords[0]->text()); + unsigned status = m_client->getStatus(); + if (status == STATUS_OFFLINE) + status = STATUS_ONLINE; + m_client->setStatus(status, m_client->getCommonStatus()); + QDialog::accept(); + return; + } + + getContacts()->clearClients(); + int n = cmbProfile->currentIndex(); + if(n == cmbProfile->count() - 1) + { + m_profile = QString::null; + m_newProfile = true; + m_newProfileName = e_newName->text(); + if(!ProfileManager::instance()->newProfile(m_newProfileName)) + { + QMessageBox::information(NULL, i18n("Create Profile"), i18n("Error while creating a new profile"), QMessageBox::Ok); + return; + } + ProfileManager::instance()->selectProfile(m_newProfileName); + QDialog::accept(); + return; + } + if (n < 0) + { + settings.setValue("SavePasswd", chkSave->isChecked()); + settings.setValue("NoShow", chkNoShow->isChecked()); + m_profile = QString::null; + emit changeProfile(QString::null); + QDialog::accept(); + return; + } + + m_profile = cmbProfile->currentText(); + log(L_DEBUG, "Profile: %s", qPrintable(m_profile)); + settings.setValue("Profile", m_profile); + settings.setValue("SavePasswd", chkSave->isChecked()); + settings.setValue("NoShow", chkNoShow->isChecked()); + + // Probably, it shouldn't be here + ProfileManager::instance()->selectProfile(m_profile); + emit changeProfile(m_profile); + + ClientList clients; + loadClients(m_profile, clients); + clients.addToContacts(); + getContacts()->load(); + + m_bLogin = false; + unsigned j = 0; + for (int i = 0; i < passwords.size(); i++) + { + Client *client = NULL; + while (j < getContacts()->nClients()) + { + client = getContacts()->getClient(j++); + if ((client->protocol()->description()->flags & PROTOCOL_NO_AUTH) == 0) + break; + client = NULL; + } + if (client == NULL) + break; + client->setSavePassword(chkSave->isChecked()); + QString pswd = client->getPassword(); + QString new_pswd = passwords[i]->text(); + if (pswd != new_pswd) + { + QString prev = client->getPreviousPassword(); + if (!prev.isEmpty()) + client->setPreviousPassword(pswd); + client->setPassword(new_pswd); + m_bLogin = true; + } + } + if(m_bLogin) + { + startLogin(); + for (int i = 0; i < passwords.size(); i++) + { + Client *client = getContacts()->getClient(i); + unsigned status = client->getStatus(); + if (status == STATUS_OFFLINE) + status = STATUS_ONLINE; + client->setStatus(status, client->getCommonStatus()); + } + QDialog::accept(); + return; + } + QDialog::accept(); + +} + +void LoginDialog::reject() +{ + if (m_bLogin) + { + stopLogin(); + return; + } + QDialog::reject(); +} + +void LoginDialog::profileChanged(int) +{ + if (m_client) + return; + int n = cmbProfile->currentIndex(); + if (n < 0) + { + clearInputs(); + buttonOk->setEnabled(false); + btnDelete->setEnabled(false); + btnRename->hide(); + return; + } + buttonOk->setEnabled(true); + if (n >= (int)cmbProfile->count() - 1) + { + groupBoxPasswords->hide(); + clearInputs(); + buttonOk->setEnabled(true); + btnDelete->setEnabled(false); + btnRename->hide(); + labelNew->show(); + e_newName->show(); + newNameChanged(e_newName->text()); + } + else + { + btnRename->show(); + labelNew->hide(); + e_newName->hide(); + clearInputs(); + ProfileManager::instance()->selectProfile(cmbProfile->currentText()); + ClientList clients; + loadClients(cmbProfile->currentText(), clients); + unsigned nClients = 0; + unsigned i; + for (i = 0; i < clients.size(); i++) + { + if (clients[i]->protocol()->description()->flags & PROTOCOL_NO_AUTH) + continue; + nClients++; + } + groupBoxPasswords->show(); + + unsigned row = 2; + for (unsigned i = 0; i < clients.size(); i++) + { + if (clients[i]->protocol()->description()->flags & PROTOCOL_NO_AUTH) + continue; + makeInputs(row, clients[i]); + } + btnDelete->setEnabled(m_loginProfile == cmbProfile->currentText()); + buttonOk->setEnabled(false); + pswdChanged(""); + // is pressed otherwise sim will overwrite wrong config file on + // exit. + } + QTimer::singleShot(0, this, SLOT(adjust())); +} + +void LoginDialog::adjust() +{ + int h = minimumSizeHint().height(); + resize(width(), h); + move(x(), (qApp->desktop()->height() - h) / 2); +} + +static void rmDir(const QString &path) +{ + QDir d(path); + QStringList l = d.entryList(QDir::Dirs); + QStringList::Iterator it; + for (it = l.begin(); it != l.end(); ++it) + { + if ((*it) == "." || (*it) == "..") continue; + QString p = path; + p += '/'; + p += *it; + rmDir(p); + } + l = d.entryList(); + for (it = l.begin(); it != l.end(); ++it) + { + if ((*it) == "." || (*it) == "..") continue; + QString p = path; + p += '/'; + p += *it; + d.remove(p); + } + d.rmdir(path); +} + +void LoginDialog::makeInputs(unsigned &row, ClientPtr client) +{ + m_pict = new QLabel(groupBoxPasswords); + m_pict->setPixmap(Pict(client->protocol()->description()->icon)); + picts.push_back(m_pict); + + m_vboxlayout = new QVBoxLayout; + verticalLayout->addLayout(m_vboxlayout); + m_hboxlayout = new QHBoxLayout; + m_vboxlayout->addLayout(m_hboxlayout); + m_hboxlayout->addWidget(m_pict); + m_pict->show(); + + m_txt = new QLabel(groupBoxPasswords); + m_txt->setText(client->name()); + m_txt->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred ); + m_edt = new QLineEdit(groupBoxPasswords); + m_edt->setText(client->getPassword()); + m_edt->setEchoMode(QLineEdit::Password); + connect(m_edt, SIGNAL(textChanged(const QString&)), this, SLOT(pswdChanged(const QString&))); + passwords.push_back(m_edt); + texts.push_back(m_txt); + m_hboxlayout->addWidget(m_txt); + m_vboxlayout->addWidget(m_edt); + m_txt->show(); + m_edt->show(); + QString helpUrl = client->protocol()->description()->accel; + if (!helpUrl.isEmpty()) + { + m_lnkHelp = new LinkLabel(groupBoxPasswords); + m_vboxlayout->addWidget(m_lnkHelp); + m_lnkHelp->setText(i18n("Forgot password?")); + m_lnkHelp->setUrl(i18n(helpUrl)); + m_lnkHelp->show(); + links.push_back(m_lnkHelp); + } + + m_line = new QFrame(groupBoxPasswords); + m_line->setFrameShape(QFrame::HLine); + m_line->setFrameShadow(QFrame::Sunken); + m_vboxlayout->addWidget(m_line); + lines.push_back(m_line); + + row++; +} + +void LoginDialog::fill() +{ + if(m_client) + { + unsigned row = 2; + makeInputs(row, m_client); + return; + } + cmbProfile->clear(); + QSettings settings; + QString profile = settings.value("Profile").toString(); + + int newCur = -1; + cmbProfile->addItems(ProfileManager::instance()->enumProfiles()); + for(int i = 0; i < cmbProfile->count(); i++) + { + if(cmbProfile->itemText(i) == profile) + newCur = i; + } + cmbProfile->insertItem(INT_MAX, i18n("New profile")); + if (newCur != - 1) + { + cmbProfile->setCurrentIndex(newCur); + } + else + { + cmbProfile->setCurrentIndex(cmbProfile->count() - 1); + } +} + +void LoginDialog::clearInputs() +{ + qDeleteAll(picts); + picts.clear(); + qDeleteAll(texts); + texts.clear(); + qDeleteAll(passwords); + passwords.clear(); + qDeleteAll(links); + links.clear(); + qDeleteAll(lines); + lines.clear(); +} + +void LoginDialog::pswdChanged(const QString&) +{ + int i; + for (i = 0; i < passwords.size(); i++) + if (passwords[i]->text().isEmpty()) + break; + buttonOk->setEnabled(i >= passwords.size()); +} + +void LoginDialog::profileDelete() +{ + /* + int n = cmbProfile->currentItem(); + if ((n < 0) || (n >= (int)(CorePlugin::m_plugin->m_profiles.size()))) + return; + */ + QString curProfile = cmbProfile->currentText(); + ProfileManager::instance()->removeProfile(curProfile); + clearInputs(); + btnDelete->setEnabled(false); + fill(); +} + +void LoginDialog::profileRename() +{ + QString old_name = cmbProfile->currentText(); + + QString name = old_name; + QDir d(ProfileManager::instance()->rootPath()); + while(1) { + bool ok = false; + name = QInputDialog::getText(this,i18n("Rename Profile"), i18n("Please enter a new name for the profile."), + QLineEdit::Normal, name, &ok); + if(!ok) + return; + if(d.exists(name)) { + QMessageBox::information(this, i18n("Rename Profile"), i18n("There is already another profile with this name. Please choose another."), QMessageBox::Ok); + continue; + } + /* + else if(!d.rename(CorePlugin::m_plugin->m_profiles[cmbProfile->currentIndex()], name)) { + QMessageBox::information(this, i18n("Rename Profile"), i18n("Unable to rename the profile. Please do not use any special characters."), QMessageBox::Ok); + continue; + } + */ + break; + } + ProfileManager::instance()->renameProfile(old_name, name); + fill(); +} + +void LoginDialog::startLogin() +{ + m_bLogin = true; + cmbProfile->setEnabled(false); + buttonOk->setEnabled(false); + btnDelete->setEnabled(false); + btnRename->setEnabled(false); + chkNoShow->setEnabled(false); + chkSave->setEnabled(false); + for (int i = 0; i < passwords.size(); i++) + passwords[i]->setEnabled(false); +} + +void LoginDialog::stopLogin() +{ + m_bLogin = false; + cmbProfile->setEnabled(true); + buttonOk->setEnabled(true); + btnDelete->setEnabled(true); + btnRename->setEnabled(true); + chkSave->setEnabled(true); + saveToggled(chkSave->isChecked()); + for (int i = 0; i < passwords.size(); i++) + passwords[i]->setEnabled(true); +} + +void LoginDialog::loginComplete() +{ + if (!m_bLogin) + return; + if (m_client) + m_client->setStatus(m_client->getManualStatus(), m_client->getCommonStatus()); + else + for (int i = 0; i < passwords.size(); i++) + { + Client *client = getContacts()->getClient(i); + client->setStatus(client->getManualStatus(), client->getCommonStatus()); + } + m_bLogin = false; + hide(); + close(); + setResult(true); +} + +bool LoginDialog::processEvent(Event *e) +{ + switch (e->type()) + { + case eEventClientChanged: + { + EventClientChanged *ecc = static_cast(e); + if (m_bLogin && (m_client == NULL || ecc->client() == m_client)){ + if (ecc->client()->getState() == Client::Connected) + { + QTimer::singleShot(0, this, SLOT(loginComplete())); + return false; + } + } + break; + } + case eEventClientNotification: + if (m_bLogin) + { + EventClientNotification *ee = static_cast(e); + const EventNotification::ClientNotificationData &client_notification_data = ee->data(); + if (!m_client) + { + for (int i = 0; i < passwords.size(); i++){ + Client *client = getContacts()->getClient(i); + if (client->getState() != Client::Error) + return true; + } + } + else if (client_notification_data.client != m_client) + return false; + stopLogin(); + QString msg; + if (!client_notification_data.text.isEmpty()) + msg = i18n(client_notification_data.text).arg(client_notification_data.args); + else + msg = i18n("Login failed"); + if (msg.length()) + { + raiseWindow(this); + BalloonMsg::message(msg, buttonOk); + } + return true; + } + break; + default: + break; + } + return false; +} + +void LoginDialog::newNameChanged( const QString &text ) { + if( text.isEmpty() ) { + buttonOk->setEnabled( false ); + return; + } + + QDir d(ProfileManager::instance()->rootPath()); + buttonOk->setEnabled( !d.exists( text ) ); +} + +void LoginDialog::loadClients(const QString& profilename, SIM::ClientList& clients) +{ + QString cfgName = ProfileManager::instance()->rootPath() + QDir::separator() + profilename + QDir::separator() + "clients.conf"; + QFile f(cfgName); + if (!f.open(QIODevice::ReadOnly)) + { + log(L_ERROR, "[1]Can't open %s", qPrintable(cfgName)); + return; + } + Buffer cfg = f.readAll(); + for (;;) + { + QByteArray section = cfg.getSection(); + if (section.isEmpty()) + break; + QString s = section; // ? + ClientPtr client = loadClient(s, &cfg); + if (client) + clients.push_back(client); + } +} + +ClientPtr LoginDialog::loadClient(const QString &name, Buffer *cfg) +{ + if (name.isEmpty()) + return ClientPtr(); + QString clientName = name; + QString pluginName = getToken(clientName, '/'); + if (pluginName.isEmpty() || clientName.length() == 0) + return ClientPtr(); + if(!getPluginManager()->isPluginProtocol(pluginName)) + { + log(L_DEBUG, "Plugin %s is not a protocol plugin", qPrintable(pluginName)); + return ClientPtr(); + } + PluginPtr plugin = getPluginManager()->plugin(pluginName); + if(plugin.isNull()) + { + log(L_WARN, "Plugin %s not found", qPrintable(pluginName)); + return ClientPtr(); + } + m_protocolPlugins.append(plugin); + ProfileManager::instance()->currentProfile()->enablePlugin(pluginName); + ProtocolPtr protocol; + ProtocolIterator it; + while ((protocol = ++it) != NULL) + if (protocol->description()->text == clientName) + return protocol->createClient(cfg); + log(L_DEBUG, "Protocol %s not found", qPrintable(clientName)); + return ClientPtr(); +} + diff --git a/plugins/_core/logindlg.h b/plugins/_core/logindlg.h new file mode 100644 index 0000000..364ba1f --- /dev/null +++ b/plugins/_core/logindlg.h @@ -0,0 +1,101 @@ +/*************************************************************************** + logindlg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _LOGINDLG_H +#define _LOGINDLG_H + +#include "buffer.h" +#include "clientlist.h" +#include "contacts/client.h" +#include "event.h" +#include "plugins.h" +#include "ui_logindlgbase.h" +#include +#include +#include + +class QLabel; +class QLineEdit; +class LinkLabel; + +class LoginDialog : public QDialog, public Ui::LoginDialogBase, public SIM::EventReceiver +{ + Q_OBJECT +public: + LoginDialog(bool bInit, SIM::ClientPtr client, const QString &msg, const QString &loginProfile); + ~LoginDialog(); + bool isChanged() { return m_bProfileChanged; } + SIM::ClientPtr client() { return m_client; } + QString profile() { return m_profile; } + bool isNewProfile() { return m_newProfile; } + QString newProfileName() { return m_newProfileName; } + +signals: + void changeProfile(const QString& profilename); + void loadClients(); + +protected slots: + void saveToggled(bool); + void profileChanged(int); + void pswdChanged(const QString&); + void profileDelete(); + void profileRename(); + void loginComplete(); + void adjust(); + void newNameChanged( const QString &text ); + +protected: + virtual bool processEvent(SIM::Event*); + virtual void closeEvent(QCloseEvent *e); + virtual void accept(); + virtual void reject(); + void makeInputs(unsigned &row, SIM::ClientPtr client); + void clearInputs(); + void fill(); + void startLogin(); + void stopLogin(); + void loadClients(const QString& profilename, SIM::ClientList&); + SIM::ClientPtr loadClient(const QString &name, Buffer *cfg); + +private: + QString m_profile; + QString m_loginProfile; + bool m_newProfile; + bool m_bLogin; + bool m_bInit; + bool m_bProfileChanged; + QList picts; + QList texts; + QList passwords; + QList links; + QList lines; + SIM::ClientPtr m_client; + QString m_newProfileName; + QList m_protocolPlugins; + QLabel *m_pict; + QVBoxLayout *m_vboxlayout; + QHBoxLayout *m_hboxlayout; + QLabel *m_txt; + QLineEdit *m_edt; + QFrame *m_line; + LinkLabel *m_lnkHelp; +}; + +#endif + +// vim: set expandtab: + diff --git a/plugins/_core/logindlgbase.ui b/plugins/_core/logindlgbase.ui new file mode 100644 index 0000000..ab43987 --- /dev/null +++ b/plugins/_core/logindlgbase.ui @@ -0,0 +1,224 @@ + + + LoginDialogBase + + + + 0 + 0 + 468 + 256 + + + + Login + + + true + + + + + + + 75 + true + + + + + + + Qt::AlignCenter + + + false + + + + + + + + + Profile: + + + + + + + + 0 + 0 + + + + + 200 + 0 + + + + + + + + &Rename + + + + + + + &Delete + + + + + + + + + New profile name: + + + + + + + + + + + 0 + 0 + + + + Passwords: + + + + + + + + + &Save passwords + + + + + + + + + + &Do not show this window on startup + + + + + + + Qt::Vertical + + + + 20 + 12 + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + &OK + + + true + + + true + + + + + + + &Cancel + + + true + + + + + + + + + chkNoShow + buttonOk + buttonCancel + cmbProfile + btnRename + btnDelete + chkSave + + + + + buttonOk + clicked() + LoginDialogBase + accept() + + + 20 + 20 + + + 20 + 20 + + + + + buttonCancel + clicked() + LoginDialogBase + reject() + + + 20 + 20 + + + 20 + 20 + + + + + diff --git a/plugins/_core/maininfo.cpp b/plugins/_core/maininfo.cpp new file mode 100644 index 0000000..50cbbd6 --- /dev/null +++ b/plugins/_core/maininfo.cpp @@ -0,0 +1,620 @@ +/*************************************************************************** + maininfo.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "icons.h" +#include "maininfo.h" +#include "editmail.h" +#include "editphone.h" +#include "simgui/listview.h" +#include "core.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "contacts/contact.h" + + +using namespace std; +using namespace SIM; + +const unsigned PHONE_TYPE = 0; +const unsigned PHONE_NUMBER = 1; +const unsigned PHONE_PUBLISH = 2; +const unsigned PHONE_ICON = 0x10; +const unsigned PHONE_PROTO = 0x11; +const unsigned PHONE_TYPE_ASIS = 0x12; +const unsigned PHONE_ACTIVE = 0x13; + +const unsigned MAIL_ADDRESS = 0; +const unsigned MAIL_PUBLISH = 1; +const unsigned MAIL_PROTO = 0x10; + +const char *phoneTypeNames[] = + { + I18N_NOOP("Home Phone"), + I18N_NOOP("Home Fax"), + I18N_NOOP("Work Phone"), + I18N_NOOP("Work Fax"), + I18N_NOOP("Private Cellular"), + I18N_NOOP("Wireless Pager"), + NULL + }; + +ext_info phoneIcons[] = + { + { "phone", PHONE }, + { "fax", FAX }, + { "cell", CELLULAR }, + { "pager", PAGER }, + { NULL, 0 } + }; + +MainInfo::MainInfo(QWidget *parent, Contact *contact) : QWidget(parent) +{ + setupUi(this); + m_contact = contact; + m_bInit = false; + cmbDisplay->setEditable(true); + lstMails->addColumn(i18n("EMail")); + lstPhones->addColumn(i18n("Type")); + lstPhones->addColumn(i18n("Phone")); + lstMails->setMenu(MenuMailList); + lstPhones->setMenu(MenuPhoneList); + if (m_contact == NULL){ + lstMails->addColumn(i18n("Publish")); + lstPhones->addColumn(i18n("Publish")); + lblCurrent->setText(i18n("I'm currently available at:")); + cmbStatus->addItem(i18n("Don't show")); + cmbStatus->addItem(Icon("phone"), i18n("Available")); + cmbStatus->addItem(Icon("nophone"), i18n("Busy")); + cmbStatus->setCurrentIndex(getContacts()->owner()->getPhoneStatus()); + }else{ + lblCurrent->setText(i18n("User is crrently available at:")); + disableWidget(cmbCurrent); + lblStatus->hide(); + cmbStatus->hide(); + } + Command cmd; + cmd->id = CmdPhones; + if (!EventCheckCommandState(cmd).process()){ + lblCurrent->hide(); + cmbCurrent->hide(); + lblStatus->hide(); + cmbStatus->hide(); + } + lstMails->setExpandingColumn(0); + lstPhones->setExpandingColumn(PHONE_NUMBER); + if (m_contact == NULL) + tabMain->removeTab(tabMain->indexOf(tabNotes)); + fill(); + connect(lstMails, SIGNAL(itemSelectionChanged()), this, SLOT(mailSelectionChanged())); + connect(lstPhones, SIGNAL(itemSelectionChanged()), this, SLOT(phoneSelectionChanged())); + connect(lstMails, SIGNAL(deleteItem(ListViewItem*)), this, SLOT(deleteMail(ListViewItem*))); + connect(lstPhones, SIGNAL(deleteItem(ListViewItem*)), this, SLOT(deletePhone(ListViewItem*))); + connect(btnMailAdd, SIGNAL(clicked()), this, SLOT(addMail())); + connect(btnMailEdit, SIGNAL(clicked()), this, SLOT(editMail())); + connect(btnMailDelete, SIGNAL(clicked()), this, SLOT(deleteMail())); + connect(btnPhoneAdd, SIGNAL(clicked()), this, SLOT(addPhone())); + connect(btnPhoneEdit, SIGNAL(clicked()), this, SLOT(editPhone())); + connect(btnPhoneDelete, SIGNAL(clicked()), this, SLOT(deletePhone())); +} + +bool MainInfo::processEvent(Event *e) +{ + switch (e->type()) { + case eEventContact: { + EventContact *ec = static_cast(e); + if(ec->action() == EventContact::eChanged) { + Contact *contact = ec->contact(); + if (contact == m_contact) + fill(); + } + break; + } + case eEventCheckCommandState: { + EventCheckCommandState *ecs = static_cast(e); + CommandDef *cmd = ecs->cmd(); + if (cmd->menu_id == MenuMailList){ + if ((cmd->id != CmdEditList) && (cmd->id != CmdRemoveList)) + return false; + ListViewItem *item = (ListViewItem*)(cmd->param); + if (item->listView() != lstMails) + return false; + cmd->flags &= ~(COMMAND_CHECKED | COMMAND_DISABLED); + bool bEnable = ((item != NULL) && (item->text(MAIL_PROTO).isEmpty() || (item->text(MAIL_PROTO) == "-"))); + if (!bEnable) + cmd->flags |= COMMAND_DISABLED; + return true; + } + if (cmd->menu_id == MenuPhoneList){ + if ((cmd->id != CmdEditList) && (cmd->id != CmdRemoveList)) + return false; + ListViewItem *item = (ListViewItem*)(cmd->param); + if (item->listView() != lstPhones) + return false; + cmd->flags &= ~(COMMAND_CHECKED | COMMAND_DISABLED); + bool bEnable = ((item != NULL) && (item->text(PHONE_PROTO).isEmpty() || (item->text(PHONE_PROTO) == "-"))); + if (!bEnable) + cmd->flags |= COMMAND_DISABLED; + return true; + } + break; + } + case eEventCommandExec: { + EventCommandExec *ece = static_cast(e); + CommandDef *cmd = ece->cmd(); + if (cmd->menu_id == MenuMailList){ + ListViewItem *item = (ListViewItem*)(cmd->param); + if (item->listView() != lstMails) + return false; + bool bEnable = ((item != NULL) && (item->text(MAIL_PROTO).isEmpty() || (item->text(MAIL_PROTO) == "-"))); + if (!bEnable) + return false; + if (cmd->id == CmdEditList){ + editMail(item); + return true; + } + if (cmd->id == CmdRemoveList){ + deleteMail(item); + return true; + } + } + if (cmd->menu_id == MenuPhoneList){ + ListViewItem *item = (ListViewItem*)(cmd->param); + if (item->listView() != lstPhones) + return false; + bool bEnable = ((item != NULL) && (item->text(PHONE_PROTO).isEmpty() || (item->text(PHONE_PROTO) == "-"))); + if (!bEnable) + return false; + if (cmd->id == CmdEditList){ + editPhone(item); + return true; + } + if (cmd->id == CmdRemoveList){ + deletePhone(item); + return true; + } + } + break; + } + default: + break; + } + return false; +} + +void MainInfo::fill() +{ + Contact *contact = m_contact; + if (contact == NULL) + contact = getContacts()->owner(); + + QString firstName = contact->getFirstName(); + firstName = getToken(firstName, '/'); + edtFirstName->setText(firstName); + QString lastName = contact->getLastName(); + lastName = getToken(lastName, '/'); + edtLastName->setText(lastName); + + cmbDisplay->clear(); + QString name = contact->getName(); + if (name.length()) + cmbDisplay->insertItem(INT_MAX,name); + if (firstName.length() && lastName.length()){ + cmbDisplay->insertItem(INT_MAX,firstName + ' ' + lastName); + cmbDisplay->insertItem(INT_MAX,lastName + ' ' + firstName); + } + if (firstName.length()) + cmbDisplay->insertItem(INT_MAX,firstName); + if (lastName.length()) + cmbDisplay->insertItem(INT_MAX,lastName); + cmbDisplay->lineEdit()->setText(contact->getName()); + + edtNotes->setPlainText(contact->getNotes()); + QString mails = contact->getEMails(); + lstMails->clear(); + while (mails.length()){ + QString mailItem = getToken(mails, ';', false); + QString mail = getToken(mailItem, '/'); + ListViewItem *item = new ListViewItem(lstMails); + item->setText(MAIL_ADDRESS, mail); + item->setText(MAIL_PROTO, mailItem); + item->setPixmap(MAIL_ADDRESS, Pict("mail_generic")); + if ((m_contact == NULL) && mailItem.isEmpty()) + item->setText(MAIL_PUBLISH, i18n("Yes")); + } + mailSelectionChanged(); + QString phones = contact->getPhones(); + lstPhones->clear(); + unsigned n = 1; + cmbCurrent->clear(); + cmbCurrent->insertItem(INT_MAX,""); + while (phones.length()){ + unsigned icon = 0; + QString phone = getToken(phones, ';', false); + QString phoneItem = getToken(phone, '/', false); + QString number = getToken(phoneItem, ','); + QString type = getToken(phoneItem, ','); + QString proto = phone; + + if (!phoneItem.isEmpty()) + icon = getToken(phoneItem, ',').toULong(); + ListViewItem *item = new ListViewItem(lstPhones); + fillPhoneItem(item, number, type, icon, proto); + cmbCurrent->insertItem(INT_MAX,number); + if (!phoneItem.isEmpty()){ + item->setText(PHONE_ACTIVE, "1"); + cmbCurrent->setCurrentIndex(n); + } + n++; + } + connect(lstPhones, SIGNAL(selectionChanged()), this, SLOT(phoneSelectionChanged())); + phoneSelectionChanged(); + if (!m_bInit) + fillEncoding(); +} + +void MainInfo::apply() +{ + getEncoding(false); /* EventContactChanged kills all our settings ... + and we send event also :) */ + Contact *contact = m_contact; + if (contact == NULL){ + contact = getContacts()->owner(); + contact->setPhoneStatus(cmbStatus->currentIndex()); + } + contact->setNotes(edtNotes->toPlainText()); + ListViewItem *item; + QString mails; + for (int i = 0; i topLevelItemCount(); i++) + { + item = static_cast(lstMails->topLevelItem(i)); + if (mails.length()) + mails += ';'; + mails += quoteChars(item->text(MAIL_ADDRESS), ";/"); + mails += '/'; + mails += item->text(MAIL_PROTO); + } + contact->setEMails(mails); + QString phones; + for (int i = 0; i < lstPhones->topLevelItemCount(); i++) + { + item = static_cast(lstPhones->topLevelItem(i)); + if (phones.length()) + phones += ';'; + phones += quoteChars(item->text(PHONE_NUMBER), ";/,"); + phones += ','; + phones += quoteChars(item->text(PHONE_TYPE_ASIS), ";/,"); + phones += ','; + phones += item->text(PHONE_ICON); + if (m_contact){ + if (!item->text(PHONE_ACTIVE).isEmpty()) + phones += ",1"; + }else{ + if (item->text(PHONE_NUMBER) == cmbCurrent->currentText()) + phones += ",1"; + } + phones += '/'; + phones += item->text(PHONE_PROTO); + } + contact->setPhones(phones); + /* Christian: The checks if the name has changed took longer + than setting the new value directly */ + contact->setFirstName(edtFirstName->text(), QString::null); + contact->setLastName(edtLastName->text(), QString::null); + + QString name = cmbDisplay->lineEdit()->text(); + if (name.isEmpty()){ + name = edtFirstName->text(); + if (!edtLastName->text().isEmpty()){ + if (!name.isEmpty()){ + name += ' '; + name += edtLastName->text(); + } + } + } + contact->setName(name); + + EventContact(contact, EventContact::eChanged).process(); +} + +void MainInfo::mailSelectionChanged() +{ + ListViewItem *item = lstMails->currentItem(); + bool bEnable = ((item != NULL) && (item->text(MAIL_PROTO).isEmpty() || (item->text(MAIL_PROTO) == "-"))); + btnMailEdit->setEnabled(bEnable); + btnMailDelete->setEnabled(bEnable); +} + +void MainInfo::phoneSelectionChanged() +{ + ListViewItem *item = lstPhones->currentItem(); + bool bEnable = ((item != NULL) && (item->text(PHONE_PROTO).isEmpty() || (item->text(PHONE_PROTO) == "-"))); + btnPhoneEdit->setEnabled(bEnable); + btnPhoneDelete->setEnabled(bEnable); +} + +void MainInfo::addMail() +{ + EditMail dlg(this, "", false, m_contact == NULL); + if (dlg.exec() && !dlg.res.isEmpty()){ + ListViewItem *item = new ListViewItem(lstMails); + QString proto = "-"; + if ((m_contact == NULL) && dlg.publish){ + item->setText(MAIL_PUBLISH, i18n("Yes")); + proto = QString::null; + } + item->setText(MAIL_ADDRESS, dlg.res); + item->setText(MAIL_PROTO, proto); + item->setPixmap(MAIL_ADDRESS, Pict("mail_generic")); + lstMails->setCurrentItem(item); + } +} + +void MainInfo::editMail() +{ + ListViewItem *item = lstMails->currentItem(); + editMail(item); +} + +void MainInfo::editMail(ListViewItem *item) +{ + if ((item == NULL) || (!item->text(MAIL_PROTO).isEmpty() && (item->text(MAIL_PROTO) != "-"))) + return; + EditMail dlg(this, item->text(MAIL_ADDRESS), item->text(MAIL_PROTO).isEmpty(), m_contact == NULL); + if (dlg.exec() && !dlg.res.isEmpty()){ + QString proto = "-"; + if ((m_contact == NULL) && dlg.publish){ + item->setText(MAIL_PUBLISH, i18n("Yes")); + proto = QString::null; + } + item->setText(MAIL_ADDRESS, dlg.res); + item->setText(MAIL_PROTO, proto); + item->setPixmap(MAIL_ADDRESS, Pict("mail_generic")); + lstMails->setCurrentItem(item); + } +} + +void MainInfo::deleteMail() +{ + deleteMail(lstMails->currentItem()); +} + +void MainInfo::deleteMail(ListViewItem *item) +{ + if ((item == NULL) || (!item->text(MAIL_PROTO).isEmpty() && (item->text(MAIL_PROTO) != "-"))) + return; + delete item; +} + +void MainInfo::addPhone() +{ + EditPhone dlg(this, "", "", PHONE, false, m_contact == NULL); + if (dlg.exec() && !dlg.number.isEmpty() && !dlg.type.isEmpty()){ + QString proto = "-"; + if ((m_contact == NULL) && dlg.publish) + proto = QString::null; + fillPhoneItem(new ListViewItem(lstPhones), dlg.number, dlg.type, dlg.icon, proto); + fillCurrentCombo(); + } +} + +void MainInfo::editPhone() +{ + ListViewItem *item = lstPhones->currentItem(); + editPhone(item); +} + +void MainInfo::editPhone(ListViewItem *item) +{ + if (item == NULL) + return; + QString proto = item->text(PHONE_PROTO); + if (!proto.isEmpty() && (proto != "-")) + return; + EditPhone dlg(this, item->text(PHONE_NUMBER), item->text(PHONE_TYPE_ASIS), item->text(PHONE_ICON).toULong(), item->text(PHONE_PROTO).isEmpty(), m_contact == NULL); + if (dlg.exec() && !dlg.number.isEmpty() && !dlg.type.isEmpty()){ + QString proto = "-"; + if ((m_contact == NULL) && dlg.publish) + proto = QString::null; + fillPhoneItem(item, dlg.number, dlg.type, dlg.icon, proto); + fillCurrentCombo(); + } +} + +void MainInfo::deletePhone() +{ + deletePhone(lstPhones->currentItem()); +} + +void MainInfo::deletePhone(ListViewItem *item) +{ + if (item == NULL) + return; + QString proto = item->text(PHONE_PROTO); + if (!proto.isEmpty() && (proto != "-")) + return; + delete item; + fillCurrentCombo(); +} + +void MainInfo::fillPhoneItem(ListViewItem *item, const QString &number, const QString &type, unsigned icon, const QString &proto) +{ + item->setText(PHONE_PROTO, proto); + item->setText(PHONE_NUMBER, number); + item->setText(PHONE_TYPE_ASIS, type); + if (!type.isEmpty()){ + const QByteArray t = type.toLatin1(); + const char **p; + for (p = phoneTypeNames; *p; p++){ + if (!strcmp(*p, t.constData())) + break; + } + if (*p){ + item->setText(PHONE_TYPE, i18n(type)); + }else{ + item->setText(PHONE_TYPE, type); + } + } + item->setText(PHONE_ICON, QString::number(icon)); + for (const ext_info *info = phoneIcons; info->szName; info++){ + if (info->nCode == icon){ + item->setPixmap(PHONE_TYPE, Pict(info->szName)); + break; + } + } + if (m_contact == NULL) + item->setText(PHONE_PUBLISH, proto.isEmpty() ? i18n("Yes") : QString("")); + lstPhones->adjustColumn(); +} + +void MainInfo::fillCurrentCombo() +{ + if (m_contact) + return; + QString current = cmbCurrent->currentText(); + cmbCurrent->clear(); + cmbCurrent->insertItem(INT_MAX,""); + int n = 1; + int cur = 0; + for (n = 1; n < lstPhones->topLevelItemCount(); n++){ + ListViewItem* item = static_cast(lstPhones->topLevelItem(n)); + QString phone = item->text(PHONE_NUMBER); + if (phone == current) + cur = n; + cmbCurrent->insertItem(INT_MAX,phone); + } + cmbCurrent->setCurrentIndex(cur); +} + +void MainInfo::fillEncoding() +{ + m_bInit = true; + int current = 0; + int n_item = 1; + cmbEncoding->clear(); + cmbEncoding->insertItem(INT_MAX,"Default"); + const ENCODING *e; + QStringList main; + QStringList::Iterator it; + for (e = getContacts()->getEncodings(); e->language; e++){ + if (!e->bMain) + continue; + main.append(i18n(e->language) + " (" + e->codec + ')'); + } + main.sort(); + Contact *contact = m_contact; + if (contact == NULL) + contact = getContacts()->owner(); + for (it = main.begin(); it != main.end(); ++it, n_item++){ + QString str = *it; + int n = str.indexOf('('); + str = str.mid(n + 1); + n = str.indexOf(')'); + str = str.left(n); + if (str == contact->getEncoding()) + current = n_item; + cmbEncoding->insertItem(INT_MAX,*it); + } + QStringList noMain; + for (e = getContacts()->getEncodings(); e->language; e++){ + if (e->bMain) + continue; + noMain.append(i18n(e->language) + " (" + e->codec + ')'); + } + noMain.sort(); + for (it = noMain.begin(); it != noMain.end(); ++it, n_item++){ + QString str = *it; + int n = str.indexOf('('); + str = str.mid(n + 1); + n = str.indexOf(')'); + str = str.left(n); + if (str == contact->getEncoding()) + current = n_item; + cmbEncoding->insertItem(INT_MAX,*it); + } + cmbEncoding->setCurrentIndex(current); +} + +void MainInfo::getEncoding(bool SendContactChangedEvent) +{ + QString encoding; + int n = cmbEncoding->currentIndex(); + Contact *contact = m_contact; + if (contact == NULL) + contact = getContacts()->owner(); + if (n){ + n--; + QStringList l; + const ENCODING *e; + QStringList main; + for (e = getContacts()->getEncodings(); e->language; e++){ + if (!e->bMain) + continue; + main.append(i18n(e->language) + " (" + e->codec + ')'); + } + main.sort(); + QStringList::Iterator it; + for (it = main.begin(); it != main.end(); ++it){ + l.append(*it); + } + QStringList noMain; + for (e = getContacts()->getEncodings(); e->language; e++){ + if (e->bMain) + continue; + noMain.append(i18n(e->language) + " (" + e->codec + ')'); + } + noMain.sort(); + for (it = noMain.begin(); it != noMain.end(); ++it){ + l.append(*it); + } + for (it = l.begin(); it != l.end(); ++it){ + if (n-- == 0){ + QString str = *it; + int n = str.indexOf('('); + str = str.mid(n + 1); + n = str.indexOf(')'); + str = str.left(n); + encoding = str; + break; + } + } + } + QString oldEncoding = contact->getEncoding(); + if (oldEncoding == encoding) + return; + contact->setEncoding(encoding); + if (SendContactChangedEvent){ + EventContact(contact, EventContact::eChanged).process(); + } + EventHistoryConfig(contact->id()).process(); +} + +/* +#ifndef NO_MOC_INCLUDES +#include "maininfo.moc" +#endif +*/ + +// vim: set expandtab: + diff --git a/plugins/_core/maininfo.h b/plugins/_core/maininfo.h new file mode 100644 index 0000000..962fdc8 --- /dev/null +++ b/plugins/_core/maininfo.h @@ -0,0 +1,65 @@ +/*************************************************************************** + maininfo.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _MAININFO_H +#define _MAININFO_H + +#include "ui_maininfobase.h" + +class ListViewItem; + +// Lets do this later whole in one, because at the moment it only breaks linking of all other plugins... +#ifndef CORE_EXPORT +# ifdef CORE_EXPORTS +# define CORE_EXPORT Q_DECL_EXPORT +# else // CORE_EXPORTS +# define CORE_EXPORT Q_DECL_IMPORT +# endif // CORE_EXPORTS +#endif // CORE_EXPORT + +class CORE_EXPORT MainInfo : public QWidget, public Ui::MainInfo, public SIM::EventReceiver +{ + Q_OBJECT +public: + MainInfo(QWidget *parent, SIM::Contact *contact); +protected slots: + void apply(); + void mailSelectionChanged(); + void phoneSelectionChanged(); + void deleteMail(ListViewItem *item); + void deletePhone(ListViewItem *item); + void editMail(ListViewItem *item); + void editPhone(ListViewItem *item); + void addMail(); + void editMail(); + void deleteMail(); + void addPhone(); + void editPhone(); + void deletePhone(); +protected: + void fill(); + virtual bool processEvent(SIM::Event*); + void fillPhoneItem(ListViewItem *item, const QString &number, const QString &type, unsigned icon, const QString &proto); + void fillCurrentCombo(); + void fillEncoding(); + void getEncoding(bool SendContactChangedEvent = true); + bool m_bInit; + SIM::Contact *m_contact; +}; + +#endif + diff --git a/plugins/_core/maininfobase.ui b/plugins/_core/maininfobase.ui new file mode 100644 index 0000000..91bb683 --- /dev/null +++ b/plugins/_core/maininfobase.ui @@ -0,0 +1,382 @@ + + + MainInfo + + + + 0 + 0 + 469 + 279 + + + + Form1 + + + + 6 + + + 11 + + + + + 3 + + + + &Info + + + + 11 + + + 6 + + + + + First Name: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + Last Name: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + + + + Display: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + 0 + 0 + + + + + + + + Encoding: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + + &Mails + + + + 6 + + + 11 + + + + + Email addresses: + + + false + + + + + + + + + + 6 + + + 0 + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + &Add + + + + + + + &Edit + + + + + + + &Delete + + + + + + + + + Note: +You can change only those addresses which have entered. +It is impossible to change addresses which were received from the user. + + + false + + + + + + + + &Phones + + + + 6 + + + 11 + + + + + Phones: + + + false + + + + + + + + + + 6 + + + 0 + + + + + + 0 + 0 + + + + + + + false + + + + + + + + 0 + 0 + + + + + + + + + + 6 + + + 0 + + + + + Phone Status: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + &Add + + + + + + + &Edit + + + + + + + &Delete + + + + + + + + + Note: +You can change only those numbers which have entered. +It is impossible to change numbers which were received from the user. + + + false + + + + + + + + &Notes + + + + 6 + + + 11 + + + + + + + + + + + + + ListView + QWidget +
simgui/listview.h
+
+
+ + +
diff --git a/plugins/_core/mainwin.cpp b/plugins/_core/mainwin.cpp new file mode 100644 index 0000000..b13c79f --- /dev/null +++ b/plugins/_core/mainwin.cpp @@ -0,0 +1,266 @@ +/*************************************************************************** + mainwin.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "simapi.h" + +#include "icons.h" +#include "mainwin.h" +#include "core.h" +#include "userview.h" +#include "contacts/contact.h" +#include "simgui/toolbtn.h" + +#include +#include +#include +#include +#include +#include +#include + +using namespace SIM; + +MainWindow *MainWindow::s_mainWindow = NULL; + +MainWindow::MainWindow() + : QMainWindow(NULL, Qt::Window) + , EventReceiver(LowestPriority) +{ + setObjectName("mainwnd"); + setAttribute(Qt::WA_AlwaysShowToolTips); + Q_ASSERT(s_mainWindow == NULL); + s_mainWindow = this; + h_lay = NULL; + m_bNoResize = false; + + m_icon = "SIM"; + setWindowIcon(Icon(m_icon)); + setTitle(); + +// setIconSize(QSize(16,16)); + + m_bar = NULL; + + main = new QWidget(this); + setCentralWidget(main); + + lay = new QVBoxLayout(main); + lay->setMargin(0); + + QStatusBar *status = statusBar(); + status->show(); + status->installEventFilter(this); +} + +MainWindow::MainWindow(Geometry &geometry) + : QMainWindow(NULL, Qt::Window) + , EventReceiver(LowestPriority) +{ + setObjectName("mainwnd"); + setAttribute(Qt::WA_AlwaysShowToolTips); + Q_ASSERT(s_mainWindow == NULL); + s_mainWindow = this; + h_lay = NULL; + m_bNoResize = false; + + m_icon = "SIM"; + setWindowIcon(Icon(m_icon)); + setTitle(); + +// setIconSize(QSize(16,16)); + + m_bar = NULL; + + main = new QWidget(this); + setCentralWidget(main); + + lay = new QVBoxLayout(main); + lay->setMargin(0); + + QStatusBar *status = statusBar(); + status->show(); + status->installEventFilter(this); + + if ((geometry[WIDTH].toLong() == -1) && (geometry[HEIGHT].toLong() == -1)) + { + geometry[HEIGHT].asLong() = QApplication::desktop()->height() * 2 / 3; + geometry[WIDTH].asLong() = geometry[HEIGHT].toLong() / 3; + } + if ((geometry[LEFT].toLong() == -1) && (geometry[TOP].toLong() == -1)){ + geometry[LEFT].asLong() = QApplication::desktop()->width() - 25 - geometry[WIDTH].toLong(); + geometry[TOP].asLong() = 5; + } + ::restoreGeometry(this, geometry, true, true); +} + +MainWindow::~MainWindow() +{ + s_mainWindow = NULL; +} + +MainWindow *MainWindow::mainWindow() +{ + return s_mainWindow; +} + +void MainWindow::resizeEvent(QResizeEvent *e) +{ + if (m_bNoResize) + return; + QMainWindow::resizeEvent(e); +} + +bool MainWindow::eventFilter(QObject *o, QEvent *e) +{ + if (e->type() == QEvent::ChildRemoved){ + QChildEvent *ce = static_cast(e); + std::list::iterator it; + for (it = statusWidgets.begin(); it != statusWidgets.end(); ++it){ + if (*it == ce->child()){ + statusWidgets.erase(it); + break; + } + } + if(statusWidgets.size() == 0) + { + statusBar()->hide(); + } + } + return QMainWindow::eventFilter(o, e); +} + +bool MainWindow::processEvent(Event *e) +{ + switch(e->type()){ + case eEventSetMainIcon: + { + EventSetMainIcon *smi = static_cast(e); + m_icon = smi->icon(); + setWindowIcon(Icon(m_icon)); + break; + } + case eEventInit: + { + setTitle(); + EventToolbar e(ToolBarMain, this); + e.process(); + m_bar = e.toolBar(); + m_bar->setObjectName("MainToolbar"); + this->addToolBar(m_bar); +// m_bar->setMaximumHeight(30); +// m_bar->setMinimumHeight(30); // FIXME + //restoreToolbar(m_bar, CorePlugin::instance()->data.toolBarState); + raiseWindow(this); + break; + } + case eEventCommandExec: + { + EventCommandExec *ece = static_cast(e); + CommandDef *cmd = ece->cmd(); + if (cmd->id == CmdQuit) + quit(); + break; + } + case eEventAddWidget: + { + EventAddWidget *aw = static_cast(e); + switch(aw->place()) { + case EventAddWidget::eMainWindow: + addWidget(aw->widget(), aw->down()); + break; + case EventAddWidget::eStatusWindow: + addStatus(aw->widget(), aw->down()); + break; + default: + return false; + } + return true; + } + case eEventIconChanged: + setWindowIcon(Icon(m_icon)); + break; + case eEventContact: + { + EventContact *ec = static_cast(e); + Contact *contact = ec->contact(); + if (contact == getContacts()->owner()) + setTitle(); + break; + } + default: + break; + } + return false; +} + +void MainWindow::quit() +{ + close(); +} + +void MainWindow::closeEvent(QCloseEvent *e) +{ + CorePlugin::instance()->prepareConfig(); + save_state(); + QMainWindow::closeEvent(e); + qApp->quit(); +} + +void MainWindow::addWidget(QWidget *w, bool bDown) +{ + w->setParent(main); + w->move(QPoint()); + if (bDown){ + lay->addWidget(w); + }else{ + lay->insertWidget(0, w); + } + if (isVisible()) + w->show(); +} + +void MainWindow::addStatus(QWidget *w, bool) +{ + QStatusBar *status = statusBar(); + w->setParent(status); + w->move(QPoint()); + statusWidgets.push_back(w); + status->addWidget(w, true); + w->show(); + status->setSizeGripEnabled(true); + status->show(); +} + +void MainWindow::setTitle() +{ + QString title; + Contact *owner = getContacts()->owner(); + if (owner) + title = owner->getName(); + if (title.isEmpty()) + title = "SIM"; + setWindowTitle(title); +} + +void MainWindow::focusInEvent(QFocusEvent *e) +{ + QMainWindow::focusInEvent(e); + if (CorePlugin::instance()->m_view) + CorePlugin::instance()->m_view->setFocus(); +} + + diff --git a/plugins/_core/mainwin.h b/plugins/_core/mainwin.h new file mode 100644 index 0000000..f9fb98e --- /dev/null +++ b/plugins/_core/mainwin.h @@ -0,0 +1,71 @@ +/*************************************************************************** + mainwin.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _MAINWIN_H +#define _MAINWIN_H + +#include +#include "simapi.h" +#include "event.h" + +#include "cfg.h" + +#include + +using namespace std; + +class QToolBat; +class CorePlugin; +class QCloseEvent; +class QEvent; +class QFocusEvent; +class QHBoxLayout; +class QResizeEvent; +class QSizeGrip; +class QVBoxLayout; + +class MainWindow : public QMainWindow, public SIM::EventReceiver +{ + Q_OBJECT +public: + MainWindow(); + MainWindow(SIM::Geometry&); + ~MainWindow(); + static MainWindow *mainWindow(); + bool m_bNoResize; + void closeEvent(QCloseEvent *e); +protected: + QWidget *main; + CToolBar *m_bar; + QVBoxLayout *lay; + QHBoxLayout *h_lay; + void focusInEvent(QFocusEvent*); + virtual bool processEvent(SIM::Event*); + void setTitle(); + void resizeEvent(QResizeEvent *e); + bool eventFilter(QObject *o, QEvent *e); + void quit(); + void addWidget(QWidget*, bool bDown); + void addStatus(QWidget *w, bool); + list statusWidgets; + QString m_icon; + friend class CorePlugin; + static MainWindow *s_mainWindow; +}; + +#endif + diff --git a/plugins/_core/manager.cpp b/plugins/_core/manager.cpp new file mode 100644 index 0000000..9ca80ad --- /dev/null +++ b/plugins/_core/manager.cpp @@ -0,0 +1,163 @@ +/*************************************************************************** + manager.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "icons.h" +#include "manager.h" +#include "newprotocol.h" +#include "connectionsettings.h" +#include "core.h" +#include "contacts/client.h" + +#include +#include +#include +#include +#include + +using namespace SIM; + +ConnectionManager::ConnectionManager(bool bModal) + : QDialog(NULL) +{ + setupUi(this); + setObjectName("manager"); + SET_WNDPROC("manager") + setWindowIcon(Icon("configure")); + setButtonsPict(this); + lstConnection->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + fill(); + connect(btnAdd, SIGNAL(clicked()), this, SLOT(addClient())); + connect(btnRemove, SIGNAL(clicked()), this, SLOT(removeClient())); + connect(btnUp, SIGNAL(clicked()), this, SLOT(upClient())); + connect(btnDown, SIGNAL(clicked()), this, SLOT(downClient())); + connect(btnUpdate, SIGNAL(clicked()), this, SLOT(updateClient())); + connect(lstConnection, SIGNAL(selectionChanged()), this, SLOT(selectionChanged())); + m_bModal = bModal; +} + +void ConnectionManager::fill(Client *current) +{ + lstConnection->clear(); + QListWidgetItem *curItem = NULL; + for (unsigned i = 0; i < getContacts()->nClients(); i++){ + Client *client = getContacts()->getClient(i); + Protocol *protocol = client->protocol(); + const CommandDef *descr = protocol->description(); + QString text = CorePlugin::instance()->clientName(client); + QListWidgetItem *item = new QListWidgetItem(text, lstConnection); + if (descr) + item->setIcon(Pict(descr->icon)); + if (current == client) + curItem = item; + } + if (curItem) + lstConnection->setCurrentItem(curItem); + selectionChanged(); +} + +void ConnectionManager::selectionChanged() +{ + QListWidgetItem *item = lstConnection->currentItem(); + if (item == NULL){ + btnUp->setEnabled(false); + btnDown->setEnabled(false); + btnRemove->setEnabled(false); + btnUpdate->setEnabled(false); + return; + } + btnUpdate->setEnabled(true); + btnRemove->setEnabled(true); + int index = lstConnection->row(item); + btnUp->setEnabled(index > 0); + btnDown->setEnabled(index < lstConnection->count()); +} + +void ConnectionManager::closeEvent(QCloseEvent *e) +{ + QDialog::closeEvent(e); + emit finished(); +} + +void ConnectionManager::addClient() +{ + NewProtocol pDlg(this); + if (pDlg.exec()) + fill(); +} + +Client *ConnectionManager::currentClient() +{ + QListWidgetItem *item = lstConnection->currentItem(); + if (item == NULL) + return NULL; + int index = lstConnection->row(item); + if (index == -1) + return NULL; + return getContacts()->getClient(index); +} + +void ConnectionManager::removeClient() +{ + Client *client = currentClient(); + if (client == NULL) + return; + delete client; + fill(); +} + +void ConnectionManager::upClient() +{ + Client *client = currentClient(); + if (client == NULL) + return; + getContacts()->moveClient(client, true); + fill(client); +} + +void ConnectionManager::downClient() +{ + Client *client = currentClient(); + if (client == NULL) + return; + getContacts()->moveClient(client, false); + fill(client); +} + +void ConnectionManager::updateClient() +{ + Client *client = currentClient(); + if (client == NULL) + return; + unsigned n; + for (n = 0; n < getContacts()->nClients(); n++){ + if (getContacts()->getClient(n) == client) + break; + } + if (n >= getContacts()->nClients()) + return; + Command cmd; + cmd->id = CmdSetup; + cmd->menu_id = CmdClient + n; + EventCommandExec(cmd).process(); +} + +/* +#ifndef NO_MOC_INCLUDES +#include "manager.moc" +#endif +*/ + diff --git a/plugins/_core/manager.h b/plugins/_core/manager.h new file mode 100644 index 0000000..abaccbd --- /dev/null +++ b/plugins/_core/manager.h @@ -0,0 +1,51 @@ +/*************************************************************************** + manager.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _MANAGER_H +#define _MANAGER_H + +#include "ui_managerbase.h" +#include "event.h" +#include +#include +#include + +class CorePlugin; + +class ConnectionManager : public QDialog, public Ui::Connection +{ + Q_OBJECT +public: + ConnectionManager(bool bModal); +signals: + void finished(); +protected slots: + void addClient(); + void removeClient(); + void upClient(); + void downClient(); + void updateClient(); + void selectionChanged(); +protected: + virtual void closeEvent(QCloseEvent *e); + SIM::Client *currentClient(); + void fill(SIM::Client *current = NULL); + bool m_bModal; +}; + +#endif + diff --git a/plugins/_core/managerbase.ui b/plugins/_core/managerbase.ui new file mode 100644 index 0000000..4780afe --- /dev/null +++ b/plugins/_core/managerbase.ui @@ -0,0 +1,150 @@ + + + Connection + + + + 0 + 0 + 376 + 247 + + + + Connection manager + + + false + + + + 11 + + + + + + + + 0 + 0 + + + + QListView::Adjust + + + + + + + + + &Down + + + + + + + &Up + + + true + + + + + + + &Configure + + + + + + + &New connection + + + + + + + &Remove + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + &Close + + + true + + + + + + + + qPixmapFromMimeSource + + buttonCancel + + + + + buttonCancel + clicked() + Connection + reject() + + + 20 + 20 + + + 20 + 20 + + + + + diff --git a/plugins/_core/msgauth.cpp b/plugins/_core/msgauth.cpp new file mode 100644 index 0000000..784684b --- /dev/null +++ b/plugins/_core/msgauth.cpp @@ -0,0 +1,104 @@ +/*************************************************************************** + msggen.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "msgauth.h" +#include "msgedit.h" +#include "simgui/textshow.h" +#include "userwnd.h" +#include "core.h" + +#include "simgui/toolbtn.h" + +#include +#include + +using namespace SIM; + +MsgAuth::MsgAuth(MsgEdit *parent, Message *msg) + : QObject(parent) +{ + m_client = msg->client(); + m_type = msg->type(); + m_edit = parent; + if (m_edit->m_edit->isReadOnly()){ + m_edit->m_edit->setText(QString::null); + m_edit->m_edit->setReadOnly(false); + } + QString text = msg->getPlainText(); + if (!text.isEmpty()) + parent->m_edit->setText(text); + Command cmd; + cmd->id = CmdSend; + cmd->flags = 0; + cmd->param = parent; + EventCommandChecked(cmd).process(); +} + +void MsgAuth::init() +{ + m_edit->m_edit->setFocus(); +} + +bool MsgAuth::processEvent(Event *e) +{ + if (e->type() == eEventCheckCommandState){ + EventCheckCommandState *ecs = static_cast(e); + CommandDef *cmd = ecs->cmd(); + if (cmd->param == m_edit){ + unsigned id = cmd->bar_grp; + if ((id >= MIN_INPUT_BAR_ID) && (id < MAX_INPUT_BAR_ID)){ + cmd->flags |= BTN_HIDE; + return true; + } + switch (cmd->id){ + case CmdTranslit: + case CmdSmile: + case CmdSend: + case CmdSendClose: + e->process(this); + cmd->flags &= ~BTN_HIDE; + return true; + case CmdNextMessage: + case CmdMsgAnswer: + e->process(this); + cmd->flags |= BTN_HIDE; + return true; + } + } + } else + if (e->type() == eEventCommandExec){ + EventCommandExec *ece = static_cast(e); + CommandDef *cmd = ece->cmd(); + if ((cmd->id == CmdSend) && (cmd->param == m_edit)){ + QString msgText = m_edit->m_edit->toPlainText(); + AuthMessage *msg = new AuthMessage(m_type); + msg->setText(msgText); + msg->setContact(m_edit->m_userWnd->id()); + msg->setClient(m_client); + m_edit->sendMessage(msg); + return true; + } + } + return false; +} + +/* +#ifndef NO_MOC_INCLUDES +#include "msgauth.moc" +#endif +*/ + diff --git a/plugins/_core/msgauth.h b/plugins/_core/msgauth.h new file mode 100644 index 0000000..21a85bf --- /dev/null +++ b/plugins/_core/msgauth.h @@ -0,0 +1,43 @@ +/*************************************************************************** + msgauth.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _MSGAUTH_H +#define _MSGAUTH_H + +#include +#include + +#include "event.h" + +class MsgEdit; + +class MsgAuth : public QObject, public SIM::EventReceiver +{ + Q_OBJECT +public: + MsgAuth(MsgEdit *parent, SIM::Message *msg); +protected slots: + void init(); +protected: + virtual bool processEvent(SIM::Event*); + QString m_client; + unsigned m_type; + MsgEdit *m_edit; +}; + +#endif + diff --git a/plugins/_core/msgcfg.cpp b/plugins/_core/msgcfg.cpp new file mode 100644 index 0000000..dba833d --- /dev/null +++ b/plugins/_core/msgcfg.cpp @@ -0,0 +1,71 @@ +/*************************************************************************** + msgcfg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "msgcfg.h" +#include "filecfg.h" +#include "smscfg.h" +#include "core.h" + +#include +#include +#include + +MessageConfig::MessageConfig(QWidget *parent, SIM::PropertyHubPtr _data) + : QWidget(parent) +{ + setupUi(this); + m_file = NULL; + for (QObject *p = parent; p != NULL; p = p->parent()){ + QTabWidget *tab = qobject_cast(p); + if(!tab) + continue; + m_file = new FileConfig(tab, _data); + tab->addTab(m_file, i18n("File")); + tab->adjustSize(); + break; + } + + SIM::PropertyHubPtr data = _data; + chkOnline->setChecked(data->value("OpenOnOnline").toBool()); + chkStatus->setChecked(data->value("LogStatus").toBool()); + switch (data->value("OpenNewMessage").toUInt()){ + case NEW_MSG_NOOPEN: + btnNoOpen->setChecked(true); + break; + case NEW_MSG_MINIMIZE: + btnMinimize->setChecked(true); + break; + case NEW_MSG_RAISE: + btnRaise->setChecked(true); + break; + } +} + +void MessageConfig::apply(SIM::PropertyHubPtr _data) +{ + if (m_file) + m_file->apply(_data); + + SIM::PropertyHubPtr data = _data; + data->setValue("OpenOnOnline", chkOnline->isChecked()); + data->setValue("LogStatus", chkStatus->isChecked()); + data->setValue("OpenNewMessage", NEW_MSG_NOOPEN); + if (btnMinimize->isChecked()) + data->setValue("OpenNewMessage", NEW_MSG_MINIMIZE); + if (btnRaise->isChecked()) + data->setValue("OpenNewMessage", NEW_MSG_RAISE); +} diff --git a/plugins/_core/msgcfg.h b/plugins/_core/msgcfg.h new file mode 100644 index 0000000..70f4cb2 --- /dev/null +++ b/plugins/_core/msgcfg.h @@ -0,0 +1,38 @@ +/*************************************************************************** + msgcfg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _MSGCFG_H +#define _MSGCFG_H + +#include "propertyhub.h" +#include "ui_msgcfgbase.h" + +class FileConfig; + +class MessageConfig : public QWidget, public Ui::MessageConfigBase +{ + Q_OBJECT +public: + MessageConfig(QWidget *parent, SIM::PropertyHubPtr data); +public slots: + void apply(SIM::PropertyHubPtr); +protected: + FileConfig *m_file; +}; + +#endif + diff --git a/plugins/_core/msgcfgbase.ui b/plugins/_core/msgcfgbase.ui new file mode 100644 index 0000000..1f4be5d --- /dev/null +++ b/plugins/_core/msgcfgbase.ui @@ -0,0 +1,85 @@ + + + MessageConfigBase + + + + 0 + 0 + 521 + 389 + + + + Form1 + + + + + + Save &status changes to history + + + + + + + Open window if user go online + + + + + + + New message + + + + + + &No open + + + + + + + Open and &minimize + + + + + + + Open and &raise + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + chkStatus + chkOnline + + + + diff --git a/plugins/_core/msgcontacts.cpp b/plugins/_core/msgcontacts.cpp new file mode 100644 index 0000000..5fe960c --- /dev/null +++ b/plugins/_core/msgcontacts.cpp @@ -0,0 +1,153 @@ +/*************************************************************************** + msgcontacts.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "msgcontacts.h" +#include "msgedit.h" + +#include "userwnd.h" +#include "userlist.h" +#include "core.h" +#include "contacts/contact.h" +#include "simgui/textshow.h" +#include "simgui/toolbtn.h" + +#include + +using namespace std; +using namespace SIM; + +MsgContacts::MsgContacts(MsgEdit *parent, Message *msg) + : QObject(parent) +{ + m_client = msg->client(); + m_edit = parent; + m_list = new UserList(m_edit); + m_edit->m_layout->addWidget(m_list); + connect(m_list, SIGNAL(selectChanged()), this, SLOT(changed())); + ContactsMessage *m = static_cast(msg); + QString contacts = m->getContacts(); + while (contacts.length()){ + QString item = getToken(contacts, ';'); + QString url = getToken(item, ','); + QString proto = getToken(url, ':'); + if (proto == "sim"){ + unsigned contact_id = url.toULong(); + if (getContacts()->contact(contact_id)) + m_list->select( contact_id ); + } + } + changed(); + connect(m_edit, SIGNAL(finished()), this, SLOT(editFinished())); + connect(m_list, SIGNAL(finished()), this, SLOT(listFinished())); +} + +MsgContacts::~MsgContacts() +{ + if (m_edit && m_edit->m_edit) + m_edit->m_edit->show(); + if (m_list) + delete m_list; +} + +void MsgContacts::editFinished() +{ + m_edit = NULL; +} + +void MsgContacts::listFinished() +{ + m_list = NULL; +} + +void MsgContacts::changed() +{ + Command cmd; + cmd->id = CmdSend; + cmd->flags = m_list->isHaveSelected() ? 0 : COMMAND_DISABLED; + cmd->param = m_edit; + EventCommandDisabled(cmd).process(); +} + +void MsgContacts::init() +{ + m_edit->m_edit->hide(); + m_list->show(); + m_list->setFocus(); +} + +bool MsgContacts::processEvent(Event *e) +{ + if (e->type() == eEventCheckCommandState){ + EventCheckCommandState *ecs = static_cast(e); + CommandDef *cmd = ecs->cmd(); + if (cmd->param == m_edit){ + unsigned id = cmd->bar_grp; + if ((id >= MIN_INPUT_BAR_ID) && (id < MAX_INPUT_BAR_ID)){ + cmd->flags |= BTN_HIDE; + return true; + } + switch (cmd->id){ + case CmdSend: + case CmdSendClose: + e->process(this); + cmd->flags &= ~BTN_HIDE; + return true; + case CmdTranslit: + case CmdSmile: + case CmdNextMessage: + case CmdMsgAnswer: + e->process(this); + cmd->flags |= BTN_HIDE; + return true; + } + } + } else + if (e->type() == eEventCommandExec){ + EventCommandExec *ece = static_cast(e); + CommandDef *cmd = ece->cmd(); + if ((cmd->id == CmdSend) && (cmd->param == m_edit)){ + QString msgText = m_edit->m_edit->toPlainText(); + QString contacts; + QList< unsigned int > listSelected = m_list->selected(); + foreach( unsigned int id, listSelected ) { + Contact *contact = getContacts()->contact( id ); + if (contact){ + if (!contacts.isEmpty()) + contacts += ';'; + contacts += QString("sim:%1,%2") .arg( id ) .arg( contact->getName() ); + } + } + if (!contacts.isEmpty()){ + ContactsMessage *msg = new ContactsMessage; + msg->setContact(m_edit->m_userWnd->id()); + msg->setContacts(contacts); + msg->setClient(m_client); + m_edit->sendMessage(msg); + } + return true; + } + } + return false; +} + + +/* +#ifndef NO_MOC_INCLUDES +#include "msgcontacts.moc" +#endif +*/ + diff --git a/plugins/_core/msgcontacts.h b/plugins/_core/msgcontacts.h new file mode 100644 index 0000000..b83836d --- /dev/null +++ b/plugins/_core/msgcontacts.h @@ -0,0 +1,48 @@ +/*************************************************************************** + msgcontacts.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _MSGCONTACTS_H +#define _MSGCONTACTS_H + +#include +#include + +#include "event.h" + +class MsgEdit; +class UserList; + +class MsgContacts : public QObject, public SIM::EventReceiver +{ + Q_OBJECT +public: + MsgContacts(MsgEdit *btn, SIM::Message *msg); + ~MsgContacts(); +protected slots: + void init(); + void changed(); + void editFinished(); + void listFinished(); +protected: + virtual bool processEvent(SIM::Event*); + UserList *m_list; + MsgEdit *m_edit; + QString m_client; +}; + +#endif + diff --git a/plugins/_core/msgedit.cpp b/plugins/_core/msgedit.cpp new file mode 100644 index 0000000..18a054f --- /dev/null +++ b/plugins/_core/msgedit.cpp @@ -0,0 +1,1683 @@ +/*************************************************************************** + msgedit.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "msgedit.h" + +#include "simapi.h" +#include "contacts/clientdataiterator.h" +#include "contacts/contact.h" +#include "contacts/client.h" + +#include "userwnd.h" +#include "simgui/toolbtn.h" + +#include "log.h" +#include "msgrecv.h" +#include "msgsms.h" +#include "msgurl.h" +#include "msgcontacts.h" +#include "simgui/listview.h" +#include "msgfile.h" +#include "msgauth.h" +#include "userlist.h" +#include "simgui/ballonmsg.h" +#include "container.h" +#include "icons.h" +#include "history.h" + +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace SIM; + +const unsigned NO_TYPE = (unsigned)(-1); + +MsgTextEdit::MsgTextEdit(MsgEdit *edit, QWidget *parent) + : TextEdit(parent) +{ + m_edit = edit; + setBackground(CorePlugin::instance()->value("EditBackground").toUInt()); + setForeground(CorePlugin::instance()->value("EditForeground").toUInt(), true); +#if defined(USE_KDE) +#if KDE_IS_VERSION(3,2,0) + setCheckSpellingEnabled(CorePlugin::instance()->getEnableSpell()); +#endif +#endif +} + +void MsgTextEdit::contextMenuEvent(QContextMenuEvent* event) +{ + if (m_bInClick) + return; + + m_popupPos = event->pos(); + + Command cmd; + + cmd->popup_id = MenuTextEdit; + cmd->param = (TextEdit*)this; + cmd->flags = COMMAND_NEW_POPUP; + EventMenuGet e(cmd); + e.process(); + if(e.menu()) + e.menu()->exec(event->globalPos()); +} + +Message *MsgTextEdit::createMessage(QMimeSource *src) +{ + Message *msg = NULL; + CommandDef *cmd; + CommandsMapIterator it(CorePlugin::instance()->messageTypes); + while ((cmd = ++it) != NULL){ + MessageDef *def = (MessageDef*)(cmd->param); + if (def && def->drag){ + msg = def->drag(src); + if (msg){ + Command c; + c->id = cmd->id; + c->menu_id = MenuMessage; + c->param = (void*)(m_edit->m_userWnd->id()); + if (EventCheckCommandState(c).process()) + break; + delete msg; + msg = NULL; + } + } + } + return msg; +} + +void MsgTextEdit::contentsDropEvent(QDropEvent *e) +{ + Message *msg = createMessage(e); + if (msg){ + e->accept(); + msg->setContact(m_edit->m_userWnd->id()); + EventOpenMessage(msg).process(); + delete msg; + return; + } + //TextEdit::contentsDropEvent(e); //FIXME +} + +void MsgTextEdit::contentsDragEnterEvent(QDragEnterEvent *e) +{ + Message *msg = createMessage(e); + if (msg){ + delete msg; + e->accept(); + return; + } + //TextEdit::contentsDragEnterEvent(e); //FIXME +} + +void MsgTextEdit::contentsDragMoveEvent(QDragMoveEvent *e) +{ + Message *msg = createMessage(e); + if (msg){ + delete msg; + e->accept(); + return; + } + //TextEdit::contentsDragMoveEvent(e); //FIXME +} + +MsgEdit::MsgEdit(QWidget *parent, UserWnd *userWnd) : QFrame(parent) +{ + m_userWnd = userWnd; + m_msg = NULL; + m_bTyping = false; + m_type = NO_TYPE; + m_flags = 0; + m_retry.msg = NULL; + m_bReceived = false; + m_processor = NULL; + m_recvProcessor = NULL; + m_cmd.param = NULL; + + connect(CorePlugin::instance(), SIGNAL(modeChanged()), this, SLOT(modeChanged())); + + m_layout = new QVBoxLayout(this); + m_layout->setMargin(0); + + m_edit = new MsgTextEdit(this, this); + m_edit->setBackground(QColor(CorePlugin::instance()->value("EditBackground").toUInt() & 0xFFFFFF)); + m_edit->setBackground(QColor(255, 255, 255)); + m_edit->setForeground(QColor(CorePlugin::instance()->value("EditForeground").toUInt() & 0xFFFFFF), true); + m_edit->setFont(CorePlugin::instance()->editFont); + m_edit->setCtrlMode(!CorePlugin::instance()->value("SendOnEnter").toBool()); + m_edit->setParam(this); + setFocusProxy(m_edit); + + connect(m_edit, SIGNAL(lostFocus()), this, SLOT(editLostFocus())); + connect(m_edit, SIGNAL(textChanged()), this, SLOT(editTextChanged())); + connect(m_edit, SIGNAL(ctrlEnterPressed()), this, SLOT(editEnterPressed())); + connect(m_edit, SIGNAL(colorsChanged()), this, SLOT(colorsChanged())); + connect(m_edit, SIGNAL(finished()), this, SLOT(editFinished())); + connect(m_edit, SIGNAL(fontSelected(const QFont&)), this, SLOT(editFontChanged(const QFont&))); + + QFontMetrics fm(m_edit->font()); + m_edit->setMinimumSize(QSize(fm.maxWidth(), fm.height() + 10)); + + EventToolbar e(ToolBarMsgEdit, NULL); + e.process(); + m_bar = e.toolBar(); + m_bar->setParam(this); + + m_layout->addWidget(m_bar); + m_layout->addWidget(m_edit); + + if (CorePlugin::instance()->getContainerMode() == 0) + showCloseSend(false); +} + +MsgEdit::~MsgEdit() +{ + typingStop(); + editLostFocus(); + if (m_retry.msg) + delete m_retry.msg; + emit finished(); +} + +void MsgEdit::editFinished() +{ + m_edit = NULL; +} + +void MsgEdit::execCommand(CommandDef *cmd) +{ + if (m_cmd.param){ + Message *msg = (Message*)(m_cmd.param); + delete msg; + } + m_cmd = *cmd; + QTimer::singleShot(0, this, SLOT(execCommand())); +} + +void MsgEdit::execCommand() +{ + if (m_cmd.param == NULL) + return; + Message *msg = (Message*)(m_cmd.param); + EventCommandExec(&m_cmd).process(); + delete msg; + m_cmd.param = NULL; + switch (m_cmd.id){ + case CmdMsgQuote: + case CmdMsgForward: + break; + default: + goNext(); + } +} + +void MsgEdit::showCloseSend(bool bState) +{ + Command cmd; + cmd->id = CmdSendClose; + cmd->text = I18N_NOOP("C&lose after send"); + cmd->icon = "exit"; + cmd->icon_on = "exit"; + cmd->bar_grp = 0x7010; + cmd->flags = bState ? COMMAND_DEFAULT : BTN_HIDE; + cmd->param = this; + if (CorePlugin::instance()->value("CloseSend").toBool()) + cmd->flags |= COMMAND_CHECKED; + EventCommandChange(cmd).process(); +} + +void MsgEdit::resizeEvent(QResizeEvent *e) +{ + QFrame::resizeEvent(e); + emit heightChanged(height()); +} + +void MsgEdit::editFontChanged(const QFont &f) +{ + if (!CorePlugin::instance()->value("EditSaveFont").toBool()) + return; + CorePlugin::instance()->editFont = f; +} + +bool MsgEdit::setMessage(Message *msg, bool bSetFocus) +{ + m_type = msg->type(); + m_userWnd->setMessageType(msg->type()); + m_resource = msg->getResource(); + m_bReceived = msg->getFlags() & MESSAGE_RECEIVED; + QObject *processor = NULL; + MsgReceived *rcv = NULL; + if (m_bReceived){ + if ((msg->getFlags() & MESSAGE_OPEN) || (CorePlugin::instance()->getContainerMode() == 0)){ + rcv = new MsgReceived(this, msg, true); + processor = rcv; + }else{ + if (m_recvProcessor == NULL){ + rcv = new MsgReceived(this, msg, false); + m_recvProcessor = rcv; + } + } + }else{ + QObject *(*create)(MsgEdit *custom, Message *msg) = NULL; + CommandDef *cmd = CorePlugin::instance()->messageTypes.find(msg->baseType()); + if (cmd == NULL) + return false; + MessageDef *def = (MessageDef*)(cmd->param); + if (def == NULL) + return false; + create = def->generate; + if (create){ + m_userWnd->setStatus(QString::null); + processor = create(this, msg); + } + } + if (processor){ + if (m_recvProcessor){ + delete m_recvProcessor; + m_recvProcessor = NULL; + } + if (m_processor){ + delete m_processor; + m_processor = NULL; + } + m_processor = processor; + } + m_client = msg->client(); + + Contact *contact = getContacts()->contact(m_userWnd->id()); + if (contact){ + EventContactClient(contact).process(); + } + + m_bar->checkState(); + if (rcv) + rcv->init(); + Command cmd; + cmd->id = CmdMultiply; + cmd->flags = COMMAND_DEFAULT; + cmd->param = this; + if (msg->getFlags() & MESSAGE_FORWARD){ + cmd->flags = COMMAND_CHECKED; + m_userWnd->showListView(true); + } + EventCommandChecked(cmd).process(); + + if (m_processor && bSetFocus) + QTimer::singleShot(0, m_processor, SLOT(init())); + return true; +} + +Client *MsgEdit::client(void *&data, bool bCreate, bool bTyping, unsigned contact_id, bool bUseClient) +{ + data = NULL; + Contact *contact = getContacts()->contact(contact_id); + if (!bUseClient || m_client.isEmpty()){ + if (contact == NULL) + return NULL; + vector cs; + getWays(cs, contact); + unsigned i; + for (i = 0; i < cs.size(); i++){ + Client *client = getContacts()->getClient(cs[i].client); + if (client->canSend(m_type, cs[i].data)){ + data = cs[i].data; + if (bTyping) + changeTyping(client, data); + return client; + } + } + for (i = 0; i < cs.size(); i++){ + for (unsigned n = 0; n < getContacts()->nClients(); n++){ + Client *client = getContacts()->getClient(n); + clientData *d = cs[i].data; + Contact *c; + if (!client->isMyData(d, c)) + continue; + if (c && (c != contact)) + continue; + if (client->canSend(m_type, d)){ + if (bCreate) + client->createData(cs[i].data, contact); + data = cs[i].data; + if (bTyping) + changeTyping(client, data); + return client; + } + } + } + if (bTyping) + changeTyping(NULL, NULL); + return NULL; + } + if (contact == NULL) + return NULL; + void *d; + ClientDataIterator it(contact->clientData); + while ((d = ++it) != NULL){ + if (it.client()->dataName(d) == m_client){ + data = d; + if (bTyping) + changeTyping(it.client(), data); + return it.client(); + } + } + if (bTyping) + changeTyping(NULL, NULL); + return NULL; +} + +void MsgEdit::setInput() +{ + if (m_recvProcessor){ + delete m_recvProcessor; + m_recvProcessor = NULL; + m_bar->checkState(); + } +} + +static Message *createGeneric(Buffer *cfg) +{ + return new Message(MessageGeneric, cfg); +} + +static QObject *generateGeneric(MsgEdit *w, Message *msg) +{ + return new MsgGen(w, msg); +} + +#if 0 +i18n("Message", "%n messages", 1); +#endif + +static MessageDef defGeneric = + { + NULL, + NULL, + MESSAGE_DEFAULT, + "Message", + "%n messages", + createGeneric, + generateGeneric, + NULL + }; + +static Message *createSMS(Buffer *cfg) +{ + return new SMSMessage(cfg); +} + +static QObject* generateSMS(MsgEdit *w, Message *msg) +{ + return new MsgSMS(w, msg); +} + +#if 0 +i18n("SMS", "%n SMSs", 1); +#endif + +static MessageDef defSMS = + { + NULL, + NULL, + MESSAGE_DEFAULT, + "SMS", + "%n SMSs", + createSMS, + generateSMS, + NULL + }; + +#if 0 +i18n("URL", "%n URLs", 1); +#endif + +static Message *createUrl(Buffer *cfg) +{ + return new UrlMessage(MessageUrl, cfg); +} + +static QObject *generateUrl(MsgEdit *p, Message *msg) +{ + return new MsgUrl(p, msg); +} + +static Message *dropUrl(QMimeSource *src) +{ + log(L_DEBUG, "FIXME: Message:dropUrl"); + /* + if (Q3UriDrag::canDecode(src)){ + QStringList l; + if (Q3UriDrag::decodeLocalFiles(src, l)) + return NULL; + if (!Q3UriDrag::decodeToUnicodeUris(src, l) || (l.count() < 1)) + return NULL; + UrlMessage *msg = new UrlMessage; + msg->setUrl(l[0]); + return msg; + } + */ + return NULL; +} + +static MessageDef defUrl = + { + NULL, + NULL, + MESSAGE_DEFAULT, + "URL", + "%n URLs", + createUrl, + generateUrl, + dropUrl + }; + +static Message *createContacts(Buffer *cfg) +{ + return new ContactsMessage(MessageContacts, cfg); +} + +static QObject *generateContacts(MsgEdit *p, Message *msg) +{ + return new MsgContacts(p, msg); +} + +static Message *dropContacts(QMimeSource *src) +{ + if (ContactDragObject::canDecode(src)){ + Contact *contact = ContactDragObject::decode(src); + ContactsMessage *msg = new ContactsMessage; + QString name = contact->getName(); + msg->setContacts(QString("sim:") + QString::number(contact->id()) + ',' + getToken(name, '/')); + return msg; + } + return NULL; +} + +#if 0 +i18n("Contact list", "%n contact lists", 1); +#endif + +static MessageDef defContacts = + { + NULL, + NULL, + MESSAGE_DEFAULT, + "Contact list", + "%n contact lists", + createContacts, + generateContacts, + dropContacts + }; + +static Message *createFile(Buffer *cfg) +{ + return new FileMessage(MessageFile, cfg); +} + +static QObject* generateFile(MsgEdit *w, Message *msg) +{ + return new MsgFile(w, msg); +} + +Message *dropFile(QMimeSource *src) +{ + log(L_DEBUG, "FIXME: Message:dropFile"); + /* + if (Q3UriDrag::canDecode(src)){ + QStringList files; + if (Q3UriDrag::decodeLocalFiles(src, files) && files.count()){ + QString fileName; + for (QStringList::Iterator it = files.begin(); it != files.end(); ++it){ + if (!fileName.isEmpty()) + fileName += ','; + fileName += '\"'; + fileName += *it; + fileName += '\"'; + } + FileMessage *m = new FileMessage; + m->setFile(fileName); + return m; + } + } + */ + return NULL; +} + +#if 0 +i18n("File", "%n files", 1); +#endif + +static CommandDef fileCommands[] = + { + CommandDef ( + CmdFileAccept, + I18N_NOOP("&Accept"), + QString::null, + QString::null, + QString::null, + ToolBarMsgEdit, + 0x1090, + MenuMessage, + 0, + 0, + COMMAND_CHECK_STATE, + NULL, + QString::null + ), + CommandDef ( + CmdFileDecline, + I18N_NOOP("&Decline"), + QString::null, + QString::null, + QString::null, + ToolBarMsgEdit, + 0x1091, + MenuMessage, + 0, + MenuFileDecline, + COMMAND_CHECK_STATE, + NULL, + QString::null + ), + CommandDef () + }; + +static MessageDef defFile = + { + fileCommands, + NULL, + MESSAGE_DEFAULT, + "File", + "%n files", + createFile, + generateFile, + dropFile + }; + +static Message *createAuthRequest(Buffer *cfg) +{ + return new AuthMessage(MessageAuthRequest, cfg); +} + +static QObject* generateAuth(MsgEdit *w, Message *msg) +{ + return new MsgAuth(w, msg); +} + +#if 0 +i18n("Authorize request", "%n authorize requests", 1); +#endif + +static CommandDef authRequestCommands[] = + { + CommandDef ( + CmdGrantAuth, + I18N_NOOP("&Grant"), + QString::null, + QString::null, + QString::null, + ToolBarMsgEdit, + 0x1080, + MenuMessage, + 0, + 0, + COMMAND_DEFAULT, + NULL, + "" + ), + CommandDef ( + CmdRefuseAuth, + I18N_NOOP("&Refuse"), + QString::null, + QString::null, + QString::null, + ToolBarMsgEdit, + 0x1081, + MenuMessage, + 0, + 0, + COMMAND_DEFAULT, + NULL, + QString::null + ), + CommandDef () + }; + +static MessageDef defAuthRequest = + { + authRequestCommands, + NULL, + MESSAGE_DEFAULT | MESSAGE_SYSTEM, + "Authorize request", + "%n authorize requests", + createAuthRequest, + generateAuth, + NULL + }; + +static Message *createAuthGranted(Buffer *cfg) +{ + return new AuthMessage(MessageAuthGranted, cfg); +} + +#if 0 +i18n("Authorization granted", "%n authorization granted", 1); +#endif + +static MessageDef defAuthGranted = + { + NULL, + NULL, + MESSAGE_SILENT, + "Authorization granted", + "%n authorization granted", + createAuthGranted, + generateAuth, + NULL + }; + +static Message *createAuthRefused(Buffer *cfg) +{ + return new AuthMessage(MessageAuthRefused, cfg); +} + +#if 0 +i18n("Authorization refused", "%n authorization refused", 1); +#endif + +static MessageDef defAuthRefused = + { + NULL, + NULL, + MESSAGE_SILENT | MESSAGE_ERROR, + "Authorization refused", + "%n authorization refused", + createAuthRefused, + generateAuth, + NULL + }; + +static Message *createAdded(Buffer *cfg) +{ + return new AuthMessage(MessageAdded, cfg); +} + +#if 0 +i18n("Add to contacts", "%n add to contacts", 1); +#endif + +static MessageDef defAdded = + { + NULL, + NULL, + MESSAGE_INFO | MESSAGE_SYSTEM, + "Add to contacts", + "%n add to contacts", + createAdded, + NULL, + NULL + }; + +static Message *createRemoved(Buffer *cfg) +{ + return new AuthMessage(MessageRemoved, cfg); +} + +#if 0 +i18n("Removed from contacts", "%n removed from contacts", 1); +#endif + +static MessageDef defRemoved = + { + NULL, + NULL, + MESSAGE_INFO | MESSAGE_SYSTEM, + "Removed from contacts", + "%n removed from contacts", + createRemoved, + NULL, + NULL + }; + +static Message *createStatus(Buffer *cfg) +{ + return new StatusMessage(cfg); +} + +#if 0 +i18n("Status changed", "%n times status changed", 1); +#endif + +static MessageDef defStatus = + { + NULL, + NULL, + MESSAGE_HIDDEN, + "Status changed", + "%n times status changed", + createStatus, + NULL, + NULL + }; + +static bool cmp_status(ClientStatus s1, ClientStatus s2) +{ + if (s1.status > s2.status) + return true; + if (s1.status < s2.status) + return false; + if (s1.data->LastSend.toULong() > s2.data->LastSend.toULong()) + return true; + if (s1.data->LastSend.toULong() < s2.data->LastSend.toULong()) + return false; + return s1.client < s2.client; +} + +void MsgEdit::getWays(vector &cs, Contact *contact) +{ + for (unsigned i = 0; i < getContacts()->nClients(); i++){ + Client *client = getContacts()->getClient(i); + ClientDataIterator it(contact->clientData, client); + clientData *data; + while ((data = ++it) != NULL){ + unsigned long status = STATUS_UNKNOWN; + unsigned style = 0; + QString statusIcon; + client->contactInfo(data, status, style, statusIcon); + ClientStatus s; + s.client = i; + s.status = status; + s.data = data; + cs.push_back(s); + } + } + sort(cs.begin(), cs.end(), cmp_status); +} + +bool MsgEdit::sendMessage(Message *msg) +{ + if (m_retry.msg){ + delete m_retry.msg; + m_retry.msg = NULL; + } + if (m_msg){ + delete msg; + if (EventMessageCancel(m_msg).process()) + m_msg = NULL; + stopSend(false); + return false; + } + bool bClose = true; + if (CorePlugin::instance()->getContainerMode()){ + bClose = false; + Command cmd; + cmd->id = CmdSendClose; + cmd->param = this; + EventCommandWidget eWidget(cmd); + eWidget.process(); + QToolButton *btnClose = qobject_cast(eWidget.widget()); + if (btnClose) + bClose = btnClose->isChecked(); + } + CorePlugin::instance()->setValue("CloseSend", bClose); + + Contact *contact = getContacts()->contact(m_userWnd->id()); + if (contact){ + SIM::PropertyHubPtr data = contact->getUserData("translit"); + if (!data.isNull() && data->value("Translit").toBool()) + msg->setFlags(msg->getFlags() | MESSAGE_TRANSLIT); + } + + msg->setFlags(msg->getFlags() | m_flags); + m_flags = 0; + + if (m_userWnd->m_list){ + if( !m_userWnd->m_list->isHaveSelected() ) + return false; + multiply = m_userWnd->m_list->selected(); + msg->setContact( multiply.first() ); + multiply.pop_front(); + msg->setClient(NULL); + if( multiply.count() > 0 ) + msg->setFlags(msg->getFlags() | MESSAGE_MULTIPLY); + }else if (!m_resource.isEmpty()){ + void *data = NULL; + Client *c = client(data, true, false, msg->contact(), true); + if (c){ + QString resources = c->resources(data); + while (!resources.isEmpty()){ + QString res = getToken(resources, ';'); + getToken(res, ','); + if (m_resource == res){ + msg->setResource(m_resource); + break; + } + } + } + } + + editLostFocus(); + Command cmd; + cmd->id = CmdSend; + cmd->text = I18N_NOOP("Cancel"); + cmd->icon = "cancel"; + cmd->flags = BTN_PICT; + cmd->param = this; + EventCommandChange(cmd).process(); + m_msg = msg; + return send(); +} + +bool MsgEdit::send() +{ + Contact *contact = getContacts()->contact(m_msg->contact()); + QString client_str = m_msg->client(); + bool bSent = false; + void *data = NULL; + if (contact){ + EventMessageSend(m_msg).process(); + if (client_str.isEmpty()){ + m_type = m_msg->type(); + Client *c = client(data, true, false, m_msg->contact(), (m_msg->getFlags() & MESSAGE_MULTIPLY) == 0); + if (c){ + m_msg->setClient(c->dataName(data)); + bSent = c->send(m_msg, data); + }else{ + data = NULL; + for (unsigned i = 0; i < getContacts()->nClients(); i++){ + Client *client = getContacts()->getClient(i); + if (client->send(m_msg, NULL)){ + bSent = true; + break; + } + } + } + }else{ + ClientDataIterator it(contact->clientData); + while ((data = ++it) != NULL){ + if (it.client()->dataName(data) == client_str){ + if (it.client()->send(m_msg, data)) + bSent = true; + break; + } + } + } + } + if (bSent){ + if (data){ + ((clientData*)data)->LastSend.asULong() = QDateTime::currentDateTime().toTime_t(); + } + }else{ + if (m_msg){ + delete m_msg; + m_msg = NULL; + } + stopSend(); + Command cmd; + cmd->id = CmdSend; + cmd->param = this; + EventCommandWidget eWidget(cmd); + eWidget.process(); + QWidget *msgWidget = eWidget.widget(); + if (msgWidget == NULL) + msgWidget = this; + BalloonMsg::message(i18n("No such client for send message"), msgWidget); + return false; + } + return true; +} + +void MsgEdit::stopSend(bool bCheck) +{ + if (m_userWnd->m_list){ + Command cmd; + m_userWnd->showListView(false); + cmd->id = CmdMultiply; + cmd->text = I18N_NOOP("Multi&ply send"); + cmd->icon = "1rightarrow"; + cmd->icon_on = "1leftarrow"; + cmd->flags = COMMAND_DEFAULT; + cmd->param = this; + EventCommandChange(cmd).process(); + } + multiply.clear(); + Command cmd; + cmd->id = CmdSend; + cmd->text = I18N_NOOP("&Send"); + cmd->icon = "mail_generic"; + cmd->bar_id = ToolBarMsgEdit; + cmd->bar_grp = 0x8000; + cmd->flags = BTN_PICT; + cmd->param = this; + EventCommandChange(cmd).process(); + if (bCheck && (m_msg == NULL)) + return; + if (m_msg) + m_msg = NULL; +} + +void MsgEdit::modeChanged() +{ + showCloseSend(CorePlugin::instance()->getContainerMode() != 0); + m_edit->setCtrlMode(CorePlugin::instance()->value("SendOnEnter").toBool()); +} + +bool MsgEdit::setType(unsigned type) +{ + CommandDef *def; + def = CorePlugin::instance()->messageTypes.find(type); + if (def == NULL) + return false; + MessageDef *mdef = (MessageDef*)(def->param); + if (mdef->flags & MESSAGE_SILENT) + return false; + if (mdef->create == NULL) + return false; + Message *msg = mdef->create(NULL); + if (msg == NULL) + return false; + m_userWnd->setMessage(msg); + delete msg; + return true; +} + +bool MsgEdit::adjustType() +{ + if (m_bReceived) + return true; + Command cmd; + cmd->menu_id = MenuMessage; + cmd->param = (void*)(m_userWnd->m_id); + cmd->id = m_userWnd->getMessageType(); + if (m_userWnd->getMessageType() != m_type) { + if(EventCheckCommandState(cmd).process()) { + if (setType(m_userWnd->getMessageType())) + return true; + } + } + cmd->id = m_type; + if(EventCheckCommandState(cmd).process()) + return true; + EventMenuGetDef eMenu(MenuMessage); + eMenu.process(); + CommandsDef *cmdsMsg = eMenu.defs(); + CommandsList itc(*cmdsMsg, true); + CommandDef *c; + unsigned desired = m_userWnd->getMessageType(); + bool bSet = false; + while ((c = ++itc) != NULL){ + if (c->id == CmdContactClients) + continue; + c->param = (void*)(m_userWnd->m_id); + if (!EventCheckCommandState(c).process()) + continue; + if (setType(c->id)){ + bSet = true; + break; + } + } + m_userWnd->setMessageType(desired); + return bSet; +} + +bool MsgEdit::processEvent(Event *e) +{ + switch (e->type()) { + case eEventContact: { + EventContact *ec = static_cast(e); + if (ec->contact()->id() != m_userWnd->m_id) + break; + adjustType(); + break; + } + case eEventClientChanged: { + adjustType(); + break; + } + case eEventMessageReceived: { + EventMessage *em = static_cast(e); + Message *msg = em->msg(); + if (msg->getFlags() & MESSAGE_NOVIEW) + return false; + if ((msg->contact() == m_userWnd->id()) && (msg->type() != MessageStatus)){ + if (CorePlugin::instance()->getContainerMode()){ + bool bSetFocus = false; + if (topLevelWidget() && topLevelWidget()->inherits("Container")){ + Container *container = static_cast(topLevelWidget()); + if (container->wnd() == m_userWnd) + bSetFocus = true; + } + setMessage(msg, bSetFocus); + }else{ + if (m_edit->isReadOnly()) + QTimer::singleShot(0, this, SLOT(setupNext())); + } + } + break; + } + case eEventRealSendMessage: { + EventRealSendMessage *ersm = static_cast(e); + if (ersm->edit() == this){ + sendMessage(ersm->msg()); + return true; + } + break; + } + case eEventCheckCommandState: { + EventCheckCommandState *ecs = static_cast(e); + CommandDef *cmd = ecs->cmd(); + if ((cmd->param == (TextEdit*)m_edit) && (cmd->id == CmdTranslit)){ + Contact *contact = getContacts()->contact(m_userWnd->id()); + if (contact){ + SIM::PropertyHubPtr data = contact->getUserData("translit"); + if(!data.isNull()) { + cmd->flags &= ~COMMAND_CHECKED; + if (data->value("Translit").toBool()) + cmd->flags |= COMMAND_CHECKED; + // FIXME: return true; missing here? + } + } + return false; + } + if ((cmd->menu_id != MenuTextEdit) || (cmd->param != (TextEdit*)m_edit)) + return false; + cmd->flags &= ~(COMMAND_CHECKED | COMMAND_DISABLED); + switch (cmd->id){ + case CmdUndo: + if (m_edit->isReadOnly()) + return false; + if (!m_edit->document()->isUndoAvailable()) + cmd->flags |= COMMAND_DISABLED; + return true; + case CmdRedo: + if (m_edit->isReadOnly()) + return false; + if (!m_edit->document()->isRedoAvailable()) + cmd->flags |= COMMAND_DISABLED; + return true; + case CmdCut: + if (m_edit->isReadOnly()) + return false; + case CmdCopy: + if (m_edit->textCursor().selectedText().isEmpty()) + cmd->flags |= COMMAND_DISABLED; + return true; + case CmdPaste: + if (m_edit->isReadOnly()) + return false; + if (QApplication::clipboard()->text().isEmpty()) + cmd->flags |= COMMAND_DISABLED; + return true; + case CmdClear: + if (m_edit->isReadOnly()) + return false; + case CmdSelectAll: + if (m_edit->toPlainText().isEmpty()) + cmd->flags |= COMMAND_DISABLED; + return true; + } + break; + } + case eEventCommandExec: { + EventCommandExec *ece = static_cast(e); + CommandDef *cmd = ece->cmd(); +#if defined(USE_KDE) +#if KDE_IS_VERSION(3,2,0) + if (cmd->id == CmdEnableSpell){ + m_edit->setCheckSpellingEnabled(cmd->flags & COMMAND_CHECKED); + return false; + } + else if ((cmd->id == CmdSpell) && (cmd->param == this)){ + m_edit->checkSpelling(); + return true; + } + else +#endif +#endif + if ((cmd->id == CmdSmile) && (cmd->param == this)){ + EventCommandWidget eWidget(cmd); + eWidget.process(); + QToolButton *btnSmile = qobject_cast(eWidget.widget()); + if (btnSmile){ + SmilePopup *popup = new SmilePopup(this); + connect(popup, SIGNAL(insert(const QString &)), this, SLOT(insertSmile(const QString &))); + QPoint p = CToolButton::popupPos(btnSmile, popup); + popup->move(p); + popup->show(); + } + return true; + } + else if ((cmd->id == CmdTranslit) && (cmd->param == this)){ + Contact *contact = getContacts()->contact(m_userWnd->id()); + if (contact){ + SIM::PropertyHubPtr data = contact->getUserData("translit", true); + data->setValue("Translit", ((cmd->flags & COMMAND_CHECKED) != 0)); + } + return true; + } + else if ((cmd->id == CmdMultiply) && (cmd->param == this)){ + m_userWnd->showListView((cmd->flags & COMMAND_CHECKED) != 0); + return true; + } + else if ((cmd->bar_id == ToolBarMsgEdit) && m_edit->isReadOnly() && (cmd->param == this)){ + switch (cmd->id){ + case CmdMsgAnswer:{ + Message *msg = new Message(MessageGeneric); + msg->setContact(m_userWnd->id()); + msg->setClient(m_client); + EventOpenMessage(msg).process(); + delete msg; + } + case CmdNextMessage: + QTimer::singleShot(0, this, SLOT(goNext())); + break; + } + } + else if ((cmd->menu_id != MenuTextEdit) || (cmd->param != this)) + return false; + switch (cmd->id){ + case CmdUndo: + m_edit->undo(); + return true; + case CmdRedo: + m_edit->redo(); + return true; + case CmdCut: + m_edit->cut(); + return true; + case CmdCopy: + m_edit->copy(); + return true; + case CmdPaste: + m_edit->paste(); + return true; + case CmdClear: + m_edit->clear(); + return true; + case CmdSelectAll: + m_edit->selectAll(); + return true; + } + break; + } + case eEventMessageSent: + case eEventMessageAcked: { + EventMessage *em = static_cast(e); + Message *msg = em->msg(); + if (msg == m_msg){ + QString err = msg->getError(); + if (!err.isEmpty()) + err = i18n(err); + Contact *contact = getContacts()->contact(msg->contact()); + if(!err.isEmpty()) + { + stopSend(); + Command cmd; + cmd->id = CmdSend; + cmd->param = this; + EventCommandWidget eWidget(cmd); + eWidget.process(); + QWidget *msgWidget = eWidget.widget(); + if (msgWidget == NULL) + msgWidget = this; + if (msg->getRetryCode()){ + m_retry.edit = this; + if (m_retry.msg) + delete m_retry.msg; + m_retry.msg = new Message(msg->type()); + m_retry.msg->setRetryCode(msg->getRetryCode()); + m_retry.msg->setError(msg->getError()); + EventMessageRetry e(&m_retry); + if (e.process()) + return false; + }else{ + BalloonMsg::message(err, msgWidget); + } + }else{ + if (contact){ + contact->setLastActive(QDateTime::currentDateTime().toTime_t()); + EventContact(contact, EventContact::eStatus).process(); + } + if (!multiply.empty() ){ + CommandDef *def = CorePlugin::instance()->messageTypes.find(m_msg->type()); + if (def){ + MessageDef *mdef = (MessageDef*)(def->param); + QByteArray cfg = m_msg->save(); + Buffer config; + config = "[Title]\n" + cfg; + config.setWritePos(0); + config.getSection(); + m_msg = (mdef->create)(&config); + m_msg->setContact( multiply.first() ); + multiply.pop_front(); + m_msg->setClient(NULL); + m_msg->setFlags(m_msg->getFlags() | MESSAGE_MULTIPLY); + if( multiply.empty() ) + m_msg->setFlags(m_msg->getFlags() | MESSAGE_LAST); + send(); + return false; + } + } + stopSend(); + bool bClose = true; + if (CorePlugin::instance()->getContainerMode()){ + bClose = false; + Command cmd; + cmd->id = CmdSendClose; + cmd->param = this; + EventCommandWidget eWidget(cmd); + eWidget.process(); + QToolButton *btnClose = qobject_cast(eWidget.widget()); + if (btnClose) + bClose = btnClose->isChecked(); + } + CorePlugin::instance()->setValue("CloseSend", bClose); + if (bClose){ + QTimer::singleShot(0, m_userWnd, SLOT(close())); + }else{ + setEmptyMessage(); + m_edit->setFont(CorePlugin::instance()->editFont); + m_edit->setForeground(CorePlugin::instance()->value("EditForeground").toUInt(), true); + m_edit->setBackground(CorePlugin::instance()->value("EditBackground").toUInt()); + } + } + } + break; + } + default: + break; + } + return false; +} + +void MsgEdit::setEmptyMessage() +{ + m_edit->setPlainText(QString()); + EventMenuGetDef eMenu(MenuMessage); + eMenu.process(); + CommandsDef *cmdsMsg = eMenu.defs(); + CommandsList itc(*cmdsMsg, true); + CommandDef *c; + while ((c = ++itc) != NULL){ + c->param = (void*)(m_userWnd->m_id); + if (EventCheckCommandState(c).process()){ + Message *msg; + CommandDef *def = CorePlugin::instance()->messageTypes.find(c->id); + if (def == NULL) + continue; + MessageDef *mdef = (MessageDef*)(def->param); + if (mdef->create == NULL) + continue; + msg = mdef->create(NULL); + msg->setContact(m_userWnd->m_id); + if (mdef->flags & MESSAGE_SILENT) + continue; + msg->setFlags(MESSAGE_NORAISE); + EventOpenMessage(msg).process(); + delete msg; + return; + } + } +} + +void MsgEdit::changeTyping(Client *client, void *data) +{ + if (!m_bTyping) + return; + if (client == NULL){ + typingStop(); + return; + } + if (client->dataName(data) == m_typingClient) + return; + typingStop(); + typingStart(); +} + +void MsgEdit::typingStart() +{ + typingStop(); + void *data = NULL; + Client *cl = client(data, false, false, m_userWnd->id(), m_userWnd->m_list == NULL); + if (cl == NULL) + return; + Message *msg = new Message(MessageTypingStart); + if (cl->send(msg, data)){ + m_typingClient = cl->dataName(data); + }else{ + delete msg; + } +} + +void MsgEdit::typingStop() +{ + if (m_typingClient.isEmpty()) + return; + Contact *contact = getContacts()->contact(m_userWnd->m_id); + if (contact == NULL) + return; + ClientDataIterator it(contact->clientData); + clientData *data; + while ((data = ++it) != NULL){ + if (it.client()->dataName(data) == m_typingClient){ + Message *msg = new Message(MessageTypingStop); + if (!it.client()->send(msg, data)) + delete msg; + break; + } + } + m_typingClient = QString::null; +} + +void MsgEdit::editTextChanged() +{ + bool bTyping = !m_edit->isEmpty(); + if (qApp->focusWidget() != m_edit) + bTyping = false; + if (m_bTyping == bTyping) + return; + m_bTyping = bTyping; + if (m_bTyping){ + typingStart(); + }else{ + typingStop(); + } +} + +void MsgEdit::editLostFocus() +{ + if (!m_bTyping) + return; + typingStop(); + m_bTyping = false; +} + +void MsgEdit::colorsChanged() +{ + CorePlugin::instance()->setValue("EditBackground", m_edit->background().rgb()); + CorePlugin::instance()->setValue("EditForeground", m_edit->foreground().rgb()); + EventHistoryColors().process(); +} + +void MsgEdit::insertSmile(const QString &id) +{ + QString img_src = QString("").arg(id); +// int para; +// int index; + QFont saveFont = m_edit->font(); + QColor saveColor = m_edit->textColor(); + // determine the current position of the cursor + //m_edit->insert("\255", false, true, true); //FIXME + m_edit->insertPlainText("\255"); + //m_edit->getCursorPosition(¶,&index); //FIXME + // RTF doesn't like < and > + QString txt = m_edit->toHtml(); + txt.replace(QRegExp("\255"),img_src); + m_edit->setHtml(txt); + //m_edit->setCursorPosition(para, index); //FIXME + m_edit->setCurrentFont(saveFont); + m_edit->setTextColor(saveColor); +} + +void MsgEdit::goNext() +{ + for (list::iterator it = CorePlugin::instance()->unread.begin(); it != CorePlugin::instance()->unread.end(); ++it){ + if (it->contact != m_userWnd->id()) + continue; + Message *msg = History::load(it->id, it->client, it->contact); + if (msg == NULL) + continue; + EventOpenMessage(msg).process(); + delete msg; + return; + } + if (CorePlugin::instance()->getContainerMode()){ + setEmptyMessage(); + return; + } + QTimer::singleShot(0, m_userWnd, SLOT(close())); +} + +void MsgEdit::setupNext() +{ + Command cmd; + cmd->id = CmdNextMessage; + cmd->param = this; + EventCommandWidget eWidget(cmd); + eWidget.process(); + CToolButton *btnNext = qobject_cast(eWidget.widget()); + if (btnNext == NULL) + return; + + unsigned type = 0; + unsigned count = 0; + for (list::iterator it = CorePlugin::instance()->unread.begin(); it != CorePlugin::instance()->unread.end(); ++it){ + if (it->contact != m_userWnd->id()) + continue; + if (count == 0) + type = it->type; + count++; + } + QString str = i18n("&Next"); + if (count > 1) + str += QString(" [%1]") .arg(count); + + CommandDef *def = NULL; + def = CorePlugin::instance()->messageTypes.find(type); + + CommandDef c = btnNext->def(); + c.text_wrk = str; + if (def) + c.icon = def->icon; + if (count){ + c.flags &= ~COMMAND_DISABLED; + }else{ + c.flags |= COMMAND_DISABLED; + } + btnNext->setCommand(&c); +} + +void MsgEdit::editEnterPressed() +{ + Command cmd; + cmd->id = CmdSend; + cmd->param = this; + EventCommandExec(cmd).process(); +} + +SmileLabel::SmileLabel(const QString &_id, QWidget *parent) + : QLabel(parent), id(_id) +{ + setPixmap(Pict(_id)); + QStringList smiles = getIcons()->getSmile(_id); + QString tip = smiles.front(); + QString name = getIcons()->getSmileName(_id); + if ((name[0] < '0') || (name[0] > '9')){ + tip += ' '; + tip += i18n(name); + } + this->setToolTip(tip); +} + +void SmileLabel::mouseReleaseEvent(QMouseEvent*) +{ + emit clicked(id); +} + +SmilePopup::SmilePopup(QWidget *popup) + : QFrame(popup, Qt::Popup) +{ + setAttribute(Qt::WA_DeleteOnClose); + + setFrameShape(QFrame::StyledPanel); + setFrameShadow(QFrame::Sunken); + setLineWidth(1); + + QSize s; + QStringList smiles; + getIcons()->getSmiles(smiles); + if (smiles.empty()) + return; + unsigned nSmiles = 0; + QStringList::iterator it; + for (it = smiles.begin(); it != smiles.end(); ++it) + { + QPixmap pict = Pict(*it); + s = QSize(qMax(s.width(), pict.width()), qMax(s.height(), pict.height())); + nSmiles++; + } + + unsigned rows = 4; + unsigned cols = (nSmiles + 3) / 4; + if (cols > 8){ + cols = 8; + rows = (nSmiles + 7) / cols; + } + + QGridLayout *lay = new QGridLayout(this); + lay->setMargin(4); + lay->setSpacing(2); + unsigned i = 0; + unsigned j = 0; + for (it = smiles.begin(); it != smiles.end(); ++it){ + QPixmap is = Pict(*it); + if (is.isNull()) + continue; + QWidget *w = new SmileLabel(*it, this); + w->setMinimumSize(s); + connect(w, SIGNAL(clicked(const QString &)), this, SLOT(labelClicked(const QString &))); + lay->addWidget(w, i, j); + if (++j >= cols){ + i++; + j = 0; + } + } + resize(minimumSizeHint()); +} + +void SmilePopup::labelClicked(const QString &id) +{ + insert(id); + close(); +} + +void MsgEdit::setupMessages() +{ + Command cmd; + + cmd->id = MessageGeneric; + cmd->text = I18N_NOOP("&Message"); + cmd->icon = "message"; + cmd->menu_grp = 0x3010; + cmd->accel = "Ctrl+M"; + cmd->flags = COMMAND_DEFAULT; + cmd->param = &defGeneric; + EventCreateMessageType(cmd).process(); + + cmd->id = MessageFile; + cmd->text = I18N_NOOP("&File"); + cmd->icon = "file"; + cmd->accel = "Ctrl+F"; + cmd->menu_grp = 0x3020; + cmd->flags = COMMAND_DEFAULT; + cmd->param = &defFile; + EventCreateMessageType(cmd).process(); + + cmd->id = MessageUrl; + cmd->text = I18N_NOOP("&URL"); + cmd->icon = "url"; + cmd->accel = "Ctrl+U"; + cmd->menu_grp = 0x3030; + cmd->flags = COMMAND_DEFAULT; + cmd->param = &defUrl; + EventCreateMessageType(cmd).process(); + + cmd->id = MessageSMS; + cmd->text = I18N_NOOP("SMS"); + cmd->icon = "sms"; + cmd->accel = "Ctrl+S"; + cmd->menu_grp = 0x3040; + cmd->flags = COMMAND_DEFAULT; + cmd->param = &defSMS; + EventCreateMessageType(cmd).process(); + + cmd->id = MessageContacts; + cmd->text = I18N_NOOP("&Contact list"); + cmd->icon = "contacts"; + cmd->accel = "Ctrl+L"; + cmd->menu_grp = 0x3050; + cmd->param = &defContacts; + EventCreateMessageType(cmd).process(); + + cmd->id = MessageAuthRequest; + cmd->text = I18N_NOOP("&Authorization request"); + cmd->icon = "auth"; + cmd->accel = "Ctrl+Q"; + cmd->menu_grp = 0x3060; + cmd->flags = COMMAND_DEFAULT; + cmd->param = &defAuthRequest; + EventCreateMessageType(cmd).process(); + + cmd->id = MessageAuthGranted; + cmd->text = I18N_NOOP("&Grant autorization"); + cmd->icon = "auth"; + cmd->accel = "Ctrl+G"; + cmd->menu_grp = 0x3070; + cmd->flags = COMMAND_DEFAULT; + cmd->param = &defAuthGranted; + EventCreateMessageType(cmd).process(); + + cmd->id = MessageAuthRefused; + cmd->text = I18N_NOOP("&Refuse autorization"); + cmd->icon = "auth"; + cmd->accel = "Ctrl+R"; + cmd->menu_grp = 0x3071; + cmd->flags = COMMAND_DEFAULT; + cmd->param = &defAuthRefused; + EventCreateMessageType(cmd).process(); + + cmd->id = MessageAdded; + cmd->text = I18N_NOOP("Added"); + cmd->icon = "auth"; + cmd->menu_grp = 0; + cmd->flags = COMMAND_DEFAULT; + cmd->param = &defAdded; + EventCreateMessageType(cmd).process(); + + cmd->id = MessageRemoved; + cmd->text = I18N_NOOP("Removed"); + cmd->icon = "auth"; + cmd->menu_grp = 0; + cmd->flags = COMMAND_DEFAULT; + cmd->param = &defRemoved; + EventCreateMessageType(cmd).process(); + + cmd->id = MessageStatus; + cmd->text = I18N_NOOP("Status"); + cmd->icon = QString::null; + cmd->menu_grp = 0; + cmd->flags = COMMAND_DEFAULT; + cmd->param = &defStatus; + EventCreateMessageType(cmd).process(); +} + diff --git a/plugins/_core/msgedit.h b/plugins/_core/msgedit.h new file mode 100644 index 0000000..6f815e8 --- /dev/null +++ b/plugins/_core/msgedit.h @@ -0,0 +1,140 @@ +/*************************************************************************** + msgedit.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _MSGEDIT_H +#define _MSGEDIT_H + +#include "core.h" +#include "simgui/textshow.h" +#include "event.h" + +#include + +class CorePlugin; +class UserWnd; +class CToolBar; +class QVBoxLayout; +class QFrame; +class TextEdit; + +struct ClientStatus +{ + unsigned long status; + unsigned client; + SIM::clientData *data; +}; + +class MsgTextEdit : public TextEdit +{ + Q_OBJECT +public: + MsgTextEdit(MsgEdit *edit, QWidget *parent); +protected: + virtual void contextMenuEvent(QContextMenuEvent* event); + virtual void contentsDropEvent(QDropEvent*); + virtual void contentsDragEnterEvent(QDragEnterEvent*); + virtual void contentsDragMoveEvent(QDragMoveEvent*); + SIM::Message *createMessage(QMimeSource*); + MsgEdit *m_edit; +}; + +class MsgEdit : public QFrame, public SIM::EventReceiver +{ + Q_OBJECT +public: + MsgEdit(QWidget *parent, UserWnd *userWnd); + ~MsgEdit(); + CToolBar *m_bar; + bool setMessage(SIM::Message *msg, bool bSetFocus); + UserWnd *m_userWnd; + TextEdit *m_edit; + QVBoxLayout *m_layout; + bool sendMessage(SIM::Message *msg); + static void setupMessages(); + void getWays(std::vector &cs, SIM::Contact *contact); + SIM::Client *client(void *&data, bool bCreate, bool bSendTyping, unsigned contact_id, bool bUseClient=true); + bool m_bReceived; + unsigned m_flags; + void execCommand(SIM::CommandDef *cmd); + unsigned type() { return m_type; } + bool adjustType(); + QString m_resource; +signals: + void heightChanged(int); + void init(); + void finished(); +public slots: + void insertSmile(const QString &id); + void modeChanged(); + void editLostFocus(); + void editTextChanged(); + void editEnterPressed(); + void setInput(); + void goNext(); + void setupNext(); + void colorsChanged(); + void execCommand(); + void editFinished(); + void editFontChanged(const QFont&); +protected: + QObject *m_processor; + QObject *m_recvProcessor; + unsigned m_type; + virtual bool processEvent(SIM::Event*); + void resizeEvent(QResizeEvent*); + void stopSend(bool bCheck=true); + void showCloseSend(bool bShow); + void typingStart(); + void typingStop(); + void changeTyping(SIM::Client *client, void *data); + void setEmptyMessage(); + bool setType(unsigned type); + bool m_bTyping; + QString m_typingClient; + bool send(); + QList< unsigned int > multiply; + SIM::CommandDef m_cmd; + SIM::Message *m_msg; + EventMessageRetry::MsgSend m_retry; + QString m_client; +}; + +class SmileLabel : public QLabel +{ + Q_OBJECT +public: + SmileLabel(const QString &id, QWidget *parent); +signals: + void clicked(const QString &id); +protected: + void mouseReleaseEvent(QMouseEvent*); + QString id; +}; + +class SmilePopup : public QFrame +{ + Q_OBJECT +public: + SmilePopup(QWidget *parent); +signals: + void insert(const QString &id); +protected slots: + void labelClicked(const QString &id); +}; + +#endif + diff --git a/plugins/_core/msgfile.cpp b/plugins/_core/msgfile.cpp new file mode 100644 index 0000000..ea6a34f --- /dev/null +++ b/plugins/_core/msgfile.cpp @@ -0,0 +1,215 @@ +/*************************************************************************** + msgfile.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "simapi.h" + +#include "msgfile.h" +#include "msgedit.h" +#include "userwnd.h" +#include "core.h" + +#include "simgui/toolbtn.h" +#include "simgui/textshow.h" + + +#include +#include +#include + +#ifdef USE_KDE +#include +#define QFileDialog KFileDialog +#else +#include +#endif + +using namespace SIM; + +MsgFile::MsgFile(MsgEdit *parent, Message *msg) + : QObject(parent) +{ + m_client = msg->client(); + m_edit = parent; + m_bCanSend = false; + if (m_edit->m_edit->isReadOnly()){ + m_edit->m_edit->setText(QString::null); + m_edit->m_edit->setReadOnly(false); + } + QString t = msg->getPlainText(); + if (!t.isEmpty()) + m_edit->m_edit->setText(t); + + Command cmd; + cmd->id = CmdFileName; + cmd->param = parent; + EventCommandWidget eWidget(cmd); + eWidget.process(); + CToolEdit *edtName = qobject_cast(eWidget.widget()); + if (edtName){ + connect(edtName, SIGNAL(textChanged(const QString&)), this, SLOT(changed(const QString&))); + edtName->setText(static_cast(msg)->getFile()); + } + changed(static_cast(msg)->getFile()); +} + +void MsgFile::init() +{ + if (!m_edit->topLevelWidget()->isActiveWindow() || m_edit->topLevelWidget()->isMinimized()) + return; + Command cmd; + cmd->id = CmdFileName; + cmd->param = m_edit; + EventCommandWidget eWidget(cmd); + eWidget.process(); + CToolEdit *edtName = qobject_cast(eWidget.widget()); + if (edtName){ + if (edtName->text().isEmpty()){ + selectFile(); + return; + } + edtName->setFocus(); + } +} + +void MsgFile::changed(const QString &str) +{ + if (m_bCanSend != str.isEmpty()) + return; + m_bCanSend = !str.isEmpty(); + Command cmd; + cmd->id = CmdSend; + cmd->flags = m_bCanSend ? 0 : COMMAND_DISABLED; + cmd->param = m_edit; + EventCommandDisabled(cmd).process(); +} + +void MsgFile::selectFile() +{ + Command cmd; + cmd->id = CmdFileName; + cmd->param = m_edit; + EventCommandWidget eWidget(cmd); + eWidget.process(); + CToolEdit *edtName = qobject_cast(eWidget.widget()); + if (edtName == NULL) + return; + QString s = edtName->text(); + QStringList lst = QFileDialog::getOpenFileNames(m_edit->topLevelWidget()); + if ((lst.count() > 1) || ((lst.count() > 0) && (lst[0].indexOf(' ') >= 0))){ + for (QStringList::Iterator it = lst.begin(); it != lst.end(); ++it){ + *it = '\"' + QDir::convertSeparators(*it) + '\"'; + } + }else{ + for (QStringList::Iterator it = lst.begin(); it != lst.end(); ++it){ + *it = QDir::convertSeparators(*it); + } + } + edtName->setText(lst.join(" ")); +} + +bool MsgFile::processEvent(Event *e) +{ + if (e->type() == eEventCheckCommandState){ + EventCheckCommandState *ecs = static_cast(e); + CommandDef *cmd = ecs->cmd(); + if (cmd->param == m_edit){ + unsigned id = cmd->bar_grp; + if ((id >= MIN_INPUT_BAR_ID) && (id < MAX_INPUT_BAR_ID)){ + cmd->flags |= BTN_HIDE; + if (cmd->id == CmdFileName) + cmd->flags &= ~BTN_HIDE; + return true; + } + switch (cmd->id){ + case CmdTranslit: + case CmdSmile: + case CmdSend: + case CmdSendClose: + e->process(this); + cmd->flags &= ~BTN_HIDE; + return true; + case CmdNextMessage: + case CmdMsgAnswer: + e->process(this); + cmd->flags |= BTN_HIDE; + return true; + } + } + } else + if (e->type() == eEventCommandExec){ + EventCommandExec *ece = static_cast(e); + CommandDef *cmd = ece->cmd(); + if (cmd->param == m_edit){ + if (cmd->id == CmdSend){ + Command cmd; + cmd->id = CmdFileName; + cmd->param = m_edit; + EventCommandWidget eWidget(cmd); + eWidget.process(); + CToolEdit *edtName = qobject_cast(eWidget.widget()); + if (edtName == NULL) + return false; + QString msgText = m_edit->m_edit->toPlainText(); + QString file = edtName->text(); + QStringList files; + QString f; + for (int i = 0; i < (int)file.length(); i++){ + if (file[i] == '\"'){ + f = f.trimmed(); + if (!f.isEmpty()) + files.append(f); + f = QString::null; + for (i++; i < (int)file.length(); i++){ + if (file[i] == '\"') + break; + f += file[i]; + } + f = f.trimmed(); + if (!f.isEmpty()) + files.append(f); + f = QString::null; + continue; + } + f += file[i]; + } + f = f.trimmed(); + if (!f.isEmpty()) + files.append(f); + file = QString::null; + for (QStringList::Iterator it = files.begin(); it != files.end(); ++it){ + if (!file.isEmpty()) + file += ';'; + file += quoteChars(*it, ";"); + } + if (!file.isEmpty()){ + FileMessage *msg = new FileMessage; + msg->setText(msgText); + msg->setFile(file); + msg->setContact(m_edit->m_userWnd->id()); + msg->setClient(m_client); + m_edit->sendMessage(msg); + } + return true; + } + if (cmd->id == CmdFileName){ + selectFile(); + return true; + } + } + } + return false; +} diff --git a/plugins/_core/msgfile.h b/plugins/_core/msgfile.h new file mode 100644 index 0000000..fca3af7 --- /dev/null +++ b/plugins/_core/msgfile.h @@ -0,0 +1,45 @@ +/*************************************************************************** + msgfile.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _MSGFILE_H +#define _MSGFILE_H + +#include +#include + +#include "event.h" + +class MsgEdit; + +class MsgFile : public QObject, public SIM::EventReceiver +{ + Q_OBJECT +public: + MsgFile(MsgEdit *parent, SIM::Message *msg); +protected slots: + void selectFile(); + void changed(const QString&); + void init(); +protected: + virtual bool processEvent(SIM::Event*); + QString m_client; + MsgEdit *m_edit; + bool m_bCanSend; +}; + +#endif + diff --git a/plugins/_core/msggen.cpp b/plugins/_core/msggen.cpp new file mode 100644 index 0000000..f23c873 --- /dev/null +++ b/plugins/_core/msggen.cpp @@ -0,0 +1,126 @@ +/*************************************************************************** + msggen.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "msggen.h" + +#include "simapi.h" +#include "log.h" + +#include "msgedit.h" +#include "userwnd.h" + +using namespace SIM; + +MsgGen::MsgGen(MsgEdit *parent, Message *msg) + : QObject(parent) +{ + m_client = msg->client(); + m_edit = parent; + if (m_edit->m_edit->isReadOnly()){ + m_edit->m_edit->setText(QString::null); + m_edit->m_edit->setReadOnly(false); + } + if (msg->getFlags() & MESSAGE_INSERT){ + QString text = msg->getPlainText(); + //m_edit->m_edit->insert(text, false, true, true); //FIXME + m_edit->m_edit->insertHtml(text); + }else{ + QString text = msg->getRichText(); + if (!text.isEmpty()){ + m_edit->m_edit->setText(text); + m_edit->m_edit->moveCursor(QTextCursor::End, QTextCursor::MoveAnchor); + if ((msg->getBackground() != msg->getForeground()) && !CorePlugin::instance()->value("OwnColors").toBool()){ + m_edit->m_edit->setBackground(msg->getBackground()); + m_edit->m_edit->setForeground(msg->getForeground(), true); + } + } + } + connect(m_edit->m_edit, SIGNAL(emptyChanged(bool)), this, SLOT(emptyChanged(bool))); + emptyChanged(m_edit->m_edit->isEmpty()); +} + +void MsgGen::init() +{ + if (m_edit->topLevelWidget()->isActiveWindow() && !m_edit->topLevelWidget()->isMinimized()) + m_edit->m_edit->setFocus(); +} + +void MsgGen::emptyChanged(bool bEmpty) +{ + Command cmd; + cmd->id = CmdSend; + cmd->flags = bEmpty ? COMMAND_DISABLED : 0; + cmd->param = m_edit; + EventCommandDisabled(cmd).process(); +} + +bool MsgGen::processEvent(Event *e) +{ + if (e->type() == eEventCheckCommandState){ + EventCheckCommandState *ecs = static_cast(e); + CommandDef *cmd = ecs->cmd(); + if (cmd->param == m_edit){ + unsigned id = cmd->bar_grp; + if ((id >= MIN_INPUT_BAR_ID) && (id < MAX_INPUT_BAR_ID)){ + cmd->flags |= BTN_HIDE; + return true; + } + switch (cmd->id){ + case CmdTranslit: + case CmdSmile: + case CmdSend: + case CmdSendClose: + e->process(this); + cmd->flags &= ~BTN_HIDE; + return true; + case CmdNextMessage: + case CmdMsgAnswer: + e->process(this); + cmd->flags |= BTN_HIDE; + return true; + } + } + } else + if (e->type() == eEventCommandExec){ + EventCommandExec *ece = static_cast(e); + CommandDef *cmd = ece->cmd(); + if ((cmd->id == CmdSend) && (cmd->param == m_edit)){ + QString msgText = m_edit->m_edit->toHtml(); + if (!msgText.isEmpty()) + { + msgText.remove(QRegExp("^]*>")); + msgText.remove(QRegExp("]*>[^<]*")); + log(L_DEBUG, "Send: %s", qPrintable(msgText)); + Message *msg = new Message; + msg->setText(msgText); + msg->setContact(m_edit->m_userWnd->id()); + msg->setClient(m_client); + msg->setFlags(MESSAGE_RICHTEXT); + msg->setForeground(m_edit->m_edit->foreground().rgb() & 0xFFFFFF); + msg->setBackground(m_edit->m_edit->background().rgb() & 0xFFFFFF); + msg->setFont(CorePlugin::instance()->value("EditFont").toString()); + m_edit->sendMessage(msg); + } + return true; + } + } + return false; +} + +// vim: set expandtab: + + diff --git a/plugins/_core/msggen.h b/plugins/_core/msggen.h new file mode 100644 index 0000000..91254ac --- /dev/null +++ b/plugins/_core/msggen.h @@ -0,0 +1,44 @@ +/*************************************************************************** + msggen.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _MSGGEN_H +#define _MSGGEN_H + +#include "event.h" + +#include +#include + +class MsgEdit; + +class MsgGen : public QObject, public SIM::EventReceiver +{ + Q_OBJECT +public: + MsgGen(MsgEdit *parent, SIM::Message *msg); +protected slots: + void init(); + void emptyChanged(bool bEmpty); +protected: + virtual bool processEvent(SIM::Event*); + QString m_client; + bool m_bCanSend; + MsgEdit *m_edit; +}; + +#endif + diff --git a/plugins/_core/msgrecv.cpp b/plugins/_core/msgrecv.cpp new file mode 100644 index 0000000..e886693 --- /dev/null +++ b/plugins/_core/msgrecv.cpp @@ -0,0 +1,209 @@ +/*************************************************************************** + msgrecv.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "msgrecv.h" +#include "msgedit.h" +#include "msgview.h" +#include "history.h" +#include "core.h" + +#include "simgui/toolbtn.h" +#include "simgui/textshow.h" + +#include +#include +#include + +using namespace std; +using namespace SIM; + +MsgReceived::MsgReceived(MsgEdit *parent, Message *msg, bool bOpen) + : QObject(parent), EventReceiver(HighPriority - 1) +{ + m_id = msg->id(); + m_contact = msg->contact(); + m_client = msg->client(); + m_edit = parent; + m_bOpen = bOpen; + m_msg = msg; + m_type = msg->baseType(); + + if (m_bOpen){ + m_edit->m_edit->setReadOnly(true); + QString p = msg->presentation(); + if (p.isEmpty()) + p = msg->getRichText(); + EventAddHyperlinks e(p); + e.process(); + p = MsgViewBase::parseText(e.text(), CorePlugin::instance()->value("OwnColors").toBool(), CorePlugin::instance()->value("UseSmiles").toBool()); + m_edit->m_edit->setText(p); + if ((msg->getBackground() != msg->getForeground()) && !CorePlugin::instance()->value("OwnColors").toBool()){ + m_edit->m_edit->setBackground(msg->getBackground()); + m_edit->m_edit->setForeground(msg->getForeground(), true); + } + for (list::iterator it = CorePlugin::instance()->unread.begin(); it != CorePlugin::instance()->unread.end(); ++it){ + if ((it->id == msg->id()) && + (it->contact == msg->contact()) && + (it->client == msg->client())){ + CorePlugin::instance()->unread.erase(it); + EventMessageRead(msg).process(); + break; + } + } + m_edit->setupNext(); + }else{ + connect(m_edit->m_edit, SIGNAL(textChanged()), m_edit, SLOT(setInput())); + } +} + +bool MsgReceived::processEvent(Event *e) +{ + if (e->type() == eEventCommandExec){ + EventCommandExec *ece = static_cast(e); + CommandDef *cmd = ece->cmd(); + unsigned id = cmd->bar_grp; + if (cmd->param == m_edit){ + MessageDef *mdef = NULL; + CommandDef *msgCmd = CorePlugin::instance()->messageTypes.find(m_type); + if (msgCmd) + mdef = (MessageDef*)(msgCmd->param); + if (mdef && mdef->cmdReceived){ + for (const CommandDef *d = mdef->cmdReceived; !d->text.isEmpty(); d++){ + if (d->popup_id && (d->popup_id == cmd->menu_id)){ + Message *msg = History::load(m_id, m_client, m_contact); + if (msg){ + CommandDef c = *cmd; + c.param = msg; + m_edit->execCommand(&c); + } + return true; + } + } + } + + if ((id >= MIN_INPUT_BAR_ID) && (id < MAX_INPUT_BAR_ID)){ + Message *msg = History::load(m_id, m_client, m_contact); + if (msg){ + CommandDef c = *cmd; + c.id -= CmdReceived; + c.param = msg; + m_edit->execCommand(&c); + } + return true; + } + } + } else + if (e->type() == eEventCheckCommandState){ + EventCheckCommandState *ecs = static_cast(e); + CommandDef *cmd = ecs->cmd(); + if (cmd->param == m_edit){ + unsigned id = cmd->bar_grp; + if ((id >= 0x1000) && (id < MAX_INPUT_BAR_ID)){ + cmd->flags |= BTN_HIDE; + switch (cmd->id - CmdReceived){ + case CmdMsgQuote: + case CmdMsgForward:{ + CommandDef c = *cmd; + Message *msg = m_msg; + if (msg == NULL) + msg = History::load(m_id, m_client, m_contact); + if (msg){ + c.id -= CmdReceived; + c.param = msg; + if (EventCheckCommandState(&c).process()) + cmd->flags &= ~BTN_HIDE; + if (m_msg == NULL) + delete msg; + } + return true; + } + } + MessageDef *mdef = NULL; + CommandDef *msgCmd = CorePlugin::instance()->messageTypes.find(m_type); + if (msgCmd) + mdef = (MessageDef*)(msgCmd->param); + if (mdef && mdef->cmdReceived){ + for (const CommandDef *d = mdef->cmdReceived; !d->text.isEmpty(); d++){ + if (d->id + CmdReceived == cmd->id){ + if (d->flags & COMMAND_CHECK_STATE){ + Message *msg = m_msg; + if (msg == NULL) + msg = History::load(m_id, m_client, m_contact); + if (msg){ + CommandDef c = *d; + c.param = msg; + if (EventCheckCommandState(&c).process()) + cmd->flags &= ~BTN_HIDE; + if (m_msg == NULL) + delete msg; + } + }else{ + cmd->flags &= ~BTN_HIDE; + } + return true; + } + } + } + return true; + } + if (cmd->id == CmdMsgAnswer){ + e->process(this); + cmd->flags |= BTN_HIDE; + if (CorePlugin::instance()->getContainerMode() == 0) + cmd->flags &= ~BTN_HIDE; + return true; + } + + if (m_bOpen){ + switch (cmd->id){ + case CmdTranslit: + case CmdSmile: + case CmdSend: + case CmdSendClose: + e->process(this); + cmd->flags |= BTN_HIDE; + return true; + case CmdNextMessage: + e->process(this); + cmd->flags |= BTN_HIDE; + if (CorePlugin::instance()->getContainerMode() == 0) + cmd->flags &= ~BTN_HIDE; + return true; + } + } + } + } else + if (e->type() == eEventMessageDeleted){ + EventMessage *em = static_cast(e); + Message *msg = em->msg(); + if (msg->id() == m_id) + QTimer::singleShot(0, m_edit, SLOT(goNext())); + } + return false; +} + +void MsgReceived::init() +{ + m_msg = NULL; +} + +/* +#ifndef NO_MOC_INCLUDES +#include "msgrecv.moc" +#endif +*/ + diff --git a/plugins/_core/msgrecv.h b/plugins/_core/msgrecv.h new file mode 100644 index 0000000..36af995 --- /dev/null +++ b/plugins/_core/msgrecv.h @@ -0,0 +1,44 @@ +/*************************************************************************** + msgrecv.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _MSGRECV_H +#define _MSGRECV_H + +#include "event.h" + +class MsgEdit; + +class MsgReceived : public QObject, public SIM::EventReceiver +{ + Q_OBJECT +public: + MsgReceived(MsgEdit *parent, SIM::Message *msg, bool bOpen); +public slots: + void init(); +protected: + virtual bool processEvent(SIM::Event*); + unsigned m_type; + unsigned m_id; + unsigned m_contact; + QString m_client; + bool m_bOpen; + MsgEdit *m_edit; + SIM::Message *m_msg; +}; + +#endif + diff --git a/plugins/_core/msgsms.cpp b/plugins/_core/msgsms.cpp new file mode 100644 index 0000000..92422ea --- /dev/null +++ b/plugins/_core/msgsms.cpp @@ -0,0 +1,309 @@ +/*************************************************************************** + msgsms.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "msgsms.h" +#include "msgedit.h" +#include "userwnd.h" +#include "core.h" +#include "contacts/contact.h" +#include "simgui/toolbtn.h" +#include "simgui/textshow.h" + +#include + +using namespace SIM; + +const unsigned MAX_SMS_LEN_LATIN1 = 160; +const unsigned MAX_SMS_LEN_UNICODE = 70; + +MsgSMS::MsgSMS(MsgEdit *parent, Message *msg) + : QObject(parent) +{ + m_edit = parent; + m_bExpand = false; + m_bCanSend = false; + if (m_edit->m_edit->isReadOnly()){ + m_edit->m_edit->setText(QString::null); + m_edit->m_edit->setReadOnly(false); + } + QString t = msg->getPlainText(); + if (!t.isEmpty()) + m_edit->m_edit->setText(t); + m_panel = NULL; + Command cmd; + cmd->id = CmdPhoneNumber; + cmd->param = m_edit; + EventCommandWidget eWidget(cmd); + eWidget.process(); + CToolCombo *cmbPhone = qobject_cast(eWidget.widget()); + if (cmbPhone) + connect(cmbPhone->lineEdit(), SIGNAL(textChanged(const QString&)), this, SLOT(textChanged(const QString&))); + connect(m_edit->m_edit, SIGNAL(textChanged()), this, SLOT(textChanged())); + Contact *contact = getContacts()->contact(msg->contact()); + if (contact == NULL) + return; + if (cmbPhone){ + QString phones = contact->getPhones(); + while (phones.length()){ + QString phoneItem = getToken(phones, ';', false); + phoneItem = getToken(phoneItem, '/', false); + QString phone = getToken(phoneItem, ','); + getToken(phoneItem, ','); + if (phoneItem.toUInt() == CELLULAR) + cmbPhone->addItem(phone); + } + t = static_cast(msg)->getPhone(); + if (!t.isEmpty()) + cmbPhone->setText(t); + } + textChanged(); + SIM::PropertyHubPtr data = contact->getUserData("SMS"); + if (contact->getFlags() & CONTACT_TEMP){ + m_panel = new SMSPanel(m_edit); + m_edit->m_layout->insertWidget(0, m_panel); + connect(m_panel, SIGNAL(destroyed()), this, SLOT(panelDestroyed())); + m_panel->show(); + } + if (m_edit->m_edit->toPlainText().isEmpty()){ + EventTemplate::TemplateExpand t; + if (!data->value("SMSSignatureBefore").toString().isEmpty()){ + t.tmpl = data->value("SMSSignatureBefore").toString(); + t.contact = contact; + t.receiver = this; + t.param = NULL; + EventTemplateExpand(&t).process(); + }else{ + m_bExpand = true; + if (!data->value("SMSSignatureAfter").toString().isEmpty()){ + t.tmpl = data->value("SMSSignatureAfter").toString(); + t.contact = contact; + t.receiver = this; + t.param = NULL; + EventTemplateExpand(&t).process(); + } + } + } +} + +MsgSMS::~MsgSMS() +{ + m_edit->m_userWnd->setStatus(QString::null); // Clear "Size: %1 / Max. size: %2" from status line + if (m_panel) + delete m_panel; +} + +void MsgSMS::panelDestroyed() +{ + m_panel = NULL; +} + +void MsgSMS::init() +{ + if (!m_edit->topLevelWidget()->isActiveWindow() || m_edit->topLevelWidget()->isMinimized()) + return; + Command cmd; + cmd->id = CmdPhoneNumber; + cmd->param = m_edit; + EventCommandWidget eWidget(cmd); + eWidget.process(); + CToolCombo *cmbPhone = qobject_cast(eWidget.widget()); + if (cmbPhone && cmbPhone->lineEdit()->text().isEmpty()){ + cmbPhone->setFocus(); + return; + } + m_edit->m_edit->setFocus(); +} + +void MsgSMS::textChanged(const QString&) +{ + textChanged(); +} + +void MsgSMS::textChanged() +{ + QString phone; + QString msgText = m_edit->m_edit->toPlainText(); + Command cmd; + cmd->id = CmdTranslit; + cmd->param = m_edit; + EventCommandWidget eWidget1(cmd); + eWidget1.process(); + CToolButton *btnTranslit = qobject_cast(eWidget1.widget()); + if (btnTranslit && btnTranslit->isChecked()) + msgText = toTranslit(msgText); + cmd->id = CmdPhoneNumber; + cmd->param = m_edit; + EventCommandWidget eWidget2(cmd); + eWidget2.process(); + CToolCombo *cmbPhone = qobject_cast(eWidget2.widget()); + if (cmbPhone) + phone = cmbPhone->lineEdit()->text(); + bool bCanSend = !phone.isEmpty() || !msgText.isEmpty(); + if (bCanSend != m_bCanSend){ + m_bCanSend = bCanSend; + cmd->id = CmdSend; + cmd->flags = m_bCanSend ? 0 : COMMAND_DISABLED; + EventCommandDisabled(cmd).process(); + } + unsigned size = msgText.length(); + unsigned max_size = MAX_SMS_LEN_UNICODE; + if (isLatin(msgText)) + max_size = MAX_SMS_LEN_LATIN1; + QString status = i18n("Size: %1 / Max. size: %2") + .arg(size) .arg(max_size); + if (size > max_size){ + status += " ! "; + status += i18n("Message will be split"); + } + m_edit->m_userWnd->setStatus(status); +} + +bool MsgSMS::processEvent(Event *e) +{ + if (e->type() == eEventCheckCommandState){ + EventCheckCommandState *ecs = static_cast(e); + CommandDef *cmd = ecs->cmd(); + if (cmd->param == m_edit){ + unsigned id = cmd->bar_grp; + if ((id >= MIN_INPUT_BAR_ID) && (id < MAX_INPUT_BAR_ID)){ + cmd->flags |= BTN_HIDE; + if (cmd->id == CmdPhoneNumber) + cmd->flags &= ~BTN_HIDE; + return true; + } + switch (cmd->id){ + case CmdTranslit: + case CmdSmile: + case CmdSend: + case CmdSendClose: + e->process(this); + cmd->flags &= ~BTN_HIDE; + return true; + case CmdNextMessage: + case CmdMsgAnswer: + e->process(this); + cmd->flags |= BTN_HIDE; + return true; + } + } + } else + if (e->type() == eEventTemplateExpanded){ + EventTemplate *et = static_cast(e); + EventTemplate::TemplateExpand *t = et->templateExpand(); + if (m_bExpand){ + m_edit->m_edit->append(t->tmpl); + }else{ + m_edit->m_edit->setText(t->tmpl); + m_edit->m_edit->moveCursor(QTextCursor::End, QTextCursor::MoveAnchor); + m_bExpand = true; + Contact *contact = getContacts()->contact(m_id); + if (contact){ + SIM::PropertyHubPtr data = contact->getUserData("SMS"); + if (!data->value("SMSSignatureAfter").toString().isEmpty()){ + t->tmpl = data->value("SMSSignatureAfter").toString(); + EventTemplateExpand(t).process(); + } + } + } + return true; + } + if (e->type() == eEventCommandExec){ + EventCommandExec *ece = static_cast(e); + CommandDef *cmd = ece->cmd(); + if ((cmd->id == CmdSend) && (cmd->param == m_edit)){ + unsigned flags = 0; + QString msgText = m_edit->m_edit->toPlainText(); + QString phone; + Command c; + c->id = CmdPhoneNumber; + c->param = m_edit; + EventCommandWidget eWidget(c); + eWidget.process(); + CToolCombo *cmbPhone = qobject_cast(eWidget.widget()); + if (cmbPhone) + phone = cmbPhone->lineEdit()->text(); + + if (!msgText.isEmpty() && !phone.isEmpty()){ + SMSMessage *msg = new SMSMessage; + msg->setText(msgText); + msg->setFlags(flags); + msg->setPhone(phone); + msg->setContact(m_edit->m_userWnd->id()); + if (m_edit->sendMessage(msg)){ + Contact *contact = getContacts()->contact(m_edit->m_userWnd->id()); + if (contact){ + if (contact->getFlags() & CONTACT_TEMP){ + contact->setName(phone); + if (m_panel && m_panel->chkSave->isChecked()){ + contact->setFlags(contact->getFlags() & ~CONTACT_TEMP); + delete m_panel; + } + EventContact(contact, EventContact::eChanged).process(); + } + QString newPhones; + QString phones = contact->getPhones(); + QString type = "Private Cellular"; + QString src = "-"; + while (phones.length()){ + QString phoneItem = getToken(phones, ';', false); + QString item = phoneItem; + QString phoneStr = getToken(phoneItem, '/', false); + QString phone = getToken(phoneStr, ','); + QString phoneType = getToken(phoneStr, ','); + if ((phone != msg->getPhone()) || (phoneStr.toUInt() != CELLULAR)){ + if (!newPhones.isEmpty()) + newPhones += ';'; + newPhones += item; + continue; + } + type = phoneType; + src = phoneItem; + } + phone += ','; + phone += type; + phone += ','; + phone += QString::number(CELLULAR); + phone += '/'; + phone += src; + if (!newPhones.isEmpty()) + phone += ';'; + newPhones = phone + newPhones; + QString oldPhones = contact->getPhones(); + contact->setPhones(newPhones); + if (oldPhones != newPhones){ + EventContact(contact, EventContact::eChanged).process(); + } + } + } + } + return true; + } + } + return false; +} + +SMSPanel::SMSPanel(QWidget *parent) + : QFrame(parent) + , lay(new QHBoxLayout(this)) +{ + chkSave = new QCheckBox(i18n("Save phone in contact list"), this); + lay->addSpacing(7); + lay->addWidget(chkSave); +} + +SMSPanel::~SMSPanel() +{} diff --git a/plugins/_core/msgsms.h b/plugins/_core/msgsms.h new file mode 100644 index 0000000..4ae8da9 --- /dev/null +++ b/plugins/_core/msgsms.h @@ -0,0 +1,60 @@ +/*************************************************************************** + msgsms.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _MSGSMS_H +#define _MSGSMS_H + +#include +#include +#include "event.h" + +class QCheckBox; +class MsgEdit; + +class SMSPanel : public QFrame +{ + Q_OBJECT +public: + SMSPanel(QWidget *parent); + ~SMSPanel(); + QCheckBox *chkSave; +private: + QHBoxLayout *lay; +}; + +class MsgSMS : public QObject, public SIM::EventReceiver +{ + Q_OBJECT +public: + MsgSMS(MsgEdit *parent, SIM::Message *msg); + ~MsgSMS(); +protected slots: + void init(); + void textChanged(const QString&); + void textChanged(); + void panelDestroyed(); +protected: + virtual bool processEvent(SIM::Event*); + MsgEdit *m_edit; + SMSPanel *m_panel; + unsigned m_id; + bool m_bExpand; + bool m_bCanSend; +}; + +#endif + diff --git a/plugins/_core/msgurl.cpp b/plugins/_core/msgurl.cpp new file mode 100644 index 0000000..203faf9 --- /dev/null +++ b/plugins/_core/msgurl.cpp @@ -0,0 +1,159 @@ +/*************************************************************************** + msgurl.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "msgurl.h" +#include "msgedit.h" +#include "userwnd.h" +#include "userlist.h" +#include "core.h" + +#include "simgui/toolbtn.h" +#include "simgui/textshow.h" + + +using namespace SIM; + +MsgUrl::MsgUrl(MsgEdit *parent, Message *msg) + : QObject(parent) +{ + m_client = msg->client(); + m_edit = parent; + if (m_edit->m_edit->isReadOnly()){ + m_edit->m_edit->setText(QString::null); + m_edit->m_edit->setReadOnly(false); + } + QString t = msg->getPlainText(); + if (!t.isEmpty()) + m_edit->m_edit->setText(t); + Command cmd; + cmd->id = CmdUrlInput; + cmd->param = m_edit; + EventCommandWidget eWidget(cmd); + eWidget.process(); + CToolEdit *edtUrl = qobject_cast(eWidget.widget()); + if (edtUrl){ + connect(edtUrl, SIGNAL(textChanged(const QString&)), this, SLOT(urlChanged(const QString&))); + edtUrl->setText(static_cast(msg)->getUrl()); + if (edtUrl->text().isEmpty()){ + QString url; + EventGetURL e; + e.process(); + url = e.url(); + if (!url.isEmpty()){ + url = url.mid(1); + int n = url.indexOf('\"'); + if (n > 0){ + QString u = url.left(n); + edtUrl->setText(u); + url = url.mid(n + 1); + n = url.indexOf('\"'); + if (n > 0) + url = url.mid(n + 1); + } + n = url.indexOf('\"'); + if (n > 0){ + url = url.left(n); + m_edit->m_edit->setText(url); + } + } + } + urlChanged(edtUrl->text()); + } +} + +void MsgUrl::init() +{ + if (!m_edit->topLevelWidget()->isActiveWindow() || m_edit->topLevelWidget()->isMinimized()) + return; + Command cmd; + cmd->id = CmdUrlInput; + cmd->param = m_edit; + EventCommandWidget eWidget(cmd); + eWidget.process(); + CToolEdit *edtUrl = qobject_cast(eWidget.widget()); + if (edtUrl && edtUrl->text().isEmpty()){ + edtUrl->setFocus(); + return; + } + m_edit->m_edit->setFocus(); +} + +void MsgUrl::urlChanged(const QString &str) +{ + Command cmd; + cmd->id = CmdSend; + cmd->flags = str.isEmpty() ? COMMAND_DISABLED : 0; + cmd->param = m_edit; + EventCommandDisabled(cmd).process(); +} + +bool MsgUrl::processEvent(Event *e) +{ + if (e->type() == eEventCheckCommandState){ + EventCheckCommandState *ecs = static_cast(e); + CommandDef *cmd = ecs->cmd(); + if (cmd->param == m_edit){ + unsigned id = cmd->bar_grp; + if ((id >= MIN_INPUT_BAR_ID) && (id < MAX_INPUT_BAR_ID)){ + cmd->flags |= BTN_HIDE; + if (cmd->id == CmdUrlInput) + cmd->flags &= ~BTN_HIDE; + return true; + } + switch (cmd->id){ + case CmdTranslit: + case CmdSmile: + case CmdSend: + case CmdSendClose: + e->process(this); + cmd->flags &= ~BTN_HIDE; + return true; + case CmdNextMessage: + case CmdMsgAnswer: + e->process(this); + cmd->flags |= BTN_HIDE; + return true; + } + } + } else + if (e->type() == eEventCommandExec){ + EventCommandExec *ece = static_cast(e); + CommandDef *cmd = ece->cmd(); + if ((cmd->id == CmdSend) && (cmd->param == m_edit)){ + QString msgText = m_edit->m_edit->toPlainText(); + QString urlText; + Command cmd; + cmd->id = CmdUrlInput; + cmd->param = m_edit; + EventCommandWidget eWidget(cmd); + eWidget.process(); + CToolEdit *edtUrl = qobject_cast(eWidget.widget()); + if (edtUrl) + urlText = edtUrl->text(); + if (!urlText.isEmpty()){ + UrlMessage *msg = new UrlMessage; + msg->setContact(m_edit->m_userWnd->id()); + msg->setText(msgText); + msg->setUrl(urlText); + msg->setClient(m_client); + m_edit->sendMessage(msg); + } + return true; + } + } + return false; +} diff --git a/plugins/_core/msgurl.h b/plugins/_core/msgurl.h new file mode 100644 index 0000000..305f67d --- /dev/null +++ b/plugins/_core/msgurl.h @@ -0,0 +1,43 @@ +/*************************************************************************** + msgurl.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _MSGURL_H +#define _MSGURL_H + +#include +#include + +#include "event.h" + +class MsgEdit; + +class MsgUrl : public QObject, public SIM::EventReceiver +{ + Q_OBJECT +public: + MsgUrl(MsgEdit *parent, SIM::Message *msg); +protected slots: + void init(); + void urlChanged(const QString&); +protected: + virtual bool processEvent(SIM::Event*); + QString m_client; + MsgEdit *m_edit; +}; + +#endif + diff --git a/plugins/_core/msgview.cpp b/plugins/_core/msgview.cpp new file mode 100644 index 0000000..50fb3fd --- /dev/null +++ b/plugins/_core/msgview.cpp @@ -0,0 +1,1466 @@ +/*************************************************************************** + msgview.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "simapi.h" + +#include "icons.h" +#include "html.h" +#include "unquot.h" +#include "xsl.h" +#include "contacts/clientdataiterator.h" +#include "contacts/contact.h" +#include "contacts/client.h" + +#include "msgview.h" +#include "core.h" +#include "history.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace SIM; + +static char MSG_ANCHOR[] = ""; + +class ViewParser : public HTMLParser +{ +public: + ViewParser(bool bIgnoreColors, bool bUseSmiles); + QString parse(const QString &str); +protected: + QString res; + bool m_bIgnoreColors; + bool m_bUseSmiles; + bool m_bInLink; + bool m_bInHead; + bool m_bInParagraph; + bool m_bParagraphEmpty; + bool m_bFirst; + bool m_bSpan; + // Marks the position in 'res' where " DIR=\"whatever\"" should be inserted, + // if the paragraph is DIR-less and we determine the DIR later on. + unsigned m_paraDirInsertionPos; + enum { + DirAuto, // Initial BiDi dir when not explicitly specified. + // Real dir will be determined from the first + // strong BiDi character. + DirLTR, + DirRTL, + DirUnknown + } m_paragraphDir; + virtual void text(const QString &text); + virtual void tag_start(const QString &tag, const list &options); + virtual void tag_end(const QString &tag); +}; + +/* + This parser is run on the output of the 'history XSL'. + The text which the XSL process output should generally be HTML, + but may contain the following special tags: + + ... + Strips the PREPEND tags and prepends their contents to the beginning + of the next paragraph. Useful to make sure chat prefixes are prepended + to the first paragraph of a multi-paragraph message (instead of residing + on a new paragraph). +*/ + +class XslOutputParser : public HTMLParser +{ +public: + XslOutputParser(); + QString parse(const QString &str); + +protected: + virtual void text(const QString &text); + virtual void tag_start(const QString &tag, const list &options); + virtual void tag_end(const QString &tag); + +protected: + QString res; + bool m_bInPrepend; + QString m_sPrepend; +}; + +XslOutputParser::XslOutputParser() + : m_bInPrepend(false) +{ +} + +QString XslOutputParser::parse(const QString &str) +{ + res = QString::null; + HTMLParser::parse(str); + if (!m_sPrepend.isEmpty()) + res = m_sPrepend + res; + return res; +} + +void XslOutputParser::text(const QString& text) +{ + if (m_bInPrepend) + m_sPrepend += quoteString(text); + else + res += quoteString(text); +} + +void XslOutputParser::tag_start(const QString &tag, const list &attrs) +{ + QString ltag = tag.toLower(); + + if (ltag == "prepend") + { + m_bInPrepend = true; + return; + } + + QString tagText; + tagText += '<'; + tagText += tag; + for (list::const_iterator it = attrs.begin(); it != attrs.end(); ++it){ + QString name = *it; + ++it; + QString value = *it; + tagText += ' '; + tagText += name; + if (!value.isEmpty()){ + tagText += "=\""; + tagText += value; + tagText += '\"'; + } + } + tagText += '>'; + + if (m_bInPrepend) + { + m_sPrepend += tagText; + } + else + { + res += tagText; + + // It's time to prepend whatever we've got in m_sPrepend + // to the start of a paragraph. + if ((ltag == "p") && !m_sPrepend.isEmpty()) + { + res += m_sPrepend; + m_sPrepend = QString::null; + } + } +} + +void XslOutputParser::tag_end(const QString &tag) +{ + QString ltag = tag.toLower(); + + if (ltag == "prepend") + { + m_bInPrepend = false; + return; + } + + QString tagText; + tagText += "'; + + if (m_bInPrepend) + m_sPrepend += tagText; + else + res += tagText; +} + +MsgViewBase::MsgViewBase(QWidget *parent, const char *name, unsigned id) + : TextShow (parent, name) + , m_id (id) + , m_popupPos (QPoint(0, 0)) + , m_nSelection (0) + , xsl (NULL) +{ + // Disable top and bottom margins for P tags. This will make sure + // paragraphs have no more spacing than regular lines, thus matching + // RTF's defaut look for paragraphs. + document()->setDefaultStyleSheet("p { margin-top: 0; margin-bottom: 0; }"); + + setColors(); + setFont(CorePlugin::instance()->editFont); + setContextMenuPolicy( Qt::DefaultContextMenu ); +} + +MsgViewBase::~MsgViewBase() +{ + if (xsl) + delete xsl; +} + +void MsgViewBase::setXSL(XSL *n_xsl) +{ + if (xsl) + delete xsl; + xsl = n_xsl; +} + +void MsgViewBase::setSelect(const QString &str) +{ + m_nSelection = 0; + m_selectStr = str; +} + +void MsgViewBase::update() +{ + if (m_updated.empty()) + return; +/* + unsigned i; + for (i = 0; i < (unsigned)paragraphs(); i++){ + QString s = text(i); + int n = s.indexOf(MSG_ANCHOR); + if (n < 0) + continue; + s = s.mid(n + strlen(MSG_ANCHOR)); + n = s.indexOf('\"'); + if (n < 0) + continue; + QString client; + unsigned id = messageId(s.left(n), client); + list::iterator it; + for (it = m_updated.begin(); it != m_updated.end(); ++it){ + if ((it->id == id) && (it->client == client)) + break; + } + if (it != m_updated.end()) + break; + } + m_updated.clear(); + if (i >= (unsigned)paragraphs()) + return; + int x = contentsX(); + int y = contentsY(); + viewport()->setUpdatesEnabled(false); + + unsigned start = i; + list msgs; + for (; i < (unsigned)paragraphs(); i++){ + QString s = text(i); + int n = s.indexOf(MSG_ANCHOR); + if (n < 0) + continue; + s = s.mid(n + strlen(MSG_ANCHOR)); + n = s.indexOf('\"'); + if (n < 0) + continue; + QString client; + unsigned id = messageId(s.left(n), client); + list::iterator it; + for (it = msgs.begin(); it != msgs.end(); ++it){ + if ((it->id == id) && (it->client == client)) + break; + } + if (it != msgs.end()) + continue; + Msg_Id m_id; + m_id.id = id; + m_id.client = client; + msgs.push_back(m_id); + } + int paraFrom, indexFrom; + int paraTo, indexTo; + getSelection(¶From, &indexFrom, ¶To, &indexTo); + setReadOnly(false); + setSelection(start, 0, paragraphs() - 1, 0xFFFF, 0); + removeSelectedText(); + setReadOnly(true); + QString text; + for (list::iterator it = msgs.begin(); it != msgs.end(); ++it){ + Message *msg = History::load(it->id, it->client, m_id); + if (msg == NULL) + continue; + bool bUnread = false; + for (list::iterator itu = CorePlugin::instance()->unread.begin(); itu != CorePlugin::instance()->unread.end(); ++itu){ + msg_id &m = (*itu); + if ((m.contact == msg->contact()) && + (m.id == msg->id()) && + (m.client == msg->client())){ + bUnread = true; + break; + } + } + text += messageText(msg, bUnread); + delete msg; + } + viewport()->setUpdatesEnabled(true); + append(text); //<= here occurred a crash + if (!CorePlugin::instance()->getOwnColors()) + setBackground(i); + if ((paraFrom != paraTo) || (indexFrom != indexTo)) + setSelection(paraFrom, indexFrom, paraTo, indexTo, 0); + TextShow::sync(); + setContentsPos(x, y); + viewport()->repaint(); +*/ +} + +//ToDo: Rewrite this ugly slow Function which is slowing down the History loading. +QString MsgViewBase::messageText(Message *msg, bool bUnread) +{ + QString options; + QString info; + QString status; + + QString icon = "message"; + const CommandDef *def = CorePlugin::instance()->messageTypes.find(msg->type()); + if (def) + icon = def->icon; + bool bDirection = false; + if (msg->type() == MessageStatus){ + icon = "empty"; + StatusMessage *sm = static_cast(msg); + Client *client = NULL; + QString clientStr = msg->client(); + int n = clientStr.lastIndexOf('.'); + if (n >= 0){ + clientStr = clientStr.left(n); + }else{ + clientStr.clear(); + } + if (!clientStr.isEmpty()){ + for (unsigned i = 0; i < getContacts()->nClients(); i++){ + QString n = getContacts()->getClient(i)->name(); + if (n.startsWith(clientStr)){ + client = getContacts()->getClient(i); + break; + } + } + } + if ((client == NULL) && getContacts()->nClients()) + client = getContacts()->getClient(0); + if(client) { + for (def = client->protocol()->statusList(); !def->text.isEmpty(); def++){ + if (def->id == sm->getStatus()){ + icon = def->icon; + status = i18n(def->text); + break; + } + } + } + options += " direction=\"2\""; + bDirection = true; + }else{ + MessageDef *m_def = (MessageDef*)(def->param); + if (m_def->flags & MESSAGE_INFO){ + options += " direction=\"2\""; + bDirection = true; + } + } + info = QString("%1") .arg(icon); + + QString contactName; + if (msg->getFlags() & MESSAGE_RECEIVED){ + if (!bDirection) + options += " direction=\"1\""; + Contact *contact = getContacts()->contact(msg->contact()); + if (contact){ + contactName = contact->getName(); + if (contactName.isEmpty()){ + Client *client = NULL; + ClientDataIterator it(contact->clientData); + void *data; + while ((data = ++it) != NULL){ + if (it.client()->dataName(data) == msg->client()){ + client = it.client(); + break; + } + } + } + } + if (!bUnread){ + for (list::iterator it = CorePlugin::instance()->unread.begin(); it != CorePlugin::instance()->unread.end(); ++it){ + msg_id &m = (*it); + if ((m.id == msg->id()) && + (m.contact == msg->contact()) && + (m.client == msg->client())){ + bUnread = true; + break; + } + } + } + if (bUnread) + options += " unread=\"1\""; + }else{ + if (!bDirection) + options += " direction=\"0\""; + contactName = getContacts()->owner()->getName(); + } + if (contactName.isEmpty()) + contactName = "???"; + info += QString("%1") .arg(quoteString(contactName)); + QString id = QString::number(msg->id()); + id += ','; + // + // Terrible hack to set message bgcolor. We prefer to insert the entire history + // in one chunk (since it's more efficient and causes less redraws), and there's + // no way to set block's background color directly in Qt's HTML), so we make a note + // of it in the HTML and set it retroactively in setBackground. + if (!CorePlugin::instance()->value("OwnColors").toBool() && (msg->getBackground() != 0xFFFFFFFF) && (msg->getForeground() != msg->getBackground())) + id += QString::number(msg->getBackground()); + // + QString client_str = msg->client(); + if (!client_str.isEmpty()){ + id += ','; + id += quoteString(client_str); + } + if (m_cut.size()){ + id += ','; + id += QString::number(m_cut.size()); + } + info += ""; + info += id; + info += ""; + + + QString icons; + if (msg->getFlags() & MESSAGE_SECURE) + options += " encrypted=\"1\""; + if (msg->getFlags() & MESSAGE_URGENT) + options += " urgent=\"1\""; + if (msg->getFlags() & MESSAGE_LIST) + options += " list=\"1\""; + + QString s; + QDateTime t; + t.setTime_t(msg->getTime()); + info += s.sprintf("", + t.time().hour(), t.time().minute(), t.time().second()) .arg(formatDate(QDateTime::fromTime_t(msg->getTime()).date())); + + s = "type() != MessageStatus){ + msgText = msg->presentation(); + if (msgText.isEmpty()){ + unsigned type = msg->baseType(); + CommandDef *cmd = CorePlugin::instance()->messageTypes.find(type); + if (cmd){ + MessageDef *def = (MessageDef*)(cmd->param); + msgText = i18n(def->singular, def->plural, 1); + int n = msgText.indexOf("1 "); + if (n == 0){ + msgText = msgText.mid(2); + }else if (n > 0){ + msgText = msgText.left(n); + } + msgText = QString("

") + msgText + "

"; + } + QString text = msg->getRichText(); + msgText += text; + } + }else{ + msgText = status; + } + EventAddHyperlinks e(msgText); + e.process(); + ViewParser parser(CorePlugin::instance()->value("OwnColors").toBool(), CorePlugin::instance()->value("UseSmiles").toBool()); + msgText = parser.parse(e.text()); + s += "value("OwnColors").toBool() && (msg->getForeground() != 0xFFFFFFFF) && (msg->getForeground() != msg->getBackground())) + { + s += " fgcolor=\"#"; + s += QString::number(msg->getForeground(), 16).rightJustified(6, '0'); + s += '\"'; + } + + // Some bright day might come when one could specify background color from inside Qt's richtext. + // Meanwhile, this is useless: + if ((msg->getBackground() != 0xFFFFFFFF) && (msg->getForeground() != msg->getBackground())) + { + s += " bgcolor=\"#"; + s += QString::number(msg->getBackground(), 16).rightJustified(6, '0'); + s += '\"'; + } + s += '>'; + + // We pass the rich text quoted, since we're not sure of its' XML validity. + // The XSL engine should copy it as-is (using xsl:value-of with disable-output-escaping="yes"). + s += quoteString(QString(MSG_BEGIN) + msgText); + + s += ""; + s += ""; + XSL *p = xsl; + if (p == NULL) + p = CorePlugin::instance()->historyXSL; + QString res = p->process(s); + + XslOutputParser outParser; + res = outParser.parse(res); + + QString anchor = MSG_ANCHOR; + anchor += id; + anchor += "\"/>"; + res = "

" + anchor + res + "

"; + return res; +} + +void MsgViewBase::setSource(const QUrl& url) +{ + setSource(url.toString()); +} + +void MsgViewBase::setSource(const QString &url) +{ + QString proto; + int n = url.indexOf(':'); + if (n >= 0) + proto = url.left(n); + if (proto != "msg"){ + TextShow::setSource(url); + return; + } + QString id = url.mid(proto.length() + 3); + unsigned msg_id = getToken(id, ',').toULong(); + getToken(id, ','); + id = getToken(id, '/'); + QString client = SIM::unquoteString(id); + if (client.isEmpty()) + client = QString::number(m_id); + Message *msg = History::load(msg_id, client, m_id); + if (msg){ + EventOpenMessage(msg).process(); + delete msg; + } +} + +// +// We have to use this function since Qt has no tag to set background color per-paragraph +// from within HTML. See matching hack in MsgViewBase::messageText. +void MsgViewBase::setBackground(unsigned /*n*/) +{ +/* + QColor bgcolor; + bool bInMsg = false; + bool bSet = false; + + QString sAnchor = QString::fromLatin1(MSG_ANCHOR), + sBegin = QString::fromLatin1(MSG_BEGIN); + + int i; + for (i = n; i >= 0; i--){ + QString s = text(i); + if (s.indexOf(sAnchor) >= 0) + break; + } + for (; i < paragraphs(); i++){ + QString s = text(i); + int anchorPos = s.indexOf(sAnchor); + if (anchorPos >= 0) + { + bInMsg = false; + bSet = false; + + // This code could be a bit faster by making assumptions. + // However, I prefer to be correct HTML-parser-wise. + + int idStart = anchorPos + sAnchor.length(); + int idEnd = s.indexOf('\"', idStart); + if ((idStart >= 0) && (idEnd >= 0)) + { + QString id = s.mid(idStart, idEnd - idStart); + + // Parse the message id (msgId,backgroundColor,...) + int bgcolorStart = id.indexOf(','); + if (bgcolorStart >= 0) + { + QString sBgcolor = id.mid(bgcolorStart + 1); + int bgcolorEnd = sBgcolor.indexOf(','); + if (bgcolorEnd > 0) + sBgcolor = sBgcolor.left(bgcolorEnd); + if (!sBgcolor.isEmpty()) + bgcolor = QColor(sBgcolor.toULong(&bSet)); + } + } + } + if (s.indexOf(sBegin) >= 0) + bInMsg = true; + + if (bInMsg && bSet){ + setParagraphBackgroundColor(i, bgcolor); + }else{ + clearParagraphBackground(i); + } + } +*/ +} +// + +void MsgViewBase::addMessage(Message *msg, bool bUnread, bool /*bSync*/) +{ + unsigned n = document()->blockCount(); + if (n > 0) + n--; + append(messageText(msg, bUnread)); + if (!CorePlugin::instance()->value("OwnColors").toBool()) + setBackground(n); +} + +bool MsgViewBase::findMessage(Message *msg) +{ + QTextBlock block = document()->firstBlock(); + while( block.isValid() ) { + QTextCursor cursor( block ); + cursor.select( QTextCursor::BlockUnderCursor ); + QTextDocumentFragment fragment( cursor ); + QString s = fragment.toHtml(); + int n = s.indexOf(MSG_ANCHOR); + if (n >= 0) { + s = s.mid(n + strlen(MSG_ANCHOR)); + n = s.indexOf('\"'); + if (n >= 0) { + QString client; + if ((messageId(s.left(n), client) == msg->id()) && (client == msg->client())) { + return true; + } + } + } + block = block.next(); + } + + return false; +} + +void MsgViewBase::setColors() +{ + TextShow::setBackground(CorePlugin::instance()->value("EditBackground").toUInt()); + TextShow::setForeground(CorePlugin::instance()->value("EditForeground").toUInt()); +} + +unsigned MsgViewBase::messageId(const QString &_s, QString &client) +{ + QString s(_s); + unsigned id = getToken(s, ',').toULong(); + getToken(s, ','); + client = getToken(s, ','); + if (id >= 0x80000000) + return id; + for (unsigned cut_id = s.toUInt(); cut_id < m_cut.size(); cut_id++){ + if (m_cut[cut_id].client != client) + continue; + if (id < m_cut[cut_id].from) + continue; + id -= m_cut[cut_id].size; + } + return id; +} + +void MsgViewBase::reload() +{ +/* + QString t; + vector msgs; + unsigned i; + for (i = 0; i < (unsigned)paragraphs(); i++){ + QString s = text(i); + int n = s.indexOf(MSG_ANCHOR); + if (n < 0) + continue; + s = s.mid(n + strlen(MSG_ANCHOR)); + n = s.indexOf('\"'); + if (n < 0) + continue; + Msg_Id id; + id.id = messageId(s.left(n), id.client); + unsigned nn; + for (nn = 0; nn < msgs.size(); nn++){ + if ((msgs[nn].id == id.id) && (msgs[nn].client == id.client)) + break; + } + if (nn >= msgs.size()) + msgs.push_back(id); + } + for (i = 0; i < msgs.size(); i++){ + Message *msg = History::load(msgs[i].id, msgs[i].client, m_id); + if (msg == NULL) + continue; + t += messageText(msg, false); + delete msg; + } + QPoint p = QPoint(0, height()); + p = mapToGlobal(p); + p = viewport()->mapFromGlobal(p); + int x, y; + viewportToContents(p.x(), p.y(), x, y); + int para; + int pos = charAt(QPoint(x, y), ¶); + setText(t); + if (!CorePlugin::instance()->getOwnColors()) + setBackground(0); + if (pos == -1){ + scrollToBottom(); + }else{ + setCursorPosition(para, pos); + ensureCursorVisible(); + } +*/ +} + +bool MsgViewBase::processEvent(Event *e) +{ + if ((e->type() == eEventRewriteMessage) || (e->type() == eEventMessageRead)){ + /* + EventMessage *em = static_cast(e); + Message *msg = em->msg(); + if (msg->contact() != m_id) + return false; + unsigned i; + for (i = 0; i < (unsigned)paragraphs(); i++){ + QString s = text(i); + int n = s.indexOf(MSG_ANCHOR); + if (n < 0) + continue; + s = s.mid(n + strlen(MSG_ANCHOR)); + n = s.indexOf('\"'); + if (n < 0) + continue; + QString client; + if ((messageId(s.left(n), client) == msg->id()) && (client == msg->client())) + break; + } + if (i >= (unsigned)paragraphs()) + return false; + Msg_Id id; + id.id = msg->id(); + id.client = msg->client(); + m_updated.push_back(id); + QTimer::singleShot(0, this, SLOT(update())); + */ + return false; + } + if (e->type() == eEventCutHistory){ + /* + EventCutHistory *ech = static_cast(e); + CutHistory *ch = ech->cut(); + if (ch->contact != m_id) + return false; + + bool bDelete = false; + vector start_pos; + vector end_pos; + for (unsigned i = 0; i < (unsigned)paragraphs(); i++){ + QString s = text(i); + int n = s.indexOf(MSG_ANCHOR); + if (n < 0) + continue; + s = s.mid(n + strlen(MSG_ANCHOR)); + n = s.indexOf('\"'); + if (n < 0) + continue; + QString client; + unsigned id = messageId(s.left(n), client); + if ((client == ch->client) && (id >= ch->from) && (id < ch->from + ch->size)){ + if (!bDelete){ + bDelete = true; + start_pos.push_back(i); + } + }else{ + if (bDelete){ + bDelete = false; + end_pos.push_back(i); + } + } + } + if (bDelete) + end_pos.push_back(paragraphs()); + if (start_pos.size()){ + int paraFrom, indexFrom; + int paraTo, indexTo; + getSelection(¶From, &indexFrom, ¶To, &indexTo); + QPoint p = QPoint(0, 0); + p = mapToGlobal(p); + p = viewport()->mapFromGlobal(p); + int x, y; + viewportToContents(p.x(), p.y(), x, y); + int para; + int pos = charAt(QPoint(x, y), ¶); + setReadOnly(false); + for (unsigned i = 0; i < start_pos.size(); i++){ + setSelection(start_pos[i], 0, end_pos[i], 0, 0); + removeSelectedText(); + if ((unsigned)pos >= start_pos[i]) + pos = end_pos[i] - start_pos[i]; + } + if ((paraFrom == -1) && (paraTo == -1)){ + if (pos == -1){ + scrollToBottom(); + }else{ + setCursorPosition(para, pos); + ensureCursorVisible(); + } + }else{ + setSelection(paraFrom, indexFrom, paraTo, indexTo, 0); + } + setReadOnly(true); + repaint(); + } + m_cut.push_back(*ch); + */ + return false; + } + if (e->type() == eEventMessageDeleted){ + EventMessage *em = static_cast(e); + Message *msg = em->msg(); + if (msg->contact() != m_id) + return false; + /* + for (unsigned i = 0; i < (unsigned)paragraphs(); i++){ + unsigned j; + QString s = text(i); + int n = s.indexOf(MSG_ANCHOR); + if (n < 0) + continue; + s = s.mid(n + strlen(MSG_ANCHOR)); + n = s.indexOf('\"'); + if (n < 0) + continue; + QString client; + if ((messageId(s.left(n), client) != msg->id()) || (client != msg->client())) + continue; + + for (j = i + 1; j < (unsigned)paragraphs(); j++){ + QString s = text(j); + int n = s.indexOf(MSG_ANCHOR); + if (n < 0) + continue; + s = s.mid(n + strlen(MSG_ANCHOR)); + n = s.indexOf('\"'); + if (n < 0) + continue; + QString client; + if ((messageId(s.left(n), client) != msg->id()) || (client != msg->client())) + break; + } + int paraFrom, indexFrom; + int paraTo, indexTo; + getSelection(¶From, &indexFrom, ¶To, &indexTo); + unsigned pos = 0xFFFF; + if (j == (unsigned)paragraphs()){ + j++; + pos = 0; + } + setSelection(i, 0, j - 1, pos, 0); + setReadOnly(false); + removeSelectedText(); + setReadOnly(true); + if ((paraFrom == -1) && (paraTo == -1)){ + scrollToBottom(); + }else{ + setSelection(paraFrom, indexFrom, paraTo, indexTo, 0); + } + break; + } + */ + return false; + } + if (e->type() == eEventHistoryConfig){ + EventHistoryConfig *ehc = static_cast(e); + unsigned long id = ehc->id(); + if (id && (id != m_id)) + return false; + reload(); + } else + if (e->type() == eEventHistoryColors) { + setColors(); + } else + if (e->type() == eEventCheckCommandState){ + EventCheckCommandState *ecs = static_cast(e); + CommandDef *cmd = ecs->cmd(); + if ((cmd->param != this) || (cmd->menu_id != MenuMsgView)) + return false; + Message *msg; + switch (cmd->id){ + case CmdCopy: + cmd->flags &= ~(COMMAND_DISABLED | COMMAND_CHECKED); + if (!textCursor().hasSelection()) + cmd->flags |= COMMAND_DISABLED; + return true; + case CmdMsgOpen: + msg = currentMessage(); + if (msg){ + unsigned type = msg->baseType(); + delete msg; + CommandDef *def = CorePlugin::instance()->messageTypes.find(type); + if (def == NULL) + return false; + cmd->icon = def->icon; + cmd->flags &= ~COMMAND_CHECKED; + return true; + } + return false; + case CmdMsgSpecial: + msg = currentMessage(); + if (msg){ + EventMenuGetDef eMenu(MenuMsgCommand); + eMenu.process(); + CommandsDef *cmdsMsg = eMenu.defs(); + + unsigned n = 0; + MessageDef *mdef = NULL; + unsigned type = msg->baseType(); + const CommandDef *cmdsSpecial = NULL; + CommandDef *msgCmd = CorePlugin::instance()->messageTypes.find(type); + if (msgCmd) + mdef = (MessageDef*)(msgCmd->param); + + if (mdef){ + if (msg->getFlags() & MESSAGE_RECEIVED){ + cmdsSpecial = mdef->cmdReceived; + }else{ + cmdsSpecial = mdef->cmdSent; + } + if (cmdsSpecial) + for (const CommandDef *d = cmdsSpecial; !d->text.isEmpty(); d++) + n++; + } + + { + CommandsList it(*cmdsMsg, true); + while (++it) + n++; + } + if (n == 0) + return false; + + n++; + CommandDef *cmds = new CommandDef[n]; + n = 0; + if (cmdsSpecial){ + for (const CommandDef *d = cmdsSpecial; !d->text.isEmpty(); d++){ + cmds[n] = *d; + cmds[n].id = CmdMsgSpecial + n; + cmds[n].flags = COMMAND_DEFAULT; + n++; + } + } + CommandDef *c; + CommandsList it(*cmdsMsg, true); + while ((c = ++it) != NULL){ + CommandDef cmd = *c; + cmd.menu_id = MenuMsgCommand; + cmd.param = msg; + if (!EventCheckCommandState(&cmd).process()) + continue; + cmd.flags &= ~COMMAND_CHECK_STATE; + cmds[n++] = cmd; + } + cmd->param = cmds; + cmd->flags |= COMMAND_RECURSIVE; + delete msg; + return true; + } + return false; + } + } else + if (e->type() == eEventCommandExec){ + EventCommandExec *ece = static_cast(e); + CommandDef *cmd = ece->cmd(); + if ((cmd->param != this) || (cmd->menu_id != MenuMsgView)) + return false; + Message *msg; + switch (cmd->id){ + case CmdCutHistory: + msg = currentMessage(); + if (msg){ + History::cut(msg, 0, 0); + delete msg; + return true; + } + return false; + case CmdDeleteMessage: + msg = currentMessage(); + if (msg){ + History::del(msg); + delete msg; + return true; + } + return false; + case CmdCopy: + copy(); + return true; + case CmdMsgOpen: + msg = currentMessage(); + if (msg){ + msg->setFlags(msg->getFlags() | MESSAGE_OPEN); + EventOpenMessage(msg).process(); + delete msg; + return true; + } + return false; + default: + msg = currentMessage(); + if (msg){ + if (cmd->id >= CmdMsgSpecial){ + MessageDef *mdef = NULL; + unsigned type = msg->baseType(); + CommandDef *msgCmd = CorePlugin::instance()->messageTypes.find(type); + if (msgCmd) + mdef = (MessageDef*)(msgCmd->param); + const CommandDef *cmds = NULL; + if (mdef){ + if (msg->getFlags() & MESSAGE_RECEIVED){ + cmds = mdef->cmdReceived; + }else{ + cmds = mdef->cmdSent; + } + } + + if (cmds){ + unsigned n = cmd->id - CmdMsgSpecial; + for (const CommandDef *d = cmds; !d->text.isEmpty(); d++){ + if (n-- == 0){ + CommandDef cmd = *d; + cmd.param = msg; + cmd.menu_id = 0; + EventCommandExec(&cmd).process(); + return true; + } + } + } + } + Command c; + c->id = cmd->id; + c->menu_id = MenuMsgCommand; + c->param = msg; + EventCommandExec e(c); + bool res = e.process(); + delete msg; + return res; + } + return false; + } + } + return false; +} + +Message *MsgViewBase::currentMessage() +{ + QTextCursor cursor = cursorForPosition( m_popupPos ); + QTextBlock block = cursor.block(); + if( !block.isValid() ) + return NULL; + while( block.isValid() ) { + QTextCursor cursor( block ); + cursor.select( QTextCursor::BlockUnderCursor ); + QTextDocumentFragment fragment( cursor ); + QString s = fragment.toHtml(); + int n = s.indexOf(MSG_ANCHOR); + if (n >= 0) { + s = s.mid(n + strlen(MSG_ANCHOR)); + n = s.indexOf('\"'); + if (n >= 0) { + QString client; + unsigned id = messageId(s.left(n), client); + Message *msg = History::load(id, client, m_id); + if (msg) + return msg; + } + } + block = block.previous(); + } + return NULL; +} + +void MsgViewBase::contextMenuEvent( QContextMenuEvent *event ) +{ + m_popupPos = event->pos(); + Command cmd; + cmd->popup_id = MenuMsgView; + cmd->param = this; + cmd->flags = COMMAND_NEW_POPUP; + EventMenuGet e(cmd); + e.process(); + QMenu *pMenu = e.menu(); + pMenu->exec( event->globalPos() ); + delete pMenu; +} + +MsgView::MsgView(QWidget *parent, unsigned id) + : MsgViewBase(parent, NULL, id) +{ + int nCopy = CorePlugin::instance()->value("CopyMessages").toUInt(); + unsigned nUnread = 0; + for (list::iterator it = CorePlugin::instance()->unread.begin(); it != CorePlugin::instance()->unread.end(); ++it){ + msg_id &m = (*it); + if (m.contact == m_id) + nUnread++; + } + if (nCopy || nUnread){ + QString t = toHtml(); + HistoryIterator it(m_id); + it.end(); + while ((nCopy > 0) || nUnread){ + Message *msg = --it; + if (msg == NULL) + break; + t = messageText(msg, false) + t; + nCopy--; + if (nUnread == 0) + continue; + for (list::iterator it = CorePlugin::instance()->unread.begin(); it != CorePlugin::instance()->unread.end(); ++it){ + msg_id &m = (*it); + if ((m.contact == msg->contact()) && + (m.id == msg->id()) && + (m.client == msg->client())){ + nUnread--; + break; + } + } + } + setHtml(t); + if (!CorePlugin::instance()->value("OwnColors").toBool()) + setBackground(0); + } + QScrollBar *sbar = verticalScrollBar(); + if( NULL != sbar ) { + sbar->setValue( sbar->maximum() ); + } + QTimer::singleShot(0, this, SLOT(init())); +} + +MsgView::~MsgView() +{ +} + +void MsgView::init() +{ + QScrollBar *sbar = verticalScrollBar(); + if( NULL != sbar ) { + sbar->setValue( sbar->maximum() ); + } +} + +bool MsgView::processEvent(Event *e) +{ + if ((e->type() == eEventSent) || (e->type() == eEventMessageReceived)){ + EventMessage *em = static_cast(e); + Message *msg = em->msg(); + if (msg->contact() != m_id) + return false; + if (msg->getFlags() & MESSAGE_NOVIEW) + return false; + bool bAdd = true; + if (msg->type() == MessageStatus){ + bAdd = false; + Contact *contact = getContacts()->contact(msg->contact()); + if (contact){ + SIM::PropertyHubPtr data = contact->getUserData("_core"); + if (!data.isNull() && data->value("LogStatus").toBool() != NEW_MSG_NOOPEN) + bAdd = true; + } + } + if (bAdd && (e->type() == eEventMessageReceived)){ + Contact *contact = getContacts()->contact(msg->contact()); + if (contact){ + SIM::PropertyHubPtr data = contact->getUserData("_core", true); + if (data->value("OpenNewMessage").toUInt() != NEW_MSG_NOOPEN) + bAdd = false; + } + } + if (bAdd){ + addMessage(msg); + if (!textCursor().hasSelection()) { + QScrollBar *sbar = verticalScrollBar(); + if( NULL != sbar ) { + sbar->setValue( sbar->maximum() ); + } + } + } + } + return MsgViewBase::processEvent(e); +} + +ViewParser::ViewParser(bool bIgnoreColors, bool bUseSmiles) +{ + m_bIgnoreColors = bIgnoreColors; + m_bUseSmiles = bUseSmiles; + m_bInLink = false; + m_bInHead = false; + m_bInParagraph = false; + m_bParagraphEmpty = true; + m_bFirst = true; + m_bSpan = false; +} + +QString ViewParser::parse(const QString &str) +{ + res = QString::null; + HTMLParser::parse(str); + return res; +} + +void ViewParser::text(const QString &text) +{ + if (text.isEmpty()) + return; + + if (m_bInParagraph) + m_bParagraphEmpty = false; + + if (m_bInParagraph && (m_paragraphDir == DirAuto)) + { + /* text isn't (unicode)-NULL terminated so we can't check for c->isNull! */ + for(unsigned int i = 0; ((i < (unsigned)text.length()) && (m_paragraphDir == DirAuto)); i++) + { + const QChar c = text.unicode()[i]; + // Note: Qt expects ltr/rtl to be lower-case. + switch(c.direction()) + { + case QChar::DirL: + res.insert(m_paraDirInsertionPos, " dir=\"ltr\""); + m_paragraphDir = DirLTR; + break; + case QChar::DirR: + res.insert(m_paraDirInsertionPos, " dir=\"rtl\""); + m_paragraphDir = DirRTL; + break; + default: // avoid gcc warning + break; + } + } + } + + if (!m_bUseSmiles || m_bInLink){ + res += quoteString(text); + return; + } + m_bFirst = false; + if (m_bUseSmiles){ + QString r = getIcons()->parseSmiles(text); + res += r; + }else{ + res += quoteString(text); + } +} + +static const char *def_smiles[] = + { + ":-)", + ":-0", + ":-|", + ":-/", + ":-(", + ":-{}", + ":*)", + ":'-(", + ";-)", + ":-@", + ":-\")", + ":-X", + ":-P", + "8-)", + "O:-)", + ":-D", + "*ANNOYED*", + "*DISGUSTED*", + "*DROOLING*", + "*GIGGLING*", + "*JOKINGLY*", + "*SHOCKED*", + "*WHINING*", + "*SURPRISED*", + "*SURPRISED*", + "*IN LOVE*" + }; + +void ViewParser::tag_start(const QString &tag, const list &attrs) +{ + // the tag that will be actually written out + QString oTag = tag; + + if (m_bInHead) + return; + + QString style; + + if (tag == "img"){ + QString src; + for (list::const_iterator it = attrs.begin(); it != attrs.end(); ++it){ + QString name = it->toLower(); + ++it; + QString value = *it; + if (name == "src"){ + src = value; + break; + } + } + if (src.startsWith("icon:smile")){ + bool bOK; + unsigned nSmile = src.mid(10).toUInt(&bOK, 16); + if (bOK && (nSmile < 26)){ + QString s = def_smiles[nSmile]; + res += getIcons()->parseSmiles(s); + return; + } + } + }else if (tag == "a"){ + m_bInLink = true; + }else if (tag == "p"){ + m_bInParagraph = true; + m_paragraphDir = DirAuto; + m_bParagraphEmpty = true; + }else if (tag == "html"){ // we display as a part of a larger document + return; + }else if (tag == "head"){ + m_bInHead = 1; + return; + }else if (tag == "body"){ // we display as a part of a larger document + oTag = "span"; + } + + QString tagText; + tagText += '<'; + tagText += oTag; + + if (tag == "p") + { + m_paraDirInsertionPos = res.length() + tagText.length(); + } + + for (list::const_iterator it = attrs.begin(); it != attrs.end(); ++it){ + QString name = it->toLower(); + ++it; + QString value = *it; + + // Handling for attributes of specific tags. + if (tag == "body"){ + if (name == "bgcolor"){ + style += "background-color:" + value + ';'; + continue; + } + }else if (tag == "p"){ + if (name == "dir"){ + QString dir = value.toLower(); + if (dir == "ltr") + m_paragraphDir = DirLTR; + else if (dir == "rtl") + m_paragraphDir = DirRTL; + else + m_paragraphDir = DirUnknown; + } + }else if (tag == "font"){ + if (name == "color" && m_bIgnoreColors) + continue; + } + + // Handle for generic attributes. + if (name == "style"){ + style += value; + continue; + } + + tagText += ' '; + tagText += name; + if (!value.isEmpty()){ + tagText += "=\""; + tagText += value; + tagText += '\"'; + } + } + + // Quite crude but working CSS to remove color styling. + // It won't filter out colors as part of 'background', but life's tough. + // (If it's any comfort, Qt probably won't display it either.) + if (!style.isEmpty()){ + if (m_bIgnoreColors){ + list opt = parseStyle(style); + list new_opt; + for (list::iterator it = opt.begin(); it != opt.end(); ++it){ + QString name = *it; + it++; + if (it == opt.end()) + break; + QString value = *it; + if ((name == "color") || + (name == "background") || + (name == "background-color") || + (name == "font-size") || + (name == "font-style") || + (name == "font-variant") || + (name == "font-weight") || + (name == "font-family")) + continue; + new_opt.push_back(name); + new_opt.push_back(value); + } + style = makeStyle(new_opt); + } + if (!style.isEmpty()) + tagText += " style=\"" + style + '\"'; + } + tagText += '>'; + res += tagText; +} + +void ViewParser::tag_end(const QString &tag) +{ + QString oTag = tag; + if (tag == "a"){ + m_bInLink = false; + }else if (tag == "p"){ + if (m_bInParagraph && m_bParagraphEmpty) + // The user probably didn't intend to insert an empty paragraph. + // We are probably viewing faulty content produced by QTextEdit + // (which returns

but optimizes it away upon loading), + // so we fix it up. + res += "
"; + res += "

"; + m_bInParagraph = false; + return; + }else if (tag == "head"){ + m_bInHead = false; + return; + }else if (tag == "html"){ + return; + }else if (tag == "body"){ + oTag = "span"; + } + if (m_bInHead) + return; + res += "'; +} + +QString MsgViewBase::parseText(const QString &text, bool bIgnoreColors, bool bUseSmiles) +{ + ViewParser parser(bIgnoreColors, bUseSmiles); + return parser.parse(text); +} + +/* +#ifndef NO_MOC_INCLUDES +#include "msgview.moc" +#endif +*/ + diff --git a/plugins/_core/msgview.h b/plugins/_core/msgview.h new file mode 100644 index 0000000..c9453f4 --- /dev/null +++ b/plugins/_core/msgview.h @@ -0,0 +1,92 @@ +/*************************************************************************** + msgview.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _MSGVIEW_H +#define _MSGVIEW_H + +#include +#include + +#include "simgui/textshow.h" +#include + +class CorePlugin; +class XSL; + +using namespace std; + +struct CutHistory +{ + unsigned contact; + QString client; + unsigned from; + unsigned size; +}; + +struct Msg_Id +{ + unsigned id; + QString client; +}; + +class MsgViewBase : public TextShow, public SIM::EventReceiver +{ + Q_OBJECT +public: + MsgViewBase(QWidget *parent, const char *name="", unsigned id=(unsigned)(-1)); + ~MsgViewBase(); + void addMessage(SIM::Message *msg, bool bUnread=false, bool bSync=true); + bool findMessage(SIM::Message *msg); + void setSelect(const QString &str); + void setXSL(XSL*); + static QString parseText(const QString &text, bool bIgnoreColors, bool bUseSmiles); + unsigned m_id; + SIM::Message *currentMessage(); +protected slots: + void update(); +protected: + virtual bool processEvent(SIM::Event*); + virtual void contextMenuEvent( QContextMenuEvent *event ); + void setBackground(unsigned start); + void setSource(const QString&); + void setSource(const QUrl&); + void setColors(); + void reload(); + unsigned messageId(const QString&, QString &client); + QString messageText(SIM::Message *msg, bool bUnread); + QPoint m_popupPos; + QString m_selectStr; + unsigned m_nSelection; + XSL *xsl; + vector m_cut; + list m_updated; +}; + +class MsgView : public MsgViewBase +{ + Q_OBJECT +public: + MsgView(QWidget *parent, unsigned id); + ~MsgView(); +protected slots: + void init(); +protected: + virtual bool processEvent(SIM::Event*); +}; + +#endif + diff --git a/plugins/_core/msgview_menu.cpp b/plugins/_core/msgview_menu.cpp new file mode 100644 index 0000000..5ec413e --- /dev/null +++ b/plugins/_core/msgview_menu.cpp @@ -0,0 +1,88 @@ +/*************************************************************************** + msgview_menu.cpp + + This file contains subroutine that creates MenuMsgView menu and add some + of it's items. Items that created in other places are mentioned as a comments. + MenuMsgView used as context menu for chat history in contaner window + (chat-window) and as a context menu in history window. (Some menu items are + visible only when used in history window (CmdDeleteMessage, CmdCutHistory)) + ------------------- + begin : Tue Nov 26 2008 + based on : core.cpp of Sim-IM by Vladimir Shutoff + and Sim-IM team + copyright : (C) 2002 - 2004 Vladimir Shutoff + (C) 2004 - 2008 Sim-IM Development Team + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "core.h" + +using namespace SIM; + +void CorePlugin::createMenuMsgView() +{ + EventMenu(MenuMsgView, EventMenu::eAdd).process(); + + Command cmd; + + cmd->id = CmdMsgOpen; + cmd->text = I18N_NOOP("&Open message"); + cmd->icon = "message"; + cmd->menu_id = MenuMsgView; + cmd->menu_grp = 0x1000; + cmd->bar_id = 0; + cmd->bar_grp = 0; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdMsgSpecial; + cmd->text = "_"; + cmd->icon = QString::null; + cmd->menu_id = MenuMsgView; + cmd->menu_grp = 0x1001; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdCopy; + cmd->text = I18N_NOOP("&Copy"); + cmd->accel = "Ctrl+C"; + cmd->icon = "editcopy"; + cmd->menu_id = MenuMsgView; + cmd->menu_grp = 0x2000; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdDeleteMessage; + cmd->text = I18N_NOOP("&Delete message"); + cmd->accel = QString::null; + cmd->icon = "remove"; + cmd->menu_id = MenuMsgView; + cmd->menu_grp = 0x3000; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdCutHistory; + cmd->text = I18N_NOOP("&Cut history"); + cmd->icon = "remove"; + cmd->menu_id = MenuMsgView; + cmd->menu_grp = 0x3001; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + /***** Ignore this phrase (CmdIgnoreText, grp=0x7000) *****/ + // This item should be created by filter plugin by FilterPlugin constructor but for + // some reason it is not seen at menu list + // FIXME: Find out why 'Ignore this phrase' is not seen + + /***** Copy location (CmdCopyLocation, grp=0x7010) *****/ + // This menu item is created in plugins/navigate/navigate.cpp by NavigatePlugin constructor + +} diff --git a/plugins/_core/newprotocol.cpp b/plugins/_core/newprotocol.cpp new file mode 100644 index 0000000..1ffb24f --- /dev/null +++ b/plugins/_core/newprotocol.cpp @@ -0,0 +1,242 @@ +/*************************************************************************** + newprotocol.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "newprotocol.h" + +#include "icons.h" + +#include "profilemanager.h" +#include "newprotocol.h" +#include "connectwnd.h" +#include "core.h" +#include "contacts/client.h" +#include "contacts/protocolmanager.h" +#include "log.h" + +#include +#include +#include +#include + +using namespace std; +using namespace SIM; + +//static bool cmp_protocol(Protocol *p1, Protocol *p2) +//{ +// const CommandDef *cmd1 = p1->description(); +// const CommandDef *cmd2 = p2->description(); +// QString s1 = i18n(cmd1->text); +// QString s2 = i18n(cmd2->text); +// return s1 < s2; +//} + +NewProtocol::NewProtocol(QWidget *parent, int default_protocol, bool bConnect) : QWizard(parent) +{ + setupUi(this); + m_setup = NULL; + m_last = NULL; + m_bConnected = false; + m_bConnect = false; + m_bStart = (parent == NULL); + setWindowIcon(Icon("configure")); + setButtonsPict(this); + + m_setupPage = new QWizardPage( this ); + m_setupLayout = new QHBoxLayout(m_setupPage); + addPage(m_setupPage); + + m_connectWnd = new ConnectWnd(m_bStart); + addPage(m_connectWnd); //, i18n(protocol->description()->text)); + if (m_bStart){ + m_last = new QWizardPage(this); + addPage(m_last);//, i18n(protocol->description()->text)); + } + +// helpButton()->hide(); + + QStringList plugins = getPluginManager()->enumPlugins(); + foreach(QString pluginname, plugins) + { + if(getPluginManager()->isPluginProtocol(pluginname)) + m_protocolPlugins.append(getPluginManager()->plugin(pluginname)); + } + + ProtocolPtr protocol; + ProtocolIterator it; + while ((protocol = ++it) != NULL){ + const CommandDef *cmd = protocol->description(); + if (cmd == NULL) + continue; + m_protocols.push_back(protocol); + } + //sort(m_protocols.begin(), m_protocols.end(), cmp_protocol); + for (unsigned i = 0; i < m_protocols.size(); i++){ + const CommandDef *cmd = m_protocols[i]->description(); + cmbProtocol->addItem(Icon(cmd->icon), i18n(cmd->text)); + } + connect(cmbProtocol, SIGNAL(activated(int)), this, SLOT(protocolChanged(int))); + cmbProtocol->setCurrentIndex(default_protocol); + protocolChanged(default_protocol); + if (bConnect){ + next(); +// showPage(m_connectWnd); +// pageChanged(NULL); + } + connect(this, SIGNAL(currentIdChanged(int)), this, SLOT(pageChanged(int))); + log(L_DEBUG, "NewProtocol::NewProtocol()"); +} + +NewProtocol::~NewProtocol() +{ + if (m_connectWnd) + delete m_connectWnd; + if (m_setup) + delete m_setup; + + // Protocol::plugin() returns raw Plugin pointer, we need smart + SIM::ProfileManager::instance()->currentProfile()->enablePlugin(m_protocol->plugin()->name()); + log(L_DEBUG, "NewProtocol::~NewProtocol()"); +} + +void NewProtocol::protocolChanged(int n) +{ + if (m_setup){ + delete m_setup; + m_setup = NULL; + } + if ((n < 0) || (n >= (int)(m_protocols.size()))) + return; + ProtocolPtr protocol = m_protocols[n]; + m_protocol = protocol; + m_client = protocol->createClient(NULL); + if (m_client == NULL) + return; + m_setup = m_client->setupWnd(); + m_setup->setParent(m_setupPage); + m_setupLayout->addWidget(m_setup); + if (m_setup == NULL){ + m_client.clear(); + return; + } + connect(m_setup, SIGNAL(okEnabled(bool)), this, SLOT(okEnabled(bool))); + connect(this, SIGNAL(apply()), m_setup, SLOT(apply())); + m_setupPage->setTitle(i18n(protocol->description()->text)); + m_connectWnd->setTitle(i18n(protocol->description()->text)); + if(m_last) + { + m_last->setTitle(i18n(protocol->description()->text)); + } +// setNextEnabled(currentPage(), true); + setWindowIcon(Icon(protocol->description()->icon)); + EventRaiseWindow e(this); + e.process(); +} + +void NewProtocol::okEnabled(bool bEnable) +{ +// setNextEnabled(m_setup, bEnable); +} + +void NewProtocol::pageChanged(int id) +{ + if (currentPage() == m_connectWnd){ + emit apply(); + m_bConnect = true; + unsigned status = CorePlugin::instance()->getManualStatus(); + if (status == STATUS_OFFLINE) + status = STATUS_ONLINE; + m_client->setStatus(status, false); + m_connectWnd->setConnecting(true); +// setBackEnabled(m_connectWnd, false); +// setNextEnabled(currentPage(), false); +// setFinishEnabled(m_connectWnd, false); + } + if (m_last && (currentPage() == m_last)){ +// setFinishEnabled(m_connectWnd, false); +// cancelButton()->show(); +// backButton()->show(); +// finishButton()->hide(); +// showPage(protocolPage); + protocolChanged(0); + } +} + +void NewProtocol::reject() +{ + if (m_bConnect){ + m_client->setStatus(STATUS_OFFLINE, false); +// setBackEnabled(m_connectWnd, true); + m_bConnect = false; + back(); + return; + } + QWizard::reject(); +} + +void NewProtocol::loginComplete() +{ + if (m_client == NULL) + return; + m_bConnect = false; + m_bConnected = true; + m_client->setStatus(CorePlugin::instance()->getManualStatus(), true); + m_connectWnd->setConnecting(false); +// setNextEnabled(currentPage(), true); +// setFinishEnabled(m_connectWnd, true); + getContacts()->addClient(m_client.data()); + m_client.clear(); +// cancelButton()->hide(); +// backButton()->hide(); + EventSaveState e; + e.process(); + accept(); +} + +bool NewProtocol::processEvent(Event *e) +{ + if (m_client == NULL || !m_bConnect) + return false; + + switch (e->type()){ + case eEventClientChanged: + if (m_client->getState() == Client::Connected){ + QTimer::singleShot(0, this, SLOT(loginComplete())); + return false; + } + break; + case eEventClientNotification: { + EventClientNotification *ee = static_cast(e); + const EventNotification::ClientNotificationData &d = ee->data(); + if (d.client == m_client){ + m_connectWnd->setErr(i18n(d.text), + (d.code == AuthError) ? m_client->protocol()->description()->accel : QString()); + m_bConnect = false; + m_client->setStatus(STATUS_OFFLINE, false); +// setBackEnabled(m_connectWnd, true); +// setFinishEnabled(m_connectWnd, false); + return true; + } + break; + } + default: + break; + } + return false; +} +// vim: set expandtab: + + diff --git a/plugins/_core/newprotocol.h b/plugins/_core/newprotocol.h new file mode 100644 index 0000000..594bdc1 --- /dev/null +++ b/plugins/_core/newprotocol.h @@ -0,0 +1,73 @@ +/*************************************************************************** + newprotocol.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _NEWPROTOCOL_H +#define _NEWPROTOCOL_H + +#include +#include +#include "contacts.h" +#include "plugins.h" +#include "contacts/protocol.h" +#include "contacts/client.h" + +#include "ui_newprotocolbase.h" + +class ConnectWnd; +class CorePlugin; + +namespace SIM +{ + class Protocol; +} + +class NewProtocol + : public QWizard + , public Ui::NewProtocolBase + , public SIM::EventReceiver +{ + Q_OBJECT +public: + NewProtocol(QWidget *parent,int default_protocol=0, bool bConnect=false); + ~NewProtocol(); + SIM::ClientPtr m_client; + bool connected() { return m_bConnected; } +signals: + void apply(); +protected slots: + void protocolChanged(int); + void okEnabled(bool); + void pageChanged(int); + void loginComplete(); +private: + virtual bool processEvent(SIM::Event*); + virtual void reject(); + std::vector m_protocols; + ConnectWnd *m_connectWnd; + QWidget *m_setup; + QWizardPage *m_setupPage; + QHBoxLayout *m_setupLayout; + QWizardPage *m_last; + bool m_bConnect; + bool m_bConnected; + bool m_bStart; + QList m_protocolPlugins; + SIM::ProtocolPtr m_protocol; +}; + +#endif + diff --git a/plugins/_core/newprotocolbase.ui b/plugins/_core/newprotocolbase.ui new file mode 100644 index 0000000..f9655ab --- /dev/null +++ b/plugins/_core/newprotocolbase.ui @@ -0,0 +1,65 @@ + + + NewProtocolBase + + + + 0 + 0 + 290 + 284 + + + + New connection + + + QWizard::ClassicStyle + + + + Select protocol + + + + 11 + + + + + Protocol: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + qPixmapFromMimeSource + + + diff --git a/plugins/_core/nonim.cpp b/plugins/_core/nonim.cpp new file mode 100644 index 0000000..91f0963 --- /dev/null +++ b/plugins/_core/nonim.cpp @@ -0,0 +1,76 @@ +/*************************************************************************** + nonim.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "contacts.h" + +#include "nonim.h" +#include "contacts/contact.h" +#include "simgui/intedit.h" +#include + +using namespace SIM; + +NonIM::NonIM(QWidget *parent) : QWidget(parent) +{ + setupUi(this); + connect(this, SIGNAL(setAdd(bool)), topLevelWidget(), SLOT(setAdd(bool))); + edtMail->setValidator(new EMailValidator(edtMail)); + edtPhone->setValidator(new PhoneValidator(edtPhone)); +} + +void NonIM::showEvent(QShowEvent *e) +{ + QWidget::showEvent(e); + emit setAdd(true); +} + +void NonIM::add(Contact *&contact) +{ + contact = getContacts()->contact(0, true); + contact->setFirstName(edtFirst->text()); + contact->setLastName(edtLast->text()); + if (!edtMail->text().isEmpty()) + contact->setEMails(edtMail->text() + "/-"); + if (!edtPhone->text().isEmpty()) + contact->setPhones(edtPhone->text() + "/-"); + QString nick = edtNick->text(); + if (nick.isEmpty()){ + nick = edtFirst->text(); + if (!nick.isEmpty() && !edtLast->text().isEmpty()) + nick += ' '; + nick += edtLast->text(); + } + if (nick.isEmpty()) + nick = edtMail->text(); + if (nick.isEmpty()) + nick = edtPhone->text(); + contact->setName(nick); +} + +void NonIM::createContact(unsigned tmpFlags, Contact *&contact) +{ + add(contact); + contact->setFlags(contact->getFlags() | tmpFlags); +} + + +/* +#ifndef NO_MOC_INCLUDES +#include "nonim.moc" +#endif +*/ + diff --git a/plugins/_core/nonim.h b/plugins/_core/nonim.h new file mode 100644 index 0000000..ff982c9 --- /dev/null +++ b/plugins/_core/nonim.h @@ -0,0 +1,43 @@ +/*************************************************************************** + nonim.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _NONIM_H +#define _NONIM_H + +#include "ui_nonimbase.h" +#include "event.h" + +#include +#include + +class NonIM : public QWidget, public Ui::NonIM +{ + Q_OBJECT +public: + NonIM(QWidget *parent); +signals: + void setAdd(bool); + void showError(const QString&); +protected slots: + void add(SIM::Contact *&contact); + void createContact(unsigned tmpFlags, SIM::Contact *&contact); +protected: + void showEvent(QShowEvent*); +}; + +#endif + diff --git a/plugins/_core/nonimbase.ui b/plugins/_core/nonimbase.ui new file mode 100644 index 0000000..afb997c --- /dev/null +++ b/plugins/_core/nonimbase.ui @@ -0,0 +1,117 @@ + + + NonIM + + + + 0 + 0 + 232 + 309 + + + + Form2 + + + + 6 + + + 0 + + + + + Non-IM Contact + + + + + + First Name: + + + false + + + + + + + + + + Last Name: + + + false + + + + + + + + + + Nickname: + + + false + + + + + + + + + + E-Mail address: + + + false + + + + + + + + + + Phone: + + + false + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + diff --git a/plugins/_core/pagerbase.ui b/plugins/_core/pagerbase.ui new file mode 100644 index 0000000..3895eec --- /dev/null +++ b/plugins/_core/pagerbase.ui @@ -0,0 +1,106 @@ + + + PagerDetails + + + + 0 + 0 + 222 + 110 + + + + Form2 + + + + 6 + + + 11 + + + + + 0 + + + 6 + + + + + + + + + + + Provider: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + Email gateway: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Number: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + edtNumber + cmbProvider + edtGateway + + + + diff --git a/plugins/_core/pagerdetails.cpp b/plugins/_core/pagerdetails.cpp new file mode 100644 index 0000000..d6f79be --- /dev/null +++ b/plugins/_core/pagerdetails.cpp @@ -0,0 +1,89 @@ +/*************************************************************************** + pagerdetails.cpp - description + ------------------- + begin : Sun Mar 24 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "country.h" +#include "misc.h" + +#include "pagerdetails.h" + +#include +#include +#include + +using namespace SIM; + +PagerDetails::PagerDetails(QWidget *p, const QString &oldNumber) + : QWidget(p) +{ + setupUi(this); + cmbProvider->setEditable(true); + for (const pager_provider *provider = getProviders(); *provider->szName; provider++) + cmbProvider->addItem(provider->szName); + cmbProvider->lineEdit()->clear(); + connect(cmbProvider, SIGNAL(textChanged(const QString&)), this, SLOT(providerChanged(const QString&))); + connect(edtNumber, SIGNAL(textChanged(const QString&)), this, SLOT(textChanged(const QString&))); + connect(edtGateway, SIGNAL(textChanged(const QString&)), this, SLOT(textChanged(const QString&))); + QString pagerNumber = oldNumber; + QString number = getToken(pagerNumber, '@').trimmed(); + QString gateway = getToken(pagerNumber, '[').trimmed(); + QString providerName = getToken(pagerNumber, ']').trimmed(); + cmbProvider->lineEdit()->setText(providerName); + edtNumber->setText(number); + edtGateway->setText(gateway); + providerChanged(cmbProvider->lineEdit()->text()); +} + +void PagerDetails::getNumber() +{ + bool bOK = true; + QString res; + if (!edtNumber->text().isEmpty()){ + res = edtNumber->text(); + }else{ + bOK = false; + } + if (!edtGateway->text().isEmpty()){ + res += '@'; + res += edtGateway->text(); + }else{ + bOK = false; + } + if (!cmbProvider->lineEdit()->text().isEmpty()){ + res += " ["; + res += cmbProvider->lineEdit()->text(); + res += ']'; + } + emit numberChanged(res, bOK); +} + +void PagerDetails::providerChanged(const QString &str) +{ + for (const pager_provider *p = getProviders(); *p->szName; p++){ + if (str == p->szName){ + edtGateway->setText(p->szGate); + edtGateway->setEnabled(false); + getNumber(); + return; + } + } + edtGateway->setEnabled(true); +} + +void PagerDetails::textChanged(const QString&) +{ + getNumber(); +} diff --git a/plugins/_core/pagerdetails.h b/plugins/_core/pagerdetails.h new file mode 100644 index 0000000..cbdc110 --- /dev/null +++ b/plugins/_core/pagerdetails.h @@ -0,0 +1,38 @@ +/*************************************************************************** + pageretails.h - description + ------------------- + begin : Sun Mar 24 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _PAGERDETAILS_H +#define _PAGERDETAILS_H + +#include "ui_pagerbase.h" +#include "event.h" + +class PagerDetails : public QWidget, public Ui::PagerDetails +{ + Q_OBJECT +public: + PagerDetails(QWidget *p, const QString &number); + void getNumber(); +signals: + void numberChanged(const QString&, bool); +protected slots: + void providerChanged(const QString&); + void textChanged(const QString&); +}; + +#endif + diff --git a/plugins/_core/phonebase.ui b/plugins/_core/phonebase.ui new file mode 100644 index 0000000..283a45c --- /dev/null +++ b/plugins/_core/phonebase.ui @@ -0,0 +1,201 @@ + + + + + PhoneDetailsBase + + + + 0 + 0 + 403 + 130 + + + + + 1 + 1 + + + + Form1 + + + + 11 + + + 6 + + + + + 0 + + + 6 + + + + + Area code: + + + Qt::AlignCenter + + + false + + + + + + + + + + Extension: + + + Qt::AlignCenter + + + false + + + + + + + + 1 + 0 + + + + + + + + + 1 + 0 + + + + + + + + + + + - + + + false + + + + + + + Number: + + + Qt::AlignCenter + + + false + + + + + + + - + + + false + + + + + + + Country: + + + Qt::AlignCenter + + + false + + + + + + + - + + + Qt::AlignVCenter|Qt::AlignLeft + + + false + + + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Vertical + + + + + + + + QWidget + QWidget +
QWidget
+ + -1 + -1 + + 0 + + 5 + 5 + + image0 + + text + +
+
+ + cmbCountry + edtAreaCode + edtNumber + edtExtension + + + + 789c6dd2c10ac2300c00d07bbf2234b7229d1be245fc04c5a3201e4615f430059d0711ff5ddb2e6bb236ec90eed134cb5a19d8ef36602af5ecdbfeeac05dda0798d3abebde87e3faa374d3807fa0d633a52d38d8de6f679fe33fc776e196f53cd010188256a3600a292882096246517815ca99884606e18044a3a40d91824820924265a7923a2e8bcd05f33db1173e002913175f2a6be6d3294871a2d95fa00e8a94ee017b69d339d90df1e77c57ea072ede6758 + + +
diff --git a/plugins/_core/phonedetails.cpp b/plugins/_core/phonedetails.cpp new file mode 100644 index 0000000..694b92c --- /dev/null +++ b/plugins/_core/phonedetails.cpp @@ -0,0 +1,134 @@ +/*************************************************************************** + phonedetails.cpp - description + ------------------- + begin : Sun Mar 24 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "misc.h" + +#include "phonedetails.h" + +#include +#include +#include +#include +#include + +using namespace SIM; + +PhoneDetails::PhoneDetails(QWidget *p, const QString &oldNumber) + : QWidget(p) +{ + setupUi(this); + QString number = oldNumber; + QString areaCode; + QString extension; + unsigned short countryCode = 0; + if (number.indexOf('(') >= 0){ + QString country = getToken(number, '(').trimmed(); + int i = 0; + while(!country[i].isNumber()) + i++; + countryCode = country.mid(i).toUShort(); + areaCode = getToken(number, ')').trimmed(); + } + if (number.indexOf(" - ") >= 0){ + int pos = number.indexOf(" - "); + extension = number.mid(pos + 3).trimmed(); + number = number.mid(0, pos); + } + number = number.trimmed(); + initCombo(cmbCountry, countryCode, getCountries()); + + QFontMetrics fm(font()); + unsigned wChar = fm.width("0"); + QSize s(wChar*10, 0); + edtNumber->setMinimumSize(s); + s = edtAreaCode->size(); + s.setWidth(wChar*5); + QSize sLabel = lblAreaCode->sizeHint(); + sLabel.setHeight(0); + s = s.expandedTo(sLabel); + edtAreaCode->setMaximumSize(s); + s.setWidth(wChar*5); + sLabel = lblExtension->sizeHint(); + sLabel.setHeight(0); + s = s.expandedTo(sLabel); + edtExtension->setMaximumSize(s); + connect(cmbCountry, SIGNAL(activated(int)), this, SLOT(countryChanged(int))); + connect(edtAreaCode, SIGNAL(textChanged(const QString&)), this, SLOT(textChanged(const QString&))); + connect(edtNumber, SIGNAL(textChanged(const QString&)), this, SLOT(textChanged(const QString&))); + connect(edtExtension, SIGNAL(textChanged(const QString&)), this, SLOT(textChanged(const QString&))); + edtAreaCode->setValidator(new QIntValidator(edtAreaCode)); + edtNumber->setValidator(new QIntValidator(edtNumber)); + edtExtension->setValidator(new QIntValidator(edtExtension)); + edtAreaCode->setText(areaCode); + edtNumber->setText(number); + edtExtension->setText(extension); + m_bExt = false; +} + +void PhoneDetails::setExtensionShow(bool bShow) +{ + if (bShow){ + lblExtension->show(); + edtExtension->show(); + lblDivExtension->show(); + }else{ + lblExtension->hide(); + edtExtension->hide(); + lblDivExtension->hide(); + } + m_bExt = bShow; +} + +void PhoneDetails::getNumber() +{ + QString res; + bool bOK = true; + if (cmbCountry->currentIndex() > 0){ + res = '+'; + res += QString::number(getComboValue(cmbCountry, getCountries())); + res += ' '; + }else{ + bOK = false; + } + if (edtAreaCode->text().length() > 0){ + res += '('; + res += edtAreaCode->text(); + res += ") "; + }else{ + bOK = false; + } + if (edtNumber->text().length() > 0){ + res += edtNumber->text(); + }else{ + bOK = false; + } + if (m_bExt && (edtExtension->text().length() > 0)){ + res += " - "; + res += edtExtension->text(); + } + emit numberChanged(res, bOK); +} + +void PhoneDetails::countryChanged(int) +{ + getNumber(); +} + +void PhoneDetails::textChanged(const QString&) +{ + getNumber(); +} diff --git a/plugins/_core/phonedetails.h b/plugins/_core/phonedetails.h new file mode 100644 index 0000000..9201000 --- /dev/null +++ b/plugins/_core/phonedetails.h @@ -0,0 +1,41 @@ +/*************************************************************************** + phonedetails.h - description + ------------------- + begin : Sun Mar 24 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _PHONEDETAILS_H +#define _PHONEDETAILS_H + +#include "ui_phonebase.h" +#include "event.h" + +class PhoneDetails : public QWidget, public Ui::PhoneDetailsBase +{ + Q_OBJECT +public: + PhoneDetails(QWidget *p, const QString &oldNumber); + void setExtensionShow(bool bShow); + void getNumber(); +signals: + void numberChanged(const QString &str, bool bOK); +protected slots: + void countryChanged(int); + void textChanged(const QString&); +protected: + bool m_bExt; +}; + +#endif + diff --git a/plugins/_core/pict/CMakeLists.txt b/plugins/_core/pict/CMakeLists.txt new file mode 100644 index 0000000..d97b4e9 --- /dev/null +++ b/plugins/_core/pict/CMakeLists.txt @@ -0,0 +1,7 @@ +# install only + +FILE(GLOB mng *.mng) +FILE(GLOB png *.png) + +INSTALL(FILES ${mng} DESTINATION ${SIM_PICT_DIR}) +INSTALL(FILES ${png} DESTINATION ${SIM_PICT_DIR}) diff --git a/plugins/_core/pict/connect.gif b/plugins/_core/pict/connect.gif new file mode 100644 index 0000000..61cd01e Binary files /dev/null and b/plugins/_core/pict/connect.gif differ diff --git a/plugins/_core/pict/connect.mng b/plugins/_core/pict/connect.mng new file mode 100644 index 0000000..04a7d3a Binary files /dev/null and b/plugins/_core/pict/connect.mng differ diff --git a/plugins/_core/plugincfg.cpp b/plugins/_core/plugincfg.cpp new file mode 100644 index 0000000..deb1137 --- /dev/null +++ b/plugins/_core/plugincfg.cpp @@ -0,0 +1,76 @@ +/*************************************************************************** + plugincfg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "misc.h" +#include "profilemanager.h" +#include "log.h" + +#include "plugincfg.h" +#include + +using namespace SIM; + +PluginCfg::PluginCfg(QWidget *parent, const QString& pluginname) : QWidget(parent) +{ + setupUi(this); + m_pluginName = pluginname; + if(ProfileManager::instance()->currentProfile()->enabledPlugins().contains(m_pluginName) || + getPluginManager()->isPluginAlwaysEnabled(m_pluginName)) + { + PluginPtr plugin = getPluginManager()->plugin(pluginname); + QWidget *w = plugin->createConfigWindow(addWnd); + if (w){ + QVBoxLayout *lay = new QVBoxLayout(addWnd); + lay->addWidget(w); + QObject::connect(parent->topLevelWidget(), SIGNAL(applyChanges()), w, SLOT(apply())); + // adjust plugin widget + w->setMinimumSize(w->sizeHint()); + w->adjustSize(); + // adjust addWnd widget + addWnd->setMinimumSize(addWnd->sizeHint()); + addWnd->adjustSize(); + } + } + // adjust description + if(!getPluginManager()->pluginDescription(pluginname).isNull()) + { + lblDescription->setText(i18n(getPluginManager()->pluginDescription(pluginname))); + } + else + { + lblDescription->setText(""); + } + // adjust tab + tabWnd->setCurrentIndex(0); + tabWnd->setTabText(0, i18n(getPluginManager()->pluginTitle(pluginname))); + tabWnd->setMinimumSize(tabWnd->sizeHint()); + tabWnd->adjustSize(); + // adjust complete widget + setMinimumSize(sizeHint()); + adjustSize(); + if (getPluginManager()->isPluginAlwaysEnabled(pluginname)) { + chkEnable->hide(); + } else { + chkEnable->setEnabled(true); + chkEnable->setChecked(ProfileManager::instance()->currentProfile()->enabledPlugins().contains(pluginname)); + } +} + +void PluginCfg::apply() +{ +} + diff --git a/plugins/_core/plugincfg.h b/plugins/_core/plugincfg.h new file mode 100644 index 0000000..87fc945 --- /dev/null +++ b/plugins/_core/plugincfg.h @@ -0,0 +1,37 @@ +/*************************************************************************** + plugincfg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _PLUGINCFG_H +#define _PLUGINCFG_H + +#include "plugins.h" +#include "ui_plugincfgbase.h" + +class PluginCfg : public QWidget, public Ui::PluginCfgBase +{ + Q_OBJECT +public: + PluginCfg(QWidget *parent, const QString& pluginname); +public slots: + void apply(); +protected: + SIM::PluginInfo *m_info; + QString m_pluginName; +}; + +#endif + diff --git a/plugins/_core/plugincfgbase.ui b/plugins/_core/plugincfgbase.ui new file mode 100644 index 0000000..bd322ea --- /dev/null +++ b/plugins/_core/plugincfgbase.ui @@ -0,0 +1,74 @@ + + + PluginCfgBase + + + + 0 + 0 + 575 + 585 + + + + Form1 + + + + 6 + + + 11 + + + + + + + + + + + + Plugin &enabled + + + + + + + + 0 + 0 + + + + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + true + + + + + + + + 0 + 0 + + + + + + + + + + + + + diff --git a/plugins/_core/prefcfg.cpp b/plugins/_core/prefcfg.cpp new file mode 100644 index 0000000..6fc60da --- /dev/null +++ b/plugins/_core/prefcfg.cpp @@ -0,0 +1,138 @@ +/*************************************************************************** + prefcfg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "misc.h" + +#include "log.h" +#include "prefcfg.h" +#include "contacts/contact.h" +#include "contacts/group.h" + +#include + +using namespace SIM; + +PrefConfig::PrefConfig(QWidget *parent, CommandDef *cmd, Contact *contact, Group *group) + : QWidget(parent) + , m_cmd(cmd) + , m_contact(contact) + , m_group(group) +{ + setupUi(this); + SIM::PropertyHubPtr data; + SIM::PropertyHubPtr mapdata; + if (m_contact) + { + data = m_contact->getUserData(m_cmd->accel); // HACK ! + if (m_contact->getUserData()->getUserData(m_cmd->accel)) + chkOverride->setChecked(true); + mapdata = m_contact->getUserData()->root(); + } + else if (m_group) { + mapdata = m_group->getUserData()->root(); + } + QWidget *w = NULL; + if(cmd->flags & COMMAND_CONTACT) + { + w = ((getPreferencesWindowContact)(cmd->param))(addWnd, mapdata); + chkOverride->setChecked(w->property("override").toBool()); + } + else if(!data.isNull()) + { + w = ((getPreferencesWindowContact)(cmd->param))(addWnd, data); + } + if(w) { + QVBoxLayout *lay = new QVBoxLayout(addWnd); + lay->addWidget(w); + + if(cmd->flags & COMMAND_CONTACT) + { + connect(this, SIGNAL(apply(SIM::PropertyHubPtr, bool)), w, SLOT(apply(SIM::PropertyHubPtr, bool))); + } + else + { + connect(this, SIGNAL(apply(SIM::PropertyHubPtr)), w, SLOT(apply(SIM::PropertyHubPtr))); + } + if(addWnd) + addWnd->setMinimumSize(w->minimumSizeHint()); + setMinimumSize(sizeHint()); + } + tabWnd->setCurrentIndex(0); + tabWnd->setTabText(tabWnd->currentIndex(), i18n(m_cmd->text)); + tabWnd->adjustSize(); + connect(chkOverride, SIGNAL(toggled(bool)), this, SLOT(overrideToggled(bool))); + overrideToggled(chkOverride->isChecked()); +} + +void PrefConfig::apply() +{ + if(m_cmd->flags & COMMAND_CONTACT) + { + SIM::PropertyHubPtr data; + if (m_contact) + { + log(L_DEBUG, "Contact"); + data = m_contact->getUserData()->root(); + } + else if (m_group) + { + log(L_DEBUG, "Group"); + data = m_group->getUserData()->root(); + } + log(L_DEBUG, "NULL Contact"); + if (data) + emit apply(data, chkOverride->isChecked()); + } + else + { + if (chkOverride->isChecked()) + { + SIM::PropertyHubPtr data; + if (m_contact) + { + data = m_contact->getUserData()->getUserData(m_cmd->accel); + if(data.isNull()) + data = m_contact->getUserData()->createUserData(m_cmd->accel); + } + else if (m_group) + { + data = m_group->getUserData()->getUserData(m_cmd->accel); + if(data.isNull()) + data = m_group->getUserData()->createUserData(m_cmd->accel); + } + if (data) + emit apply(data); + } + else + { + if (m_contact) + { + m_contact->getUserData()->destroyUserData(m_cmd->accel); + } + else if(m_group) + { + m_group->getUserData()->destroyUserData(m_cmd->accel); + } + } + } +} + +void PrefConfig::overrideToggled(bool bState) +{ + for(int i = 0; i < tabWnd->count(); ++i) + tabWnd->widget(i)->setEnabled(bState); +} diff --git a/plugins/_core/prefcfg.h b/plugins/_core/prefcfg.h new file mode 100644 index 0000000..8521c22 --- /dev/null +++ b/plugins/_core/prefcfg.h @@ -0,0 +1,48 @@ +/*************************************************************************** + prefcfg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _PREFCFG_H +#define _PREFCFG_H + +#include "cmddef.h" +#include "contacts.h" +#include "ui_prefcfgbase.h" + +class PrefConfig : public QWidget, public Ui::PrefConfigBase +{ + Q_OBJECT +public: + PrefConfig(QWidget *parent, SIM::CommandDef *cmd, SIM::Contact *contact, SIM::Group *group); + +signals: + void apply(SIM::PropertyHubPtr); + void apply(SIM::PropertyHubPtr, bool); + +public slots: + void apply(); + +protected slots: + void overrideToggled(bool); + +protected: + SIM::CommandDef *m_cmd; + SIM::Contact *m_contact; + SIM::Group *m_group; +}; + +#endif + diff --git a/plugins/_core/prefcfgbase.ui b/plugins/_core/prefcfgbase.ui new file mode 100644 index 0000000..c465c25 --- /dev/null +++ b/plugins/_core/prefcfgbase.ui @@ -0,0 +1,54 @@ + + + PrefConfigBase + + + + 0 + 0 + 354 + 266 + + + + Form1 + + + + 6 + + + 11 + + + + + &Override global settings + + + + + + + + + + + + 6 + + + 11 + + + + + + + + + + + + + diff --git a/plugins/_core/search.cpp b/plugins/_core/search.cpp new file mode 100644 index 0000000..3ba4200 --- /dev/null +++ b/plugins/_core/search.cpp @@ -0,0 +1,854 @@ +/*************************************************************************** + search.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "icons.h" +#include "search.h" +#include "usercfg.h" +#include "core.h" + +#include "nonim.h" +#include "searchall.h" + +#include "simgui/ballonmsg.h" +#include "simgui/toolbtn.h" +#include "simgui/listview.h" + +#include "contacts/contact.h" +#include "contacts/client.h" +#include "contacts/group.h" +//#include "searchbase.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace SIM; + +const unsigned COL_KEY = 0x100; +const unsigned COL_SEARCH_WND = 0x101; + +SearchWidget::SearchWidget(QWidget* parent) : QWidget(parent) +{ + setupUi(this); +} + +SearchDialog::SearchDialog() +{ + SET_WNDPROC("search") + setWindowIcon(Icon("find")); + setButtonsPict(this); + setWindowTitle(i18n("Search")); + m_current = NULL; + m_currentResult = NULL; + m_bAdd = true; + m_id = 0; + m_result_id = 0; + m_active = NULL; + m_search = new SearchWidget(this); + m_update = new QTimer(this); + connect(m_update, SIGNAL(timeout()), this, SLOT(update())); + setCentralWidget(m_search); + m_status = statusBar(); + m_result = NULL; + setAdd(false); + m_search->btnOptions->setIcon(Icon("1downarrow")); + m_search->btnAdd->setIcon(Icon("add")); + m_search->btnNew->setIcon(Icon("new")); + connect(m_search->wndCondition, SIGNAL(aboutToShow(QWidget*)), this, SLOT(aboutToShow(QWidget*))); + connect(m_search->wndResult, SIGNAL(aboutToShow(QWidget*)), this, SLOT(resultShow(QWidget*))); + fillClients(); + connect(m_search->cmbClients, SIGNAL(activated(int)), this, SLOT(clientActivated(int))); + m_result = new ListView(m_search->wndResult); + m_result->addColumn(i18n("Results")); + //m_result->setShowSortIndicator(true); + m_result->setExpandingColumn(0); + m_result->setFrameShadow(QFrame::Sunken); + m_result->setLineWidth(1); + addResult(m_result); + showResult(NULL); + aboutToShow(m_search->wndCondition->currentWidget()); + connect(m_search->btnSearch, SIGNAL(clicked()), this, SLOT(searchClick())); + m_search->cmbClients->setFocus(); + connect(m_search->btnOptions, SIGNAL(clicked()), this, SLOT(optionsClick())); + connect(m_search->btnAdd, SIGNAL(clicked()), this, SLOT(addClick())); + m_search->btnOptions->setEnabled(false); + m_search->btnAdd->setEnabled(false); + connect(m_result, SIGNAL(selectionChanged()), this, SLOT(selectionChanged())); + connect(m_result, SIGNAL(dragStart()), this, SLOT(dragStart())); + connect(m_search->btnNew, SIGNAL(clicked()), this, SLOT(newSearch())); + m_result->setMenu(MenuSearchItem); + resultShow(m_result); +} + +SearchDialog::~SearchDialog() +{ + // Fixme Todin + //::saveGeometry(this, CorePlugin::instance()->data.SearchGeometry); +} + +void SearchDialog::resizeEvent(QResizeEvent *e) +{ + QMainWindow::resizeEvent(e); + m_result->adjustColumn(); + /* Fixme Todin + if (isVisible()) + ::saveGeometry(this, CorePlugin::instance()->data.SearchGeometry); + */ +} + +void SearchDialog::moveEvent(QMoveEvent *e) +{ + QMainWindow::moveEvent(e); + /* Fixme Todin + if (isVisible()) + ::saveGeometry(this, CorePlugin::instance()->data.SearchGeometry); + */ +} + +void SearchDialog::closeEvent(QCloseEvent *e) +{ + QMainWindow::closeEvent(e); + emit finished(); +} + +void SearchDialog::setAdd(bool bAdd) +{ + if (m_bAdd == bAdd) + return; + m_bAdd = bAdd; + setAddButton(); + setTitle(); +} + +void SearchDialog::setAddButton() +{ + QString text; + QIcon icon; + if (m_active){ + icon = Icon("cancel"); + text = i18n("&Cancel"); + }else if (m_bAdd){ + icon = Icon("add"); + text = i18n("&Add"); + }else{ + icon = Icon("find"); + text = i18n("&Search"); + } + m_search->btnSearch->setText(text); //Fixme: btnSearch broken + m_search->btnSearch->setIcon(icon); +} + +void SearchDialog::fillClients() +{ + vector widgets = m_widgets; + m_widgets.clear(); + m_search->cmbClients->clear(); + unsigned nClients = 0; + int current = -1; + int defCurrent = -1; + for (unsigned i = 0; i < getContacts()->nClients(); i++){ + Client *client = getContacts()->getClient(i); + QWidget *search = client->searchWindow(m_search->wndCondition); + if (search == NULL) + continue; + unsigned n; + for (n = 0; n < widgets.size(); n++){ + if ((widgets[n].client != client) || !widgets[n].name.isEmpty()) + continue; + delete search; + search = widgets[n].widget; + widgets[n].widget = NULL; + break; + } + if (n >= widgets.size()) + m_id = m_search->wndCondition->addWidget(search); + m_search->cmbClients->addItem(Icon(client->protocol()->description()->icon), + CorePlugin::instance()->clientName(client)); + ClientWidget cw; + cw.client = client; + cw.widget = search; + m_widgets.push_back(cw); + if (search == m_current) + current = m_widgets.size() - 1; + if (client->protocol()->description()->flags & PROTOCOL_SEARCH) + nClients++; + if (client->name() == CorePlugin::instance()->value("SearchClient").toString()) + defCurrent = m_widgets.size() - 1; + } + + + if (nClients > 1){ + unsigned n; + QWidget *search = NULL; + for (n = 0; n < widgets.size(); n++){ + if (widgets[n].client == (Client*)(-1)){ + search = widgets[n].widget; + widgets[n].widget = NULL; + break; + } + } + if (search == NULL){ + search = new SearchAll(NULL); + m_id = m_search->wndCondition->addWidget(search); + } + m_search->cmbClients->addItem(Icon("find"), i18n("All networks")); + ClientWidget cw; + cw.client = (Client*)(-1); + cw.widget = search; + m_widgets.push_back(cw); + if ((search == m_current) || ((m_current == NULL) && (current < 0) && (defCurrent < 0))) + current = m_widgets.size() - 1; + } + unsigned n; + QWidget *search = NULL; + for (n = 0; n < widgets.size(); n++){ + if (widgets[n].client == NULL){ + search = widgets[n].widget; + widgets[n].widget = NULL; + break; + } + } + if (search == NULL){ + search = new NonIM(NULL); + m_id = m_search->wndCondition->addWidget(search); + } + m_search->cmbClients->addItem(Icon("nonim"), i18n("Non-IM contact")); + ClientWidget cw; + cw.client = NULL; + cw.widget = search; + m_widgets.push_back(cw); + if (search == m_current) + current = m_widgets.size() - 1; + + if (m_update->isActive()){ + m_update->stop(); + }else if (m_result){ + m_result->viewport()->setUpdatesEnabled(false); + } + for (n = 0; n < widgets.size(); n++){ + if (widgets[n].name.isEmpty()) + continue; + unsigned i; + for (i = 0; i < m_widgets.size(); i++) + if (widgets[n].client == m_widgets[i].client) + break; + if (i >= m_widgets.size()) + continue; + m_search->cmbClients->addItem(Icon(widgets[n].client->protocol()->description()->icon), + widgets[n].name); + m_widgets.push_back(widgets[n]); + widgets[n].widget = NULL; + } + for (n = 0; n < widgets.size(); n++){ + if (widgets[n].widget){ + if (widgets[n].widget == m_active) + searchDone(m_active); + if (widgets[n].widget == m_current) + m_current = NULL; + for (int i = 0; i < m_result->topLevelItemCount(); i++){ + ListViewItem *item = static_cast(m_result->topLevelItem(i)); + if ((QWidget*)(item->text(COL_SEARCH_WND).toULong()) == widgets[n].widget) + delete item; + } + delete widgets[n].widget; + } + } + + if (current == -1) + current = defCurrent; + if (current == -1) + current = 0; + m_search->cmbClients->setCurrentIndex(current); + clientActivated(current); + setStatus(); + m_update->start(500); +} + +void SearchDialog::clientActivated(int n) +{ + if ((unsigned)n >= m_widgets.size()) + return; + searchDone(m_active); + if (m_widgets[n].widget != m_current) + showResult(NULL); + m_search->wndCondition->setCurrentWidget(m_widgets[n].widget); + setTitle(); +} + +void SearchDialog::setTitle() +{ + unsigned n = m_search->cmbClients->currentIndex(); + if (n >= m_widgets.size()) + return; + Client *client = m_widgets[n].client; + QString name; + if ((client != NULL) && (client != (Client*)(-1))) + name = client->name(); + CorePlugin::instance()->setValue("SearchClient", name); + if (m_bAdd){ + setWindowTitle(i18n("Add") + ": " + m_search->cmbClients->currentText()); + setWindowIcon(Icon("add")); + }else{ + setWindowTitle(i18n("Search") + ": " + m_search->cmbClients->currentText()); + setWindowIcon(Icon("find")); + } +} + +void SearchDialog::toggled(bool) +{ + textChanged(); +} + +bool SearchDialog::processEvent(Event *e) +{ + switch (e->type()){ + case eEventClientsChanged: + case eEventClientChanged: + fillClients(); + break; + case eEventCommandExec:{ + if (m_result != m_currentResult) + return false; + EventCommandExec *ece = static_cast(e); + CommandDef *cmd = ece->cmd(); + if (cmd->menu_id == MenuSearchGroups){ + Group *grp = getContacts()->group(cmd->id - CmdContactGroup); + if (grp){ + Contact *contact = NULL; + if ((QWidget*)(cmd->param) == m_search->btnSearch){ + if (m_current){ + connect(this, SIGNAL(createContact(unsigned,SIM::Contact*&)), m_current, SLOT(createContact(unsigned,SIM::Contact*&))); + emit createContact(CONTACT_TEMP, contact); + disconnect(this, SIGNAL(createContact(unsigned,SIM::Contact*&)), m_current, SLOT(createContact(unsigned,SIM::Contact*&))); + } + }else{ + contact = createContact(CONTACT_TEMP); + } + if (contact){ + if ((contact->getFlags() & CONTACT_TEMP) == 0){ + QString err = i18n("%1 already in contact list") .arg(contact->getName()); + if ((QWidget*)(cmd->param) == m_search->btnAdd){ + BalloonMsg::message(err, m_search->btnAdd); + }else if ((QWidget*)(cmd->param) == m_search->btnSearch){ + BalloonMsg::message(err, m_search->btnSearch); + }else{ + BalloonMsg::message(err, m_result); + } + return true; + } + contact->setFlags(contact->getFlags() & ~CONTACT_TEMP); + contact->setGroup(grp->id()); + EventContact(contact, EventContact::eChanged).process(); + } + } + return true; + } + if (cmd->id == CmdSearchInfo){ + Contact *contact = createContact(CONTACT_TEMP); + if (contact == NULL) + return true; + Command cmd; + cmd->id = CmdInfo; + cmd->menu_id = MenuContact; + cmd->param = (void*)(contact->id()); + CorePlugin::instance()->showInfo(cmd); + return true; + } + if (cmd->id == CmdSearchMsg){ + Contact *contact = createContact(CONTACT_TEMP); + if (contact == NULL) + return true; + Message *m = new Message(MessageGeneric); + m->setContact(contact->id()); + EventOpenMessage(m).process(); + delete m; + } + break; + } + case eEventCheckCommandState:{ + EventCheckCommandState *ecs = static_cast(e); + CommandDef *cmd = ecs->cmd(); + if ((cmd->id == CmdSearchOptions) && (cmd->menu_id == MenuSearchItem)){ + EventMenuGetDef eMenu(MenuSearchOptions); + eMenu.process(); + CommandsDef *def = eMenu.defs(); + if (def){ + CommandsList list(*def, true); + CommandDef *s; + unsigned nItems = 0; + while ((s = ++list) != NULL) + nItems++; + if (nItems){ + CommandDef *cmds = new CommandDef[nItems * 2 + 1]; + list.reset(); + nItems = 0; + unsigned prev = 0; + while ((s = ++list) != NULL){ + if (s->flags & COMMAND_CHECK_STATE){ + CommandDef cCheck = *s; + if (!EventCheckCommandState(&cCheck).process()) + continue; + } + if (prev && ((prev & 0xFF00) != (s->menu_grp & 0xFF00))) + cmds[nItems++].text = "_"; + prev = s->menu_grp; + cmds[nItems++] = *s; + } + cmd->param = cmds; + cmd->flags |= COMMAND_RECURSIVE; + return true; + } + } + return false; + } + if ((cmd->id == CmdContactGroup) && (cmd->menu_id == MenuSearchGroups)){ + Group *grp; + ContactList::GroupIterator it; + unsigned nGrp = 0; + while ((grp = ++it) != NULL) + nGrp++; + it.reset(); + CommandDef *cmds = new CommandDef[nGrp + 1]; + nGrp = 0; + while ((grp = ++it) != NULL){ + if (grp->id() == 0) + continue; + cmds[nGrp].id = CmdContactGroup + grp->id(); + cmds[nGrp].menu_id = MenuSearchGroups; + cmds[nGrp].text = "_"; + cmds[nGrp].text_wrk = grp->getName(); + nGrp++; + } + cmds[nGrp].id = CmdContactGroup; + cmds[nGrp].menu_id = MenuSearchGroups; + cmds[nGrp].text = I18N_NOOP("Not in list"); + + cmd->param = cmds; + cmd->flags |= COMMAND_RECURSIVE; + return true; + } + break; + } + default: + break; + } + return false; +} + +void SearchDialog::textChanged(const QString&) +{ + if (m_active != NULL){ + m_search->btnSearch->setEnabled(true); + return; + } + bool bEnable = false; + checkSearch(m_current, bEnable) && checkSearch(m_currentResult, bEnable); + m_search->btnSearch->setEnabled(bEnable); +} + +bool SearchDialog::checkSearch(QWidget *w, bool &bEnable) +{ + if (w == NULL) + return true; + + const QList l = qFindChildren(w); + foreach(QWidget *obj,l){ + if ((obj->parent() == NULL) || + qobject_cast(obj->parent()) || + qobject_cast(obj->parent())) + continue; + + const QLineEdit *edit = qobject_cast(obj); + if (edit){ + if (edit->isEnabled()){ + if (!edit->text().isEmpty()){ + const QValidator *v = edit->validator(); + if (v){ + QString text = edit->text(); + int pos = 0; + if (v->validate(text, pos) == QValidator::Acceptable){ + bEnable = true; + }else{ + bEnable = false; + return false; + } + }else{ + bEnable = true; + } + } + } + continue; + } + const QComboBox *cmb = qobject_cast(obj); + if (cmb){ + if (cmb->isEnabled() && !cmb->currentText().isEmpty()) + bEnable = true; + continue; + } + } + return true; +} + +void SearchDialog::detach(QWidget *w) +{ + const QList l = qFindChildren(w); + foreach(QWidget *obj,l){ + if (qobject_cast(obj)) + disconnect(obj, SIGNAL(textChanged(const QString&)), this, SLOT(textChanged(const QString&))); + if (qobject_cast(obj)) + disconnect(obj, SIGNAL(activated(const QString&)), this, SLOT(textChanged(const QString&))); + if (qobject_cast(obj)) + disconnect(obj, SIGNAL(toggled(bool)), this, SLOT(toggled(bool))); + } +} + +void SearchDialog::attach(QWidget *w) +{ + if (w == NULL) + return; + const QList l = qFindChildren(w); + foreach(QWidget *obj,l){ + if (qobject_cast(obj)) + connect(obj, SIGNAL(textChanged(const QString&)), this, SLOT(textChanged(const QString&))); + if (qobject_cast(obj)) + connect(obj, SIGNAL(activated(const QString&)), this, SLOT(textChanged(const QString&))); + if (qobject_cast(obj)) + connect(obj, SIGNAL(toggled(bool)), this, SLOT(toggled(bool))); + } +} + +void SearchDialog::aboutToShow(QWidget *w) +{ + if (m_current) + detach(m_current); + m_current = w; + attach(m_current); + textChanged(); +} + +void SearchDialog::resultShow(QWidget *w) +{ + if (m_currentResult){ + if (m_currentResult != m_result) + disconnect(m_currentResult, SIGNAL(enableOptions(bool)), this, SLOT(enableOptions(bool))); + disconnect(m_currentResult, SIGNAL(destroyed()), this, SLOT(resultDestroyed())); + detach(m_currentResult); + } + m_currentResult = w; + attach(m_currentResult); + connect(m_currentResult, SIGNAL(destroyed()), this, SLOT(resultDestroyed())); + if (m_currentResult != m_result) + connect(m_currentResult, SIGNAL(enableOptions(bool)), this, SLOT(enableOptions(bool))); + textChanged(); +} + +void SearchDialog::resultDestroyed() +{ + m_currentResult = NULL; +} + +void SearchDialog::addResult(QWidget *w) +{ + m_result_id = m_search->wndResult->addWidget(w); +} + +void SearchDialog::showResult(QWidget *w) +{ + if (w == NULL) + w = m_result; + m_search->wndResult->setCurrentWidget(w); + selectionChanged(); +} + +const unsigned NO_GROUP = 0x10000; + +void SearchDialog::searchClick() +{ + if (m_bAdd){ + if (CorePlugin::instance()->value("GroupMode").toUInt()) + { + EventMenuProcess eMenu(MenuSearchGroups, m_search->btnSearch); + eMenu.process(); + QMenu *popup = eMenu.menu(); + if (popup) + popup->popup(CToolButton::popupPos(m_search->btnSearch, popup)); + } + else + { + Command cmd; + cmd->id = CmdContactGroup; + cmd->menu_id = MenuSearchGroups; + cmd->param = m_search->btnSearch; + EventCommandExec(cmd).process(); + } + return; + } + if (m_active){ + emit searchStop(); + searchDone(m_active); + return; + } + m_active = m_current; + m_result->clear(); + m_search->btnAdd->setEnabled(false); + m_search->btnOptions->setEnabled(false); + setAddButton(); + setStatus(); + m_bColumns = false; + connect(this, SIGNAL(search()), m_active, SLOT(search())); + connect(this, SIGNAL(searchStop()), m_active, SLOT(searchStop())); + connect(m_active, SIGNAL(setColumns(const QStringList&, int, QWidget*)), this, SLOT(setColumns(const QStringList&, int, QWidget*))); + connect(m_active, SIGNAL(addItem(const QStringList&,QWidget*)), this, SLOT(addItem(const QStringList&,QWidget*))); + connect(m_active, SIGNAL(searchDone(QWidget*)), this, SLOT(searchDone(QWidget*))); + emit search(); + m_result->setFocus(); +} + +void SearchDialog::setStatus() +{ + if (m_result == NULL) + return; + QString message = i18n("Search"); + if (m_result->firstChild()){ + message += ": "; + message += i18n("%n contact found", "%n contacts found", m_result->columnCount()); + } + m_status->showMessage(message); +} + +void SearchDialog::searchDone(QWidget*) +{ + if (m_active == NULL) + return; + m_status->clearMessage(); + disconnect(this, SIGNAL(search()), m_active, SLOT(search())); + disconnect(this, SIGNAL(searchStop()), m_active, SLOT(searchStop())); + disconnect(m_active, SIGNAL(setColumns(const QStringList&, int, QWidget*)), this, SLOT(setColumns(const QStringList&, int, QWidget*))); + disconnect(m_active, SIGNAL(addItem(const QStringList&,QWidget*)), this, SLOT(addItem(const QStringList&,QWidget*))); + disconnect(m_active, SIGNAL(searchDone(QWidget*)), this, SLOT(searchDone(QWidget*))); + m_active = NULL; + textChanged(); + setAddButton(); +} + +void SearchDialog::setColumns(const QStringList &columns, int n, QWidget*) +{ + int i; + if (!m_bColumns){ + m_result->setColumnCount(0); + /* + for (i = m_result->columnCount() - 1; i >= 0; i--) + m_result->removeColumn(i); + */ + m_bColumns = true; + } + for (i = 0; i < columns.count() / 2; i++) + m_result->addColumn(columns[2 * i + 1]); + m_result->setExpandingColumn(n); + m_result->adjustColumn(); +} + +class SearchViewItem : public ListViewItem +{ +public: +SearchViewItem(ListView *view) : ListViewItem(view) {} + QString key(int column, bool ascending) const; +}; + +QString SearchViewItem::key(int column, bool ascending) const +{ + /* + if (column) + return ListViewItem::key(column, ascending); + */ + QString res = text(COL_KEY); + return res; +} + +void SearchDialog::addItem(const QStringList &values, QWidget *wnd) +{ + ListViewItem *item = NULL; + for (int i = 0; i < m_result->topLevelItemCount(); i++){ + item = static_cast(m_result->topLevelItem(i)); + if (item->text(COL_KEY) == values[1]) + break; + } + if (item){ + QWidget *oldSearch = (QWidget*)(item->text(COL_SEARCH_WND).toULong()); + for (unsigned i = 0; i < m_widgets.size(); i++){ + if (m_widgets[i].widget == wnd){ + item->setText(COL_SEARCH_WND, QString::number((unsigned long)wnd)); + return; + } + if (m_widgets[i].widget == oldSearch) + return; + } + return; + } + if (m_update->isActive()){ + m_update->stop(); + }else{ + m_result->viewport()->setUpdatesEnabled(false); + } + item = new SearchViewItem(m_result); + item->setPixmap(0, Pict(values[0])); + item->setText(COL_KEY, values[1]); + for (int i = 2; i < values.count(); i++) + item->setText(i - 2, values[i]); + item->setText(COL_SEARCH_WND, QString::number((unsigned long)wnd)); + setStatus(); + m_update->start(500); +} + +void SearchDialog::update() +{ + m_update->stop(); + m_result->viewport()->setUpdatesEnabled(true); + m_result->viewport()->repaint(); + m_result->adjustColumn(); +} + +void SearchDialog::selectionChanged() +{ + if (m_result && ((m_currentResult == NULL) || (m_currentResult == m_result))){ + bool bEnable = (m_result->selectedItems().count() > 0); + enableOptions(bEnable); + } +} + +void SearchDialog::enableOptions(bool bEnable) +{ + m_search->btnAdd->setEnabled(bEnable); + m_search->btnOptions->setEnabled(bEnable); +} + +void SearchDialog::addClick() +{ + if (CorePlugin::instance()->value("GroupMode").toUInt()){ + EventMenuProcess eMenu(MenuSearchGroups, m_search->btnAdd); + eMenu.process(); + QMenu *popup = eMenu.menu(); + if (popup) + popup->popup(CToolButton::popupPos(m_search->btnAdd, popup)); + }else{ + Command cmd; + cmd->id = CmdContactGroup; + cmd->menu_id = MenuSearchGroups; + cmd->param = m_search->btnAdd; + EventCommandExec(cmd).process(); + } +} + +Contact *SearchDialog::createContact(unsigned flags) +{ + Contact *contact = NULL; + if (m_result->currentItem() == NULL) + return NULL; + QWidget *w = (QWidget*)(m_result->currentItem()->text(COL_SEARCH_WND).toULong()); + connect(this, SIGNAL(createContact(const QString&, unsigned, SIM::Contact*&)), w, SLOT(createContact(const QString&, unsigned, SIM::Contact*&))); + QString name = m_result->currentItem()->text(0); + emit createContact(name, flags, contact); + disconnect(this, SIGNAL(createContact(const QString&, unsigned, SIM::Contact*&)), w, SLOT(createContact(const QString&, unsigned, SIM::Contact*&))); + return contact; +} + +void SearchDialog::dragStart() +{ + Contact *contact = createContact(CONTACT_DRAG); + if (contact == NULL) + return; +// m_result->startDrag(new ContactDragObject(m_result, contact)); +} + +void SearchDialog::optionsClick() +{ + EventMenuProcess eMenu(MenuSearchOptions, NULL); + eMenu.process(); + QMenu *popup = eMenu.menu(); + if (popup) + popup->popup(CToolButton::popupPos(m_search->btnOptions, popup)); +} + +void SearchDialog::newSearch() +{ + searchStop(); + const QList l = qFindChildren(this); + foreach(QWidget *obj,l){ + QWidget *parent = static_cast(obj)->parentWidget(); + + QLineEdit *le = qobject_cast(obj); + if (le && parent && qobject_cast(parent) == NULL) + le->clear(); + + QComboBox *cb = qobject_cast(obj); + if (cb && parent && qobject_cast(parent) == NULL) + cb->setCurrentIndex(0); + } + m_result->clear(); + /* + for (int i = m_result->columnCount() - 1; i >= 0; i--) + m_result->removeColumn(i); + */ + m_result->setColumnCount(0); + m_result->addColumn(i18n("Results")); + m_result->setExpandingColumn(0); + m_result->adjustColumn(); +} + +void SearchDialog::addSearch(QWidget *w, Client *client, const QString &name) +{ + for (unsigned i = 0; i < m_widgets.size(); i++){ + if ((m_widgets[i].client == client) && (m_widgets[i].name == name)){ + delete w; + m_search->cmbClients->setCurrentIndex(i); + clientActivated(i); + return; + } + } + m_id = m_search->wndCondition->addWidget(w); + ClientWidget cw; + cw.widget = w; + cw.client = client; + cw.name = name; + m_widgets.push_back(cw); + m_search->cmbClients->addItem(Icon(client->protocol()->description()->icon), name); + m_search->cmbClients->setCurrentIndex(m_widgets.size() - 1); + clientActivated(m_widgets.size() - 1); +} + +void SearchDialog::showClient(Client *client) +{ + for (unsigned i = 0; i < m_widgets.size(); i++){ + if (m_widgets[i].client != client) + continue; + m_search->cmbClients->setCurrentIndex(i); + clientActivated(i); + return; + } +} diff --git a/plugins/_core/search.h b/plugins/_core/search.h new file mode 100644 index 0000000..e8015c3 --- /dev/null +++ b/plugins/_core/search.h @@ -0,0 +1,115 @@ +/*************************************************************************** + search.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _SEARCH_H +#define _SEARCH_H + +#include +#include "contacts.h" +#include "ui_searchbase.h" + +#include +#include +#include +#include + +class CorePlugin; +class ListView; +class SearchBase; +class QStatusBar; +class QTimer; + +struct ClientWidget +{ + SIM::Client *client; + QWidget *widget; + QString name; +}; + +class SearchWidget : public QWidget, public Ui::Search +{ + Q_OBJECT +public: + SearchWidget(QWidget* parent); +}; + +class SearchDialog : public QMainWindow, public SIM::EventReceiver +{ + Q_OBJECT +public: + SearchDialog(); + ~SearchDialog(); +public slots: + void setAdd(bool bAdd); + void clientActivated(int); + void aboutToShow(QWidget*); + void resultShow(QWidget*); + void resultDestroyed(); + void textChanged(const QString &txt = QString::null); + void toggled(bool); + void addResult(QWidget*); + void showResult(QWidget*); + void addSearch(QWidget*, SIM::Client*, const QString &name); + void showClient(SIM::Client*); +signals: + void finished(); + void search(); + void searchStop(); + void createContact(const QString&, unsigned tmpFlags, SIM::Contact *&contact); + void createContact(unsigned tmpFlags, SIM::Contact *&contact); +protected slots: + void searchClick(); + void setColumns(const QStringList&, int, QWidget*); + void addItem(const QStringList&, QWidget *search); + void searchDone(QWidget*); + void update(); + void addClick(); + void optionsClick(); + void selectionChanged(); + void dragStart(); + void newSearch(); + void enableOptions(bool); +protected: + std::vector m_widgets; + void setStatus(); + void setAddButton(); + ListView *m_result; + QWidget *m_current; + QWidget *m_currentResult; + QWidget *m_active; + virtual bool processEvent(SIM::Event*); + void resizeEvent(QResizeEvent*); + void moveEvent(QMoveEvent*); + void closeEvent(QCloseEvent*); + void fillClients(); + void attach(QWidget*); + void detach(QWidget*); + bool checkSearch(QWidget*, bool&); + SIM::Contact *createContact(unsigned flags); + void setTitle(); + bool m_bAdd; + bool m_bColumns; + unsigned m_id; + unsigned m_result_id; + SearchWidget *m_search; + QStatusBar *m_status; + QTimer *m_update; + friend class SearchAll; +}; + +#endif + diff --git a/plugins/_core/searchall.cpp b/plugins/_core/searchall.cpp new file mode 100644 index 0000000..05b9f81 --- /dev/null +++ b/plugins/_core/searchall.cpp @@ -0,0 +1,184 @@ +/*************************************************************************** + searchall.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "searchall.h" +#include "search.h" +#include "log.h" + +#include "contacts/client.h" +#include "simgui/intedit.h" + +#include +#include + +using namespace std; +using namespace SIM; + +SearchAll::SearchAll(QWidget *parent) : QWidget(parent) + //: SearchAllBase(parent) +{ + setupUi(this); + connect(this, SIGNAL(setAdd(bool)), topLevelWidget(), SLOT(setAdd(bool))); + edtMail->setValidator(new EMailValidator(edtMail)); +} + +void SearchAll::showEvent(QShowEvent *e) +{ + QWidget::showEvent(e); + emit setAdd(false); +} + +void SearchAll::wndDestroyed() +{ + QTimer::singleShot(0, this, SLOT(refresh())); +} + +void SearchAll::refresh() +{ + vector &widgets = static_cast(topLevelWidget())->m_widgets; + WND_MAP::iterator it; + for (it = m_searches.begin(); it != m_searches.end(); ){ + vector::iterator itw; + for (itw = widgets.begin(); itw != widgets.end(); ++itw) + if (it->first == itw->widget) + break; + if (itw != widgets.end()){ + ++it; + continue; + } + m_searches.erase(it); + } + if (m_searches.empty()) + emit searchDone(this); +} + +void SearchAll::search() +{ + if (grpMail->isChecked() && !edtMail->text().isEmpty()){ + if (!makeSearches()) + return; + emit searchMail(edtMail->text()); + } + if(grpName->isChecked() && makeSearches()) + emit searchName(edtFirst->text(), edtLast->text(), edtNick->text()); +} + +void SearchAll::searchStop() +{ + emit sSearchStop(); + for (WND_MAP::iterator it = m_searches.begin(); it != m_searches.end(); ++it){ + disconnect(this, SIGNAL(sSearchStop()), it->first, SLOT(searchStop())); + disconnect(this, SIGNAL(searchMail(const QString&)), it->first, SLOT(searchMail(const QString&))); + disconnect(this, SIGNAL(searchName(const QString&, const QString&, const QString&)), it->first, SLOT(searchName(const QString&, const QString&, const QString&))); + disconnect(it->first, SIGNAL(searchDone(QWidget*)), this, SLOT(slotSearchDone(QWidget*))); + disconnect(it->first, SIGNAL(setColumns(const QStringList&, int, QWidget*)), this, SLOT(slotSetColumns(const QStringList&, int, QWidget*))); + disconnect(it->first, SIGNAL(addItem(const QStringList&, QWidget*)), this, SLOT(slotAddItem(const QStringList&, QWidget*))); + } +} + +bool SearchAll::makeSearches() +{ + m_searches.clear(); + m_attrs.clear(); + vector &widgets = static_cast(topLevelWidget())->m_widgets; + for (unsigned i = 0; i < widgets.size(); i++){ + if ((widgets[i].client == NULL) || (widgets[i].client == (Client*)(-1))) + continue; + if ((widgets[i].client->protocol()->description()->flags & PROTOCOL_SEARCH) == 0) + continue; + connect(this, SIGNAL(sSearchStop()), widgets[i].widget, SLOT(searchStop())); + connect(this, SIGNAL(searchMail(const QString&)), widgets[i].widget, SLOT(searchMail(const QString&))); + connect(this, SIGNAL(searchName(const QString&, const QString&, const QString&)), widgets[i].widget, SLOT(searchName(const QString&, const QString&, const QString&))); + connect(widgets[i].widget, SIGNAL(searchDone(QWidget*)), this, SLOT(slotSearchDone(QWidget*))); + connect(widgets[i].widget, SIGNAL(setColumns(const QStringList&, int, QWidget*)), this, SLOT(slotSetColumns(const QStringList&, int, QWidget*))); + connect(widgets[i].widget, SIGNAL(addItem(const QStringList&, QWidget*)), this, SLOT(slotAddItem(const QStringList&, QWidget*))); + QStringList l; + m_searches.insert(WND_MAP::value_type(widgets[i].widget, l)); + } + return m_searches.size() > 0; +} + +void SearchAll::slotSearchDone(QWidget *w) +{ + WND_MAP::iterator it = m_searches.find(w); + if (it == m_searches.end()) + return; + m_searches.erase(it); + disconnect(this, SIGNAL(sSearchStop()), w, SLOT(searchStop())); + disconnect(this, SIGNAL(searchMail(const QString&)), w, SLOT(searchMail(const QString&))); + disconnect(this, SIGNAL(searchName(const QString&, const QString&, const QString&)), w, SLOT(searchName(const QString&, const QString&, const QString&))); + disconnect(w, SIGNAL(searchDone(QWidget*)), this, SLOT(slotSearchDone(QWidget*))); + disconnect(w, SIGNAL(setColumns(const QStringList&, int, QWidget*)), this, SLOT(slotSetColumns(const QStringList&, int, QWidget*))); + disconnect(w, SIGNAL(addItem(const QStringList&, QWidget*)), this, SLOT(slotAddItem(const QStringList&, QWidget*))); + if (m_searches.empty()) + emit searchDone(this); +} + +void SearchAll::slotSetColumns(const QStringList &attrs, int, QWidget *w) +{ + WND_MAP::iterator it = m_searches.find(w); + if (it == m_searches.end()) + return; + int i; + for (i = 0; i < attrs.count() / 2; i++) + it->second.append(attrs[2 * i]); + QStringList newAttrs; + for (i = 0; i < attrs.count() / 2; i++){ + QString attr = attrs[i * 2]; + int n; + for (n = 0; n < m_attrs.count(); n++) + if (m_attrs[n] == attr) + break; + if (n < m_attrs.count()) + continue; + m_attrs.append(attr); + newAttrs.append(attr); + newAttrs.append(attrs[i * 2 + 1]); + } + if (newAttrs.count() == 0) + return; + emit setColumns(newAttrs, 0, this); +} + +void SearchAll::slotAddItem(const QStringList &attrs, QWidget *w) +{ + WND_MAP::iterator it = m_searches.find(w); + if (it == m_searches.end()) + return; + QStringList la; + la.append(attrs[0]); + la.append(attrs[1]); + for (int i = 0; i < m_attrs.count(); i++){ + QString attr = m_attrs[i]; + QString v; + for (int n = 0; n < it->second.count(); n++){ + if (it->second[n] == attr){ + v = attrs[n + 2]; + break; + } + } + la.append(v); + } + emit addItem(la, w); +} + +/* +#ifndef NO_MOC_INCLUDES +#include "searchall.moc" +#endif +*/ + diff --git a/plugins/_core/searchall.h b/plugins/_core/searchall.h new file mode 100644 index 0000000..95fb616 --- /dev/null +++ b/plugins/_core/searchall.h @@ -0,0 +1,59 @@ +/*************************************************************************** + searchall.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _SEARCHALL_H +#define _SEARCHALL_H + +#ifdef __OS2__ // to make it compileable under OS/2 (gcc 3.3.5) +#include "simapi.h" +#endif +#include "ui_searchallbase.h" + +#include + +typedef std::map WND_MAP; + +class SearchAll : public QWidget, public Ui::SearchAll +{ + Q_OBJECT +public: + SearchAll(QWidget *parent); +signals: + void setAdd(bool); + void searchName(const QString &first, const QString &last, const QString &nick); + void searchMail(const QString &mail); + void setColumns(const QStringList&, int, QWidget*); + void addItem(const QStringList&, QWidget*); + void searchDone(QWidget*); + void sSearchStop(); +protected slots: + void search(); + void searchStop(); + void wndDestroyed(); + void refresh(); + void slotSearchDone(QWidget*); + void slotSetColumns(const QStringList&, int, QWidget*); + void slotAddItem(const QStringList&, QWidget*); +protected: + void showEvent(QShowEvent*); + bool makeSearches(); + WND_MAP m_searches; + QStringList m_attrs; +}; + +#endif + diff --git a/plugins/_core/searchallbase.ui b/plugins/_core/searchallbase.ui new file mode 100644 index 0000000..f17bbf3 --- /dev/null +++ b/plugins/_core/searchallbase.ui @@ -0,0 +1,131 @@ + + + SearchAll + + + + 0 + 0 + 373 + 369 + + + + Form4 + + + + 6 + + + 0 + + + + + true + + + false + + + &E-Mail + + + + 6 + + + 11 + + + + + + + + + + + true + + + false + + + &Name + + + + 6 + + + 11 + + + + + First: + + + false + + + + + + + + + + Last: + + + false + + + + + + + + + + Nick: + + + false + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + grpMail + grpName + groupBox + groupBox_2 + + + + diff --git a/plugins/_core/searchbase.ui b/plugins/_core/searchbase.ui new file mode 100644 index 0000000..680038d --- /dev/null +++ b/plugins/_core/searchbase.ui @@ -0,0 +1,99 @@ + + + Search + + + + 0 + 0 + 614 + 451 + + + + Search + + + + 11 + + + 6 + + + + + &Add to list + + + + + + + + + + + + + true + + + + + + + More &options + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + &New search + + + + + + + + + + + + + + + + + + + btnSearch + btnNew + btnOptions + btnAdd + cmbClients + + + + diff --git a/plugins/_core/smiles/Angel.png b/plugins/_core/smiles/Angel.png new file mode 100644 index 0000000..aa8e871 Binary files /dev/null and b/plugins/_core/smiles/Angel.png differ diff --git a/plugins/_core/smiles/Angry.png b/plugins/_core/smiles/Angry.png new file mode 100644 index 0000000..5804a2a Binary files /dev/null and b/plugins/_core/smiles/Angry.png differ diff --git a/plugins/_core/smiles/Annoyed.png b/plugins/_core/smiles/Annoyed.png new file mode 100644 index 0000000..b03a2e9 Binary files /dev/null and b/plugins/_core/smiles/Annoyed.png differ diff --git a/plugins/_core/smiles/Cool.png b/plugins/_core/smiles/Cool.png new file mode 100644 index 0000000..763ff64 Binary files /dev/null and b/plugins/_core/smiles/Cool.png differ diff --git a/plugins/_core/smiles/Crying.png b/plugins/_core/smiles/Crying.png new file mode 100644 index 0000000..8a37b12 Binary files /dev/null and b/plugins/_core/smiles/Crying.png differ diff --git a/plugins/_core/smiles/Embarrassed.png b/plugins/_core/smiles/Embarrassed.png new file mode 100644 index 0000000..10473e6 Binary files /dev/null and b/plugins/_core/smiles/Embarrassed.png differ diff --git a/plugins/_core/smiles/Grin.png b/plugins/_core/smiles/Grin.png new file mode 100644 index 0000000..79ad029 Binary files /dev/null and b/plugins/_core/smiles/Grin.png differ diff --git a/plugins/_core/smiles/Indifferent.png b/plugins/_core/smiles/Indifferent.png new file mode 100644 index 0000000..bb15064 Binary files /dev/null and b/plugins/_core/smiles/Indifferent.png differ diff --git a/plugins/_core/smiles/Kiss.png b/plugins/_core/smiles/Kiss.png new file mode 100644 index 0000000..3b43494 Binary files /dev/null and b/plugins/_core/smiles/Kiss.png differ diff --git a/plugins/_core/smiles/Sad.png b/plugins/_core/smiles/Sad.png new file mode 100644 index 0000000..1ed065d Binary files /dev/null and b/plugins/_core/smiles/Sad.png differ diff --git a/plugins/_core/smiles/Skeptical.png b/plugins/_core/smiles/Skeptical.png new file mode 100644 index 0000000..5df3974 Binary files /dev/null and b/plugins/_core/smiles/Skeptical.png differ diff --git a/plugins/_core/smiles/Smile.png b/plugins/_core/smiles/Smile.png new file mode 100644 index 0000000..2af912d Binary files /dev/null and b/plugins/_core/smiles/Smile.png differ diff --git a/plugins/_core/smiles/Surprised.png b/plugins/_core/smiles/Surprised.png new file mode 100644 index 0000000..089bfc4 Binary files /dev/null and b/plugins/_core/smiles/Surprised.png differ diff --git a/plugins/_core/smiles/Teaser.png b/plugins/_core/smiles/Teaser.png new file mode 100644 index 0000000..f33b01d Binary files /dev/null and b/plugins/_core/smiles/Teaser.png differ diff --git a/plugins/_core/smiles/Uptight.png b/plugins/_core/smiles/Uptight.png new file mode 100644 index 0000000..309944a Binary files /dev/null and b/plugins/_core/smiles/Uptight.png differ diff --git a/plugins/_core/smiles/Wink.png b/plugins/_core/smiles/Wink.png new file mode 100644 index 0000000..d5a97ed Binary files /dev/null and b/plugins/_core/smiles/Wink.png differ diff --git a/plugins/_core/smiles/icondef.xml b/plugins/_core/smiles/icondef.xml new file mode 100644 index 0000000..d124ebc --- /dev/null +++ b/plugins/_core/smiles/icondef.xml @@ -0,0 +1,97 @@ + + + + SIM smiles + 0.9.6 + SIM smiles. + Vladimir Shutoff + 2004-06-11 + http://sim-im.org/ + + + :-) + :) + =) + Smile.png + + + :-0 + :-O + :=0 + :=O + Surprised.png + + + :-| + :-! + Indifferent.png + + + :-/ + :-\ + Skeptical.png + + + :-( + :( + Sad.png + + + :-{} + :{} + Kiss.png + + + :*) + Annoyed.png + + + :'-( + :'( + Crying.png + + + ;-) + ;) + Wink.png + + + :-@ + >:0 + >:O + >:o + Angry.png + + + :-") + :-[ + :-< + :< + Embarrassed.png + + + :-X + :-x + Uptight.png + + + :-P + Teaser.png + + + 8-) + Cool.png + + + 0:-) + O:-) + 0-) + O-) + Angel.png + + + :-D + :D + Grin.png + + diff --git a/plugins/_core/smscfg.cpp b/plugins/_core/smscfg.cpp new file mode 100644 index 0000000..c194128 --- /dev/null +++ b/plugins/_core/smscfg.cpp @@ -0,0 +1,37 @@ +/*************************************************************************** + smscfg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "smscfg.h" +#include "core.h" + +#include + +SMSConfig::SMSConfig(QWidget *parent, SIM::PropertyHubPtr data) : QWidget(parent) +{ + setupUi(this); + edtBefore->setPlainText(data->value("SMSSignatureBefore").toString()); + edtAfter->setPlainText(data->value("SMSSignatureAfter").toString()); +} + +void SMSConfig::apply(SIM::PropertyHubPtr data) +{ + data->setValue("SMSSignatureBefore", edtBefore->toPlainText()); + data->setValue("SMSSignatureAfter", edtAfter->toPlainText()); +} + +// vim: set expandtab: + diff --git a/plugins/_core/smscfg.h b/plugins/_core/smscfg.h new file mode 100644 index 0000000..3975512 --- /dev/null +++ b/plugins/_core/smscfg.h @@ -0,0 +1,34 @@ +/*************************************************************************** + smscfg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _SMSCFG_H +#define _SMSCFG_H + +#include "propertyhub.h" +#include "ui_smscfgbase.h" + +class SMSConfig : public QWidget, public Ui::SMSConfig +{ + Q_OBJECT +public: + SMSConfig(QWidget *parent, SIM::PropertyHubPtr data); +public slots: + void apply(SIM::PropertyHubPtr ); +}; + +#endif + diff --git a/plugins/_core/smscfgbase.ui b/plugins/_core/smscfgbase.ui new file mode 100644 index 0000000..0122d38 --- /dev/null +++ b/plugins/_core/smscfgbase.ui @@ -0,0 +1,59 @@ + + + SMSConfig + + + + 0 + 0 + 321 + 274 + + + + Form1 + + + + 6 + + + 11 + + + + + Text before cursor: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + false + + + + + + + + + + Text after cursor: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + false + + + + + + + + + + + diff --git a/plugins/_core/status.cpp b/plugins/_core/status.cpp new file mode 100644 index 0000000..87f0cd7 --- /dev/null +++ b/plugins/_core/status.cpp @@ -0,0 +1,554 @@ +/*************************************************************************** + status.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include + +#include +#include +#include + +#include "unquot.h" +#include "status.h" +#include "core.h" +#include "statuswnd.h" +#include "logindlg.h" +#include "autoreply.h" + +#include "contacts/client.h" +#include "socket/socket.h" +#include "socket/socketfactory.h" +#include "clientmanager.h" +#include "simgui/ballonmsg.h" + +using namespace std; +using namespace SIM; + +typedef map MAP_STATUS; + +CommonStatus::CommonStatus() + : EventReceiver(LowPriority + 2) +{ + m_bBlink = false; + m_timer = NULL; + m_balloon = NULL; + + EventMenu(MenuStatus, EventMenu::eAdd).process(); + + Command cmd; + cmd->id = CmdStatusMenu; + cmd->text = I18N_NOOP("Status"); + cmd->menu_id = MenuMain; + cmd->menu_grp = 0x6000; + cmd->popup_id = MenuStatus; + cmd->flags = COMMAND_IMPORTANT; + + EventCommandCreate(cmd).process(); + + m_bInitialized = false; + rebuildStatus(); + QTimer::singleShot(500, this, SLOT(setBarStatus())); +} + +CommonStatus::~CommonStatus() +{ + EventCommandRemove(CmdStatusBar).process(); + EventMenu(MenuStatus, EventMenu::eRemove).process(); +} + +void CommonStatus::setBarStatus() +{ + QString text = I18N_NOOP("Inactive"); + QString icon = "SIM_inactive"; + + m_bConnected = false; + bool bActive = getSocketFactory()->isActive(); + if (!bActive) + for (unsigned i = 0; i < getContacts()->nClients(); i++) + { + Client *client = getContacts()->getClient(i); + if (client->getState() != Client::Connected) + continue; + + bActive = true; + break; + } + + if (bActive) + { + m_bConnected = false; + for (unsigned i = 0; i < getContacts()->nClients(); i++) + { + Client *client = getContacts()->getClient(i); + if (!client->getCommonStatus() || (client->getState() != Client::Connecting)) + continue; + + m_bConnected = true; + break; + } + if (m_bConnected) + { + text = I18N_NOOP("Connecting"); + Client *client = getContacts()->getClient(0); + Protocol *protocol = NULL; + if (client) + protocol = client->protocol(); + if (m_timer == NULL){ + m_timer = new QTimer(this); + connect(m_timer, SIGNAL(timeout()), this, SLOT(timeout())); + m_timer->start(1000); + m_bBlink = false; + } + unsigned status; + if (m_bBlink) + { + icon = "SIM_online"; + status = CorePlugin::instance()->getManualStatus(); + } + else + { + icon = "SIM_offline"; + status = STATUS_OFFLINE; + } + } + else + { + if (m_timer) + { + delete m_timer; + m_timer = NULL; + } + unsigned status = CorePlugin::instance()->getManualStatus(); + unsigned i; + for (i = 0; i < getContacts()->nClients(); i++){ + Client *client = getContacts()->getClient(i); + if (!client->getCommonStatus()) + continue; + if (client->getState() == Client::Error){ + icon = "SIM_error"; + text = I18N_NOOP("Error"); + break; + } + } + if (i >= getContacts()->nClients()){ + Client *client = getContacts()->getClient(0); + if (client) + { + const CommandDef *d; + unsigned i = getContacts()->nClients(); + if ((status == STATUS_ONLINE) && CorePlugin::instance()->value("Invisible").toBool()) + for (i = 0; i < getContacts()->nClients(); i++) + { + Client *client = getContacts()->getClient(i); + if (!(client->protocol()->description()->flags & PROTOCOL_INVISIBLE)) + continue; + + icon = "SIM_invisible"; + text = I18N_NOOP("&Invisible"); + break; + } + if (i >= getContacts()->nClients()) + { + for (d = client->protocol()->statusList(); !d->text.isEmpty(); d++) + { + if (d->id != status) + continue; + + if (status == STATUS_ONLINE) + icon = "SIM_online"; + else if (status == STATUS_AWAY) + icon = "SIM_away"; + else if (status == STATUS_NA) + icon = "SIM_na"; + else if (status == STATUS_DND) + icon = "SIM_dnd"; + else if (status == STATUS_OCCUPIED) + icon = "SIM_occupied"; + else if (status == STATUS_FFC) + icon = "SIM_ffc"; + else if (status == STATUS_OFFLINE) + icon = "SIM_offline"; + text = d->text; + break; + } + } + } + } + } + } + + Command cmd; + cmd->id = CmdStatusBar; + cmd->text = text; + cmd->icon = icon; + cmd->bar_id = ToolBarMain; + cmd->bar_grp = 0x6000; + cmd->popup_id = MenuStatus; + cmd->flags = BTN_PICT; + + if (m_bInitialized) + EventCommandChange(cmd).process(); + else + EventCommandCreate(cmd).process(); + + m_bInitialized = true; + + EventSetMainIcon(icon).process(); + EventSetMainText(text).process(); +} + +void CommonStatus::timeout() +{ + m_bBlink = !m_bBlink; + setBarStatus(); +} + +void CommonStatus::rebuildStatus() +{ + MAP_STATUS status; + unsigned nClients = getContacts()->nClients(); + if (nClients == 0) + return; + int nInvisible = -1; + for (unsigned i = 0; i < nClients; i++){ + Client *client = getContacts()->getClient(i); + for (const CommandDef *cmd = client->protocol()->statusList(); !cmd->text.isEmpty(); cmd++) + { + MAP_STATUS::iterator it = status.find(cmd->id); + if (it == status.end()) + status.insert(MAP_STATUS::value_type(cmd->id, 1)); + else + it->second++; + } + if (!(nInvisible == -1 && client->protocol()->description()->flags & PROTOCOL_INVISIBLE)) + continue; + + nInvisible = i; + } + if (nInvisible != -1) + { + Command cmd; + cmd->id = CmdInvisible; + cmd->text = I18N_NOOP("&Invisible"); + cmd->icon = "SIM_invisible"; + cmd->menu_id = MenuStatus; + cmd->menu_grp = 0x2000; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + } + Client *client = getContacts()->getClient(0); + unsigned id = 0x1000; + unsigned long FirstStatus = 0; + unsigned long ManualStatus = 0; + for (const CommandDef *cmd = client->protocol()->statusList(); !cmd->text.isEmpty(); cmd++) + { + MAP_STATUS::iterator it = status.find(cmd->id); + if (it == status.end()) + continue; + if (it->second != nClients) + continue; + CommandDef c = *cmd; + if (FirstStatus == 0) + FirstStatus = cmd->id; + if ((ManualStatus == 0) && (CorePlugin::instance()->getManualStatus() == cmd->id)) + ManualStatus = cmd->id; + if (c.id == STATUS_ONLINE) + c.icon = "SIM_online"; + else if (c.id == STATUS_AWAY) + c.icon = "SIM_away"; + else if (c.id == STATUS_NA) + c.icon = "SIM_na"; + else if (c.id == STATUS_DND) + c.icon = "SIM_dnd"; + else if (c.id == STATUS_OCCUPIED) + c.icon = "SIM_occupied"; + else if (c.id == STATUS_FFC) + c.icon = "SIM_ffc"; + else if (c.id == STATUS_OFFLINE) + c.icon = "SIM_offline"; + c.menu_id = MenuStatus; + c.menu_grp = id++; + c.flags = COMMAND_CHECK_STATE; + EventCommandCreate(&c).process(); + } + if (ManualStatus == 0) + ManualStatus = FirstStatus; + CorePlugin::instance()->setManualStatus(ManualStatus); + setBarStatus(); +} + +void CommonStatus::checkInvisible() +{ + bool bAllInvisible = true; + bool bAllNotInvisible = true; + for (unsigned i = 0; i < getContacts()->nClients(); i++) + { + Client *client = getContacts()->getClient(i); + if (!(client->protocol()->description()->flags & PROTOCOL_INVISIBLE)) + continue; + + if (client->getInvisible()) + bAllNotInvisible = false; + else + bAllInvisible = false; + } + + if (bAllNotInvisible && bAllInvisible) + return; + + if (bAllInvisible) + CorePlugin::instance()->setValue("Invisible", true); + if (bAllNotInvisible) + CorePlugin::instance()->setValue("Invisible", false); +} + +bool CommonStatus::processEvent(Event *e) +{ + switch (e->type()) + { + case eEventClientChanged: + checkInvisible(); + setBarStatus(); + break; + case eEventShowNotification: + { + EventShowNotification *ee = static_cast(e); + const EventNotification::ClientNotificationData &data = ee->data(); + for (list::iterator it = m_queue.begin(); it != m_queue.end(); ++it) + if (it->id == data.id) + return true; + BalloonItem item; + item.id = data.id; + item.client = data.client; + item.text = i18n(data.text); + if (!data.args.isEmpty()) + if (item.text.indexOf("%1") >= 0) + item.text = item.text.arg(data.args); + QString title = "SIM"; + if (getContacts()->nClients() > 1) + for (unsigned i = 0; i < getContacts()->nClients(); i++) + if (getContacts()->getClient(i) == data.client) + { + title = data.client->name(); + int n = title.indexOf("."); + if (n > 0) + title = title.left(n) + ' ' + title.mid(n + 1); + break; + } + item.text = QString(" %2
") + .arg((data.flags & EventNotification::ClientNotificationData::E_INFO) ? "info" : "error") + .arg(title) + quoteString(item.text) + "
"; + if (data.options.isEmpty()) + item.buttons.append(i18n("OK")); + else { + QStringList sl = data.options.split(QLatin1Char('\0')); + Q_FOREACH(const QString &s, sl) + item.buttons.append(i18n(s)); + } + m_queue.push_back(item); + if (m_balloon == NULL) + showBalloon(); + break; + } + case eEventClientNotification: + { + EventClientNotification *ee = static_cast(e); + const EventNotification::ClientNotificationData &data = ee->data(); + if (data.code == AuthError) + { + QString msg; + if (!data.text.isEmpty()) + msg = i18n(data.text).arg(data.args); + ClientPtr client = SIM::getClientManager()->client(data.client->name()); + LoginDialog *loginDlg = new LoginDialog(false, client, msg, NULL); + raiseWindow(loginDlg); + } + else + { + EventShowNotification eShow(data); + eShow.process(); + } + return true; + } + case eEventClientStatus: + case eEventSocketActive: + case eEventInit: + setBarStatus(); + break; + case eEventClientsChanged: + { + bool bCommon = false; + for (unsigned i = 0; i < getContacts()->nClients(); i++) + { + Client *client = getContacts()->getClient(i); + if (client->getCommonStatus()) + bCommon = true; + } + if (!bCommon) + { + Client *client = getContacts()->getClient(0); + if (client) + { + client->setCommonStatus(true); + EventClientChanged(client).process(); + } + } + checkInvisible(); + rebuildStatus(); + break; + } + case eEventCheckCommandState: + { + EventCheckCommandState *ecs = static_cast(e); + CommandDef *def = ecs->cmd(); + if (def->menu_id == MenuStatus) + { + if (def->id == CmdInvisible) + { + if (CorePlugin::instance()->value("Invisible").toBool()) + def->flags |= COMMAND_CHECKED; + else + def->flags &= ~COMMAND_CHECKED; + return true; + } + Client *client = getContacts()->getClient(0); + if (client == NULL) + return 0; + const CommandDef *curStatus = NULL; + const CommandDef *d; + for (d = client->protocol()->statusList(); !d->text.isEmpty(); d++) + if (d->id == def->id) + curStatus = d; + if (curStatus == NULL) + return 0; + bool bChecked = false; + unsigned status = CorePlugin::instance()->getManualStatus(); + bChecked = (status == curStatus->id); + + if (bChecked) + def->flags |= COMMAND_CHECKED; + else + def->flags &= ~COMMAND_CHECKED; + return true; + } + return 0; + } + case eEventCommandExec:{ + EventCommandExec *ece = static_cast(e); + CommandDef *def = ece->cmd(); + if (def->menu_id == MenuStatus) + { + if (def->id == CmdInvisible) + { + CorePlugin::instance()->setValue("Invisible", !CorePlugin::instance()->value("Invisible").toBool()); + for (unsigned i = 0; i < getContacts()->nClients(); i++) + getContacts()->getClient(i)->setInvisible(CorePlugin::instance()->value("Invisible").toBool()); + return true; + } + Client *client = getContacts()->getClient(0); + if (client == NULL) + return 0; + const CommandDef *curStatus = NULL; + const CommandDef *d; + for (d = client->protocol()->statusList(); !d->text.isEmpty(); d++) + if (d->id == def->id) + curStatus = d; + if (curStatus == NULL) + return false; + bool bOfflineStatus = false; + for (unsigned i = 0; i < getContacts()->nClients(); i++) + { + Client *client = getContacts()->getClient(i); + if (!(client->getCommonStatus() && client->protocol()->description()->flags & PROTOCOL_AR_OFFLINE)) + continue; + + bOfflineStatus = true; + break; + } + + if (bOfflineStatus || + (def->id != STATUS_ONLINE && def->id != STATUS_OFFLINE)){ + QString noShow = CorePlugin::instance()->propertyHub()->stringMapValue("NoShowAutoReply", def->id); + if (noShow.isEmpty()) + { + AutoReplyDialog dlg(def->id); + if (!dlg.exec()) + return true; + } + } + CorePlugin::instance()->setManualStatus(def->id); + for (unsigned i = 0; i < getContacts()->nClients(); i++) + { + Client *client = getContacts()->getClient(i); + if (client->getCommonStatus()) + client->setStatus(def->id, true); + } + return true; + } + break; + } + default: + break; + } + return false; +} + +void CommonStatus::showBalloon() +{ + if (m_balloon || m_queue.empty()) + return; + Command cmd; + cmd->id = CmdStatusBar; + EventCommandWidget eWidget(cmd); + eWidget.process(); + QWidget *widget = eWidget.widget(); + if (widget == NULL){ + m_queue.erase(m_queue.begin()); + return; + } + BalloonItem &item = m_queue.front(); + if (CorePlugin::instance()->m_statusWnd) + m_balloon = CorePlugin::instance()->m_statusWnd->showError(item.text, item.buttons, item.client); + if (m_balloon == NULL) + m_balloon = new BalloonMsg(NULL, item.text, item.buttons, widget); + connect(m_balloon, SIGNAL(yes_action(void*)), this, SLOT(yes_action(void*))); + connect(m_balloon, SIGNAL(finished()), this, SLOT(finished())); + raiseWindow(widget->topLevelWidget()); + m_balloon->show(); +} + +void CommonStatus::yes_action(void*) +{ + if (!m_queue.empty() && m_balloon) + { + m_balloon->hide(); + BalloonItem &item = m_queue.front(); + Command cmd; + cmd->id = item.id; + cmd->param = item.client; + EventCommandExec(cmd).process(); + } +} + +void CommonStatus::finished() +{ + m_balloon = NULL; + if (!m_queue.empty()) + m_queue.erase(m_queue.begin()); + QTimer::singleShot(1000, this, SLOT(showBalloon())); +} + diff --git a/plugins/_core/status.h b/plugins/_core/status.h new file mode 100644 index 0000000..ddff721 --- /dev/null +++ b/plugins/_core/status.h @@ -0,0 +1,68 @@ +/*************************************************************************** + status.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _STATUS_H +#define _STATUS_H + +#include + +#include +#include +#include + +#include "event.h" + +using namespace std; + +class QTimer; +class CorePlugin; +class BalloonMsg; + +struct BalloonItem +{ + QString text; + QStringList buttons; + unsigned id; + SIM::Client *client; +}; + +class CommonStatus : public QObject, public SIM::EventReceiver +{ + Q_OBJECT +public: + CommonStatus(); + ~CommonStatus(); +protected slots: + void timeout(); + void setBarStatus(); + void yes_action(void*); + void finished(); + void showBalloon(); +protected: + QTimer *m_timer; + virtual bool processEvent(SIM::Event*); + void rebuildStatus(); + void checkInvisible(); + bool m_bInitialized; + bool m_bBlink; + bool m_bConnected; + BalloonMsg *m_balloon; + list m_queue; +}; + +#endif + diff --git a/plugins/_core/statuswnd.cpp b/plugins/_core/statuswnd.cpp new file mode 100644 index 0000000..f28c35b --- /dev/null +++ b/plugins/_core/statuswnd.cpp @@ -0,0 +1,388 @@ +/*************************************************************************** + statuswnd.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "icons.h" +#include "statuswnd.h" +#include "core.h" +#include "log.h" + +#include "contacts/client.h" +#include "socket/socket.h" +#include "socket/socketfactory.h" +#include "simgui/ballonmsg.h" +#include "simgui/toolbtn.h" + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace SIM; + +StatusLabel::StatusLabel(QWidget *parent, Client *client, unsigned id) + : QLabel(parent) +{ + m_client = client; + m_bBlink = false; + m_id = id; + m_blinkTimer = NULL; + setPict(); +} + +void StatusLabel::startBlinkTimer() +{ + if (m_blinkTimer == NULL) { + m_blinkTimer = new QTimer(this); + connect(m_blinkTimer, SIGNAL(timeout()), this, SLOT(timeout())); + m_blinkTimer->start(1000); + m_bBlink = false; + } +} + +void StatusLabel::stopBlinkTimer() +{ + if (m_blinkTimer) { + delete m_blinkTimer; + m_blinkTimer = NULL; + } +} + +void StatusLabel::setPict() +{ + QIcon icon; + QString text; + if (m_client->getState() == Client::Connecting) { + if (getSocketFactory()->isActive()) { + IMStatusPtr status; + startBlinkTimer(); + text = I18N_NOOP("Connecting"); + if(m_client->protocol()) { + if (m_bBlink) { + status = m_client->currentStatus(); + } else { + status = m_client->protocol()->status("offline"); + } + icon = status->icon(); + } else { + icon = m_bBlink ? Icon("online") : Icon("offline"); + } + } else { + stopBlinkTimer(); + // TODO retreive appropriate icon + icon = Icon("inactive"); + text = I18N_NOOP("Inactive"); + } + } + else + { + stopBlinkTimer(); + if (m_client->getState() == Client::Error) { + icon = Icon("error"); + text = I18N_NOOP("Error"); + } else { + icon = m_client->currentStatus()->icon(); + text = m_client->currentStatus()->name(); + } + } + QPixmap p = icon.pixmap(size()); + setPixmap(p); + QString tip = CorePlugin::instance()->clientName(m_client); + tip += '\n'; + tip += i18n(text); + setToolTip(tip); + resize(p.width(), p.height()); + setFixedSize(p.width(), p.height()); +} + +void StatusLabel::timeout() +{ + m_bBlink = !m_bBlink; + setPict(); +} + +void StatusLabel::fillStatusMenu(QMenu& menu) +{ + menu.clear(); + menu.setTitle(m_client->name()); + QStringList statusNames = m_client->protocol()->statuses(); + foreach(const QString& statusId, statusNames) { + IMStatusPtr status = m_client->protocol()->status(statusId); + QAction* action = menu.addAction(status->icon(), status->name()); + action->setProperty("status_id", status->id()); + } +} + +void StatusLabel::mousePressEvent(QMouseEvent *me) +{ + if(me->button() == Qt::RightButton) + { + QMenu statusMenu; + fillStatusMenu(statusMenu); + if(!statusMenu.isEmpty()) { + QAction* action = statusMenu.exec(CToolButton::popupPos(this, &statusMenu)); + if(action) { + IMStatusPtr status = m_client->protocol()->status(action->property("status_id").toString()); + if(!status) + { + log(L_WARN, "Invalid status requested: %s (%s)", qPrintable(action->property("status_id").toString()), qPrintable(m_client->name())); + return; + } + CorePlugin::instance()->changeClientStatus(m_client, status); + } + } + } +} + +StatusFrame::StatusFrame(QWidget *parent) : QFrame(parent), EventReceiver(LowPriority + 1) +{ + log(L_DEBUG, "StatusFrame::StatusFrame()"); + setFrameStyle(NoFrame); + setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); + m_frame = new QFrame(this); + m_frame->show(); + m_lay = new QHBoxLayout(m_frame); + m_lay->setMargin(1); + m_lay->setSpacing(2); + m_lay->addStretch(); + addClients(); +} + +void StatusFrame::mousePressEvent(QMouseEvent *me) +{ + if (me->button() == Qt::RightButton){ + Command cmd; + cmd->id = MenuConnections; + EventMenuGet e(cmd); + e.process(); + QMenu *popup = e.menu(); + if (popup) + popup->popup(me->globalPos()); + } +} + +bool StatusFrame::processEvent(Event *e) +{ + switch (e->type()){ + case eEventSocketActive: { + const QList list = findChildren(); + Q_FOREACH(StatusLabel *lbl, list) { + lbl->setPict(); + } + break; + } + case eEventCheckCommandState: + { + EventCheckCommandState *ecs = static_cast(e); + CommandDef *cmd = ecs->cmd(); + if ((cmd->menu_id == MenuStatusWnd) && (cmd->id == CmdStatusWnd)){ + unsigned n = 0; + const QList list = findChildren(); + Q_FOREACH(StatusLabel *lbl, list) { + if (lbl->x() + lbl->width() > width()) + n++; + } + CommandDef *cmds = new CommandDef[n + 1]; + n = 0; + Q_FOREACH(StatusLabel *lbl, list) { + if (lbl->x() + lbl->width() > width()) { + cmds[n].id = 1; + cmds[n].text = "_"; + cmds[n].text_wrk = CorePlugin::instance()->clientName(lbl->m_client); + cmds[n].popup_id = lbl->m_id; + if (lbl->m_client->getState() == Client::Error) { + cmds[n].icon = "error"; + } else { + Protocol *protocol = lbl->m_client->protocol(); + const CommandDef *cmd = protocol->description(); + cmds[n].icon = cmd->icon; + for (cmd = protocol->statusList(); !cmd->text.isEmpty(); cmd++) { + if (cmd->id == lbl->m_client->getStatus()) { + cmds[n].icon = cmd->icon; + break; + } + } + } + n++; + } + } + cmd->param = cmds; + cmd->flags |= COMMAND_RECURSIVE; + return true; + } + break; + } + case eEventClientsChanged: + addClients(); + break; + case eEventClientChanged:{ + EventClientChanged *ecc = static_cast(e); + StatusLabel *lbl = findLabel(ecc->client()); + if (lbl) + lbl->setPict(); + break; + } + case eEventIconChanged:{ + const QList list = findChildren(); + Q_FOREACH(StatusLabel *lbl, list) { + lbl->setPict(); + } + break; + } + default: + break; + } + return false; +} + +void StatusFrame::addClients() +{ + const QList list = findChildren(); + Q_FOREACH(StatusLabel *lbl, list) { + delete lbl; + } + for (unsigned i = 0; i < getContacts()->nClients(); i++) { + Client *client = getContacts()->getClient(i); + QWidget *w = new StatusLabel(m_frame, client, CmdClient + i); + m_lay->addWidget(w); + w->show(); + } + adjustPos(); + repaint(); +} + +StatusLabel *StatusFrame::findLabel(Client *client) +{ + const QList list = findChildren(); + Q_FOREACH(StatusLabel *lbl, list) { + if (lbl->m_client == client) + return lbl; + } + return NULL; +} + +QSize StatusFrame::sizeHint() const +{ + QSize res = m_frame->sizeHint(); + res.setWidth(20); + return res; +} + +QSize StatusFrame::minimumSizeHint() const +{ + QSize res = m_frame->minimumSizeHint(); + res.setWidth(20); + return res; +} + +void StatusFrame::resizeEvent(QResizeEvent *e) +{ + QFrame::resizeEvent(e); + adjustPos(); +} + +void StatusFrame::adjustPos() +{ + QSize s = m_frame->minimumSizeHint(); + m_frame->resize(s); + m_frame->move(width() > s.width() ? width() - s.width() : 0, 0); + emit showButton(width() < s.width()); + repaint(); + m_frame->repaint(); + const QList list = findChildren(); + Q_FOREACH(StatusLabel *lbl, list) { + lbl->repaint(); + } +} + +static const char * const arrow_h_xpm[] = { + "9 7 3 1", + " c None", + ". c #000000", + "+ c none", + "..++..+++", + "+..++..++", + "++..++..+", + "+++..++..", + "++..++..+", + "+..++..++", + "..++..+++"}; + +StatusWnd::StatusWnd() : QFrame(NULL) +{ + log(L_DEBUG, "StatusWnd::StatusWnd()"); + setFrameStyle(NoFrame); + m_lay = new QHBoxLayout(this); + m_lay->setMargin(0); + m_frame = new StatusFrame(this); + m_btn = new QToolButton(this); + m_btn->setAutoRaise(true); + QIcon icon( QPixmap((const char **)arrow_h_xpm) ); + m_btn->setIcon( icon ); + m_btn->setMinimumSize(QSize(10, 10)); + m_lay->addWidget(m_frame); + m_lay->addWidget(m_btn); + connect(m_frame, SIGNAL(showButton(bool)), this, SLOT(showButton(bool))); + connect(m_btn, SIGNAL(clicked()), this, SLOT(clicked())); + EventAddWidget(this, true, EventAddWidget::eStatusWindow).process(); +} + +void StatusWnd::showButton(bool bState) +{ + if (bState){ + m_btn->show(); + }else{ + m_btn->hide(); + } +} + +void StatusWnd::clicked() +{ + Command cmd; + cmd->popup_id = MenuStatusWnd; + cmd->flags = COMMAND_NEW_POPUP; + EventMenuGet e(cmd); + e.process(); + QMenu *popup = e.menu(); + if (popup){ + QPoint pos = CToolButton::popupPos(m_btn, popup); + popup->popup(pos); + } +} + +BalloonMsg *StatusWnd::showError(const QString &text, QStringList &buttons, Client *client) +{ + if (!isVisible()) + return NULL; + StatusLabel *lbl = m_frame->findLabel(client); + if (lbl == NULL) + return NULL; + if (lbl->x() + lbl->width() > width()) + return NULL; + return new BalloonMsg(NULL, text, buttons, lbl); +} + diff --git a/plugins/_core/statuswnd.h b/plugins/_core/statuswnd.h new file mode 100644 index 0000000..2d3d059 --- /dev/null +++ b/plugins/_core/statuswnd.h @@ -0,0 +1,98 @@ +/*************************************************************************** + statuswnd.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _STATUSWND_H +#define _STATUSWND_H + + +#include "event.h" +#include +#include +#include +#include +#include + +class CorePlugin; + +class QHBoxLayout; +class QTimer; +class QToolButton; +class BalloonMsg; + +class StatusLabel : public QLabel +{ + Q_OBJECT +public: + StatusLabel(QWidget *parent, SIM::Client *client, unsigned id); + +protected slots: + void timeout(); + +protected: + void mousePressEvent(QMouseEvent *e); + +private: + void setPict(); + void fillStatusMenu(QMenu& menu); + void startBlinkTimer(); + void stopBlinkTimer(); + QTimer *m_blinkTimer; + SIM::Client *m_client; + unsigned m_id; + bool m_bBlink; + friend class StatusFrame; + +}; + +class StatusFrame : public QFrame, public SIM::EventReceiver +{ + Q_OBJECT +public: + StatusFrame(QWidget *parent); + void adjustPos(); + StatusLabel *findLabel(SIM::Client*); +signals: + void showButton(bool); +protected slots: + void addClients(); +protected: + virtual void resizeEvent(QResizeEvent*); + virtual void mousePressEvent(QMouseEvent *e); + virtual bool processEvent(SIM::Event*); + virtual QSize sizeHint() const; + virtual QSize minimumSizeHint() const; + QFrame *m_frame; + QHBoxLayout *m_lay; +}; + +class StatusWnd : public QFrame +{ + Q_OBJECT +public: + StatusWnd(); + BalloonMsg *showError(const QString &text, QStringList &buttons, SIM::Client *client); +protected slots: + void showButton(bool); + void clicked(); +protected: + StatusFrame *m_frame; + QHBoxLayout *m_lay; + QToolButton *m_btn; +}; + +#endif + diff --git a/plugins/_core/styles/CMakeLists.txt b/plugins/_core/styles/CMakeLists.txt new file mode 100644 index 0000000..97d694f --- /dev/null +++ b/plugins/_core/styles/CMakeLists.txt @@ -0,0 +1,30 @@ +# install only + +FILE(GLOB styles *.xsl) + +IF(MSVC_IDE) + FILE(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/debug/styles) + FILE(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/release/styles) +ELSE(MSVC_IDE) + IF(APPLE) + FILE(MAKE_DIRECTORY ${SIM_STYLES_DIR}) + ELSE(APPLE) + FILE(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/styles) + ENDIF(APPLE) +ENDIF(MSVC_IDE) + +FOREACH(FILE ${styles}) + GET_FILENAME_COMPONENT(FILENAME ${FILE} NAME) + IF(MSVC_IDE) + CONFIGURE_FILE(${FILE} ${CMAKE_BINARY_DIR}/debug/styles/${NAME} COPYONLY) + CONFIGURE_FILE(${FILE} ${CMAKE_BINARY_DIR}/release/styles/${NAME} COPYONLY) + ELSE(MSVC_IDE) + IF(APPLE) + CONFIGURE_FILE(${FILE} ${SIM_STYLES_DIR}/${NAME} COPYONLY) + ELSE(APPLE) + CONFIGURE_FILE(${FILE} ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/styles/${NAME} COPYONLY) + ENDIF(APPLE) + ENDIF(MSVC_IDE) +ENDFOREACH(FILE) + +INSTALL(FILES ${styles} DESTINATION ${SIM_STYLES_DIR}) diff --git a/plugins/_core/styles/SIM.2.xsl b/plugins/_core/styles/SIM.2.xsl new file mode 100644 index 0000000..45cdbd8 --- /dev/null +++ b/plugins/_core/styles/SIM.2.xsl @@ -0,0 +1,70 @@ + + + +

+ +msg:// + +sim:icons/ + + +  + + +  + + + +  + + + +  + + + + +#808080 + + + +:: + + + + + + + +font-weight:600 + + + + + +#800000 + + +#000080 + + + + + + + + + +:: + + + +

+background-color:;color:; + +

+

+  +

+ + \ No newline at end of file diff --git a/plugins/_core/styles/SIM.3.xsl b/plugins/_core/styles/SIM.3.xsl new file mode 100644 index 0000000..505f9f7 --- /dev/null +++ b/plugins/_core/styles/SIM.3.xsl @@ -0,0 +1,54 @@ + + + +

+ + + +#808080 + + + +:: + + +msg:// + + + + + + + +font-weight:600 + + + + + +#800000 + + +#000080 + + + +msg:// + + + + + + + + +:: + + + +

+background-color:;color:; + +

+
+
\ No newline at end of file diff --git a/plugins/_core/styles/SIM.4.(2+3).xsl b/plugins/_core/styles/SIM.4.(2+3).xsl new file mode 100644 index 0000000..f651e54 --- /dev/null +++ b/plugins/_core/styles/SIM.4.(2+3).xsl @@ -0,0 +1,57 @@ + + + +

+ + + +#808080 + + + +:: + + +msg:// + + + + + + + +font-weight:600 + + + + + +#800000 + + +#000080 + + + +msg:// + + + + + + + + +:: + + + +

+background-color:;color:; + +

+

+  +

+
+
\ No newline at end of file diff --git a/plugins/_core/styles/SIM.5.2.2.xsl b/plugins/_core/styles/SIM.5.2.2.xsl new file mode 100644 index 0000000..d439c06 --- /dev/null +++ b/plugins/_core/styles/SIM.5.2.2.xsl @@ -0,0 +1,160 @@ + + + + + + +
+ + + + + + +#e5e5e5 + + +#b0b0b0 + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +msg:// +sim:icons/ + +  + + + + +  + + + + + +  + + + + + +  + + + + + + + + + +font-weight:600 + + + + + + +#800000 + + +#000080 + + + + + + + + + +#ffffff + + + + +:: + +
+ + + + + + + + +

+ +sim:icons/ +  + + + + + + +:: + + + --> + +

+
+ + + + +

+ +

+
+
+ + + + +

+  +

+ + +
+
\ No newline at end of file diff --git a/plugins/_core/styles/SIM.5.2.3.xsl b/plugins/_core/styles/SIM.5.2.3.xsl new file mode 100644 index 0000000..a01629e --- /dev/null +++ b/plugins/_core/styles/SIM.5.2.3.xsl @@ -0,0 +1,160 @@ + + + + + + +
+ + + + + + +#e5e5e5 + + +#b0b0b0 + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +msg:// +sim:icons/ + +  + + + + +  + + + + + +  + + + + + +  + + + + + + + + + +font-weight:600 + + + + + + +#800000 + + +#000080 + + + + + + + + + +#ffffff + + + + +:: + +
+ + + + + + + + +

+ +sim:icons/ +  + + + + + + +:: + + + --> + +

+
+ + + + + + + + +
+ + + + +

+  +

+ + +
+
\ No newline at end of file diff --git a/plugins/_core/styles/SIM.5.2.4.xsl b/plugins/_core/styles/SIM.5.2.4.xsl new file mode 100644 index 0000000..9952c6b --- /dev/null +++ b/plugins/_core/styles/SIM.5.2.4.xsl @@ -0,0 +1,167 @@ + + + + + + +
+ + + + + + +#e5e5e5 + + +#b0b0b0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +msg:// +sim:icons/ + +  + + + + +  + + + + + +  + + + + + +  + + + + + + + + + +font-weight:600 + + + + + + +#800000 + + +#000080 + + + + + + + + + +#ffffff + + + + +:: + +
+ + + + + +#00C183 +

+ +sim:icons/ +  + + + +#000000 + + + +:: + + + --> + +

+
+ + + + +#e5e5e5 +

+ +

+
+ +#b0b0b0 +

+ +

+
+ +
+
+
+
+
\ No newline at end of file diff --git a/plugins/_core/styles/SIM.5.2.5.xsl b/plugins/_core/styles/SIM.5.2.5.xsl new file mode 100644 index 0000000..0b90a05 --- /dev/null +++ b/plugins/_core/styles/SIM.5.2.5.xsl @@ -0,0 +1,167 @@ + + + + + + + + + + + + + +#e5e5e5 + + +#b0b0b0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +msg:// +sim:icons/ + +  + + + + +  + + + + + +  + + + + + +  + + + + + + + + + +font-weight:600 + + + + + + +#800000 + + +#000080 + + + + + + + + + +#ffffff + + + + +:: + +
+ + + + + +#00C183 +

+ +sim:icons/ +  + + + +#000000 + + + +:: + + + --> + +

+
+ + + + +#e5e5e5 +

+ +

+
+ +#b0b0b0 +

+ +

+
+ +
+
+
+
+
\ No newline at end of file diff --git a/plugins/_core/styles/SIM.5.2.xsl b/plugins/_core/styles/SIM.5.2.xsl new file mode 100644 index 0000000..b3f1ef8 --- /dev/null +++ b/plugins/_core/styles/SIM.5.2.xsl @@ -0,0 +1,160 @@ + + + + + + +
+ + + + + + +#e5e5e5 + + +#b0b0b0 + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +msg:// +sim:icons/ + +  + + + + +  + + + + + +  + + + + + +  + + + + + + + + + +font-weight:600 + + + + + + +#800000 + + +#000080 + + + + + + + + + +#ffffff + + + + +:: + +
+ + + + + + + + +

+ +sim:icons/ +  + + + + + + +:: + + + --> + +

+
+ + + + +

+ +

+
+
+ + + + +

+  +

+ + +
+
\ No newline at end of file diff --git a/plugins/_core/styles/SIM.5.xsl b/plugins/_core/styles/SIM.5.xsl new file mode 100644 index 0000000..86eb191 --- /dev/null +++ b/plugins/_core/styles/SIM.5.xsl @@ -0,0 +1,162 @@ + + + + + + +
+ + + + + + +#e5e5e5 + + +#b0b0b0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +msg:// +sim:icons/ + +  + + + + +  + + + + + +  + + + + + +  + + + + + + + +font-weight:600 + + + + + + +#800000 + + +#000080 + + + + + + + + + +#ffffff + + + + +:: + +
+ + + + + + + + +

+ +sim:icons/ +  + + + + + + +:: + + + --> + +

+
+ + + + +

+ +

+
+
+ + + + +

+  +

+ + +
+
\ No newline at end of file diff --git a/plugins/_core/styles/SIM.xsl b/plugins/_core/styles/SIM.xsl new file mode 100644 index 0000000..50bc9dd --- /dev/null +++ b/plugins/_core/styles/SIM.xsl @@ -0,0 +1,64 @@ + + + +

+ +msg:// + +sim:icons/ + + + + + + + + + + + + + + + +#808080 + + + +:: + + + + + + + +font-weight:600 + + + + + +#800000 + + +#000080 + + + + + + + + + +:: + + + +

+background-color:;color:; + +

+
+
\ No newline at end of file diff --git a/plugins/_core/styles/Separated.2.xsl b/plugins/_core/styles/Separated.2.xsl new file mode 100644 index 0000000..49f6b6d --- /dev/null +++ b/plugins/_core/styles/Separated.2.xsl @@ -0,0 +1,71 @@ + + + + + +
+ + +#cccccc + + +#fafafa + + + + + + + + + +
+ +msg:// + +sim:icons/ + + + +  + + + +  + + + +  + + + + + +font-weight:600 + + + +#660000 + + +#000066 + + + + + + + +:: + +
+ + + + +color:; + + +
+
+
diff --git a/plugins/_core/styles/Separated.3.xsl b/plugins/_core/styles/Separated.3.xsl new file mode 100644 index 0000000..331df14 --- /dev/null +++ b/plugins/_core/styles/Separated.3.xsl @@ -0,0 +1,54 @@ + + + + + +
+ + +#cccccc + + +#fafafa + + + + + + + + +
+ + +font-weight:600 + + + +#660000 + + +#000066 + + +msg:// + + + + + + + +:: + +
+ + + + +color:; + + +
+
+
diff --git a/plugins/_core/styles/Separated.4.xsl b/plugins/_core/styles/Separated.4.xsl new file mode 100644 index 0000000..d6e5c3b --- /dev/null +++ b/plugins/_core/styles/Separated.4.xsl @@ -0,0 +1,67 @@ + + + + + + + +#cccccc + + +#fafafa + + + + + + + + + +
+ +msg:// + +sim:icons/ + + + + + + + + + + + + + + +font-weight:600 + + + +#660000 + + +#000066 + + + + + + + +:: + +
+ + + + +color:; + + +
+
+
diff --git a/plugins/_core/styles/Separated.5.(2+3).xsl b/plugins/_core/styles/Separated.5.(2+3).xsl new file mode 100644 index 0000000..7eb0930 --- /dev/null +++ b/plugins/_core/styles/Separated.5.(2+3).xsl @@ -0,0 +1,54 @@ + + + + + +
+ + +#cccccc + + +#fafafa + + + + + + + + +
+ + +font-weight:600 + + + +#660000 + + +#000066 + + +msg:// + + + + + + + +:: + +
+ + + + +color:; + + +
+
+
diff --git a/plugins/_core/styles/Separated.6.(2+4).xsl b/plugins/_core/styles/Separated.6.(2+4).xsl new file mode 100644 index 0000000..070d59b --- /dev/null +++ b/plugins/_core/styles/Separated.6.(2+4).xsl @@ -0,0 +1,70 @@ + + + + + + + +#cccccc + + +#fafafa + + + + + + + + + +
+ +msg:// + +sim:icons/ + + + +  + + + +  + + + +  + + + + + +font-weight:600 + + + +#660000 + + +#000066 + + + + + + + +:: + +
+ + + + +color:; + + +
+
+
diff --git a/plugins/_core/styles/Separated.7.(3+4).xsl b/plugins/_core/styles/Separated.7.(3+4).xsl new file mode 100644 index 0000000..2fe3582 --- /dev/null +++ b/plugins/_core/styles/Separated.7.(3+4).xsl @@ -0,0 +1,53 @@ + + + + + + + +#cccccc + + +#fafafa + + + + + + + + +
+ + +font-weight:600 + + + +#660000 + + +#000066 + + +msg:// + + + + + + + +:: + +
+ + + + +color:; + + +
+
+
diff --git a/plugins/_core/styles/Separated.8.(2+3+4).xsl b/plugins/_core/styles/Separated.8.(2+3+4).xsl new file mode 100644 index 0000000..8da4beb --- /dev/null +++ b/plugins/_core/styles/Separated.8.(2+3+4).xsl @@ -0,0 +1,53 @@ + + + + + + + +#cccccc + + +#fafafa + + + + + + + + +
+ + +font-weight:600 + + + +#660000 + + +#000066 + + +msg:// + + + + + + + +:: + +
+ + + + +color:; + + +
+
+
diff --git a/plugins/_core/styles/Separated.xsl b/plugins/_core/styles/Separated.xsl new file mode 100644 index 0000000..eb69d98 --- /dev/null +++ b/plugins/_core/styles/Separated.xsl @@ -0,0 +1,68 @@ + + + + + +
+ + +#cccccc + + +#fafafa + + + + + + + + + +
+ +msg:// + +sim:icons/ + + + + + + + + + + + + + + +font-weight:600 + + + +#660000 + + +#000066 + + + + + + + +:: + +
+ + + + +color:; + + +
+
+
diff --git a/plugins/_core/styles/XChat.xsl b/plugins/_core/styles/XChat.xsl new file mode 100644 index 0000000..f19d38a --- /dev/null +++ b/plugins/_core/styles/XChat.xsl @@ -0,0 +1,47 @@ + + + + + + + +#808080 + +[:] + < + +> + + + + + + + + +font-weight:600 + +[:] + < + + + +#800000 + + +#000080 + + + + +> + + + +background-color:;color:; + + + + + + diff --git a/plugins/_core/styles/XChat2seconds.xsl b/plugins/_core/styles/XChat2seconds.xsl new file mode 100644 index 0000000..6c420a7 --- /dev/null +++ b/plugins/_core/styles/XChat2seconds.xsl @@ -0,0 +1,47 @@ + + + + + + + + +#808080 +[::] + < + +> + + + + + + + + +font-weight:600 + +[::] + < + + + +#800000 + + +#000080 + + + + +> + + + +background-color:;color:; + + + + + + diff --git a/plugins/_core/styles/XChat3fullDate.xsl b/plugins/_core/styles/XChat3fullDate.xsl new file mode 100644 index 0000000..8ec6961 --- /dev/null +++ b/plugins/_core/styles/XChat3fullDate.xsl @@ -0,0 +1,47 @@ + + + + + + + + +#808080 +[::] + < + +> + + + + + + + + +font-weight:600 + +[ ::] + < + + + +#800000 + + +#000080 + + + + +> + + + +background-color:;color:; + + + + + + diff --git a/plugins/_core/textedit_menu.cpp b/plugins/_core/textedit_menu.cpp new file mode 100644 index 0000000..1113f53 --- /dev/null +++ b/plugins/_core/textedit_menu.cpp @@ -0,0 +1,138 @@ +/*************************************************************************** + textedit_menu.cpp + + This file contains subroutine that creates MenuTextEdit menu and adds some + of it's items. Items that created in other places are mentioned here as a + comments. MenuTextEdit is used as context menu in any multiline text input + areas, including MsgEdit area, and also in some non-editable text view + areas, witch is also based on such TextShow class, such as log view area in + networkmonitor, etc. + ------------------- + begin : Tue Nov 26 2008 + based on : core.cpp of Sim-IM by Vladimir Shutoff + and Sim-IM team + copyright : (C) 2002 - 2004 Vladimir Shutoff + (C) 2004 - 2008 Sim-IM Development Team + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "core.h" +#include "kdeisversion.h" // for KDE_IS_VERSION + +using namespace SIM; + +void CorePlugin::createMenuTextEdit() +{ + EventMenu(MenuTextEdit, EventMenu::eAdd).process(); + + Command cmd; + + /***** ????????? (CmdSpell, grp=0x0100) *****/ + // Some strange menu item is created here by constructor of spell plugin + // What does it do you should find out yourself + + cmd->id = CmdUndo; + cmd->text = I18N_NOOP("&Undo"); + cmd->accel = "Ctrl+Z"; + cmd->icon = "undo"; + cmd->menu_id = MenuTextEdit; + cmd->menu_grp = 0x1000; + cmd->bar_id = 0; + cmd->bar_grp = 0; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + + cmd->id = CmdRedo; + cmd->text = I18N_NOOP("&Redo"); + cmd->accel = "Ctrl+Y"; + cmd->icon = "redo"; + cmd->menu_id = MenuTextEdit; + cmd->menu_grp = 0x1001; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdCut; + cmd->text = I18N_NOOP("Cu&t"); + cmd->icon = "editcut"; + cmd->accel = "Ctrl+X"; + cmd->menu_id = MenuTextEdit; + cmd->menu_grp = 0x2000; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdCopy; + cmd->text = I18N_NOOP("&Copy"); + cmd->icon = "editcopy"; + cmd->accel = "Ctrl+C"; + cmd->menu_id = MenuTextEdit; + cmd->menu_grp = 0x2001; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdPaste; + cmd->text = I18N_NOOP("&Paste"); + cmd->icon = "editpaste"; + cmd->accel = "Ctrl+V"; + cmd->menu_id = MenuTextEdit; + cmd->menu_grp = 0x2002; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdClear; + cmd->text = I18N_NOOP("Clear"); + cmd->icon = QString::null; + cmd->accel = QString::null; + cmd->menu_id = MenuTextEdit; + cmd->menu_grp = 0x3000; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdSelectAll; + cmd->text = I18N_NOOP("Select All"); + cmd->icon = QString::null; + cmd->accel = "Ctrl+A"; + cmd->menu_id = MenuTextEdit; + cmd->menu_grp = 0x3001; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + +#ifdef USE_KDE +#if KDE_IS_VERSION(3,2,0) + cmd->id = CmdEnableSpell; + cmd->text = I18N_NOOP("Enable spell check"); + cmd->icon = QString::null; // TODO: Add KDE spellcheck icon here... may be slightly modified + cmd->accel = QString::null; + cmd->menu_id = MenuTextEdit; + cmd->menu_grp = 0x4000; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdSpell; + cmd->text = I18N_NOOP("Spell check"); + cmd->icon = QString::null; // TODO: Add KDE spellcheck icon here... + cmd->menu_id = MenuTextEdit; + cmd->menu_grp = 0x4001; + cmd->flags = COMMAND_DEFAULT; + EventCommandCreate(cmd).process(); +#endif +#endif + + /***** Ignore this phrase (CmdIgnoreText, grp=0x7000) *****/ + // This menu item should be created by constructor of filter plugin, but for some reason + // it is not visible, where it should be. + // TODO: findout why 'Ignore this phrase' is always hidden + + /***** Copy &location (CmdCopyLocation, grp=0x7010 *****/ + // This menu item is created by constructor of navigate plugin + // TODO: findout why this 'Copy Location' item is always visible at msgedit box, even when there is no http link there + +} diff --git a/plugins/_core/tmpl.cpp b/plugins/_core/tmpl.cpp new file mode 100644 index 0000000..5cdf950 --- /dev/null +++ b/plugins/_core/tmpl.cpp @@ -0,0 +1,268 @@ +/*************************************************************************** + tmpl.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include + +#include "log.h" +#include "contacts/clientdataiterator.h" +#include "contacts/contact.h" +#include "contacts/client.h" + +#include "core.h" + +#ifdef Q_OS_WIN +#include +#else +#include +#include +#endif + +#include +#include +#include + +#include "tmpl.h" +#include "socket/ip.h" + +using namespace std; +using namespace SIM; + +Tmpl::Tmpl(QObject *parent) + : QObject(parent) +{ +} + +Tmpl::~Tmpl() +{ +} + +bool Tmpl::processEvent(Event *e) +{ + if (e->type() == eEventTemplateExpand){ + EventTemplate *et = static_cast(e); + EventTemplate::TemplateExpand *t = et->templateExpand(); + TmplExpand tmpl; + tmpl.tmpl = *t; + tmpl.process = NULL; + tmpl.bReady = false; + if (!process(tmpl)) + tmpls.push_back(tmpl); + return true; + } + return false; +} + +void Tmpl::clear() +{ + for (QList::iterator it = tmpls.begin(); it != tmpls.end();){ + if (it->bReady && it->process){ + delete it->process; + it->process = NULL; + it->bReady = false; + if (process(*it)){ + tmpls.erase(it); + it = tmpls.begin(); + continue; + } + ++it; + } else { + ++it; + } + } +} + +void Tmpl::ready() +{ + for (QList::iterator it = tmpls.begin(); it != tmpls.end(); ++it){ + QProcess *p = it->process; + if (p && p->state() == QProcess::NotRunning){ + if (p->exitStatus() == QProcess::NormalExit){ + it->bReady = true; + p->setReadChannel(QProcess::StandardOutput); + it->res += QString::fromLocal8Bit(p->readAll()); + QTimer::singleShot(0, this, SLOT(clear())); + return; + } + } + } +} + +bool Tmpl::process(TmplExpand &t) +{ + QString head = getToken(t.tmpl.tmpl, '`', false); + t.res += process(t, head); + if (t.tmpl.tmpl.isEmpty()){ + t.tmpl.tmpl = t.res; + EventTemplateExpanded e(&t.tmpl); + t.tmpl.receiver->processEvent(&e); + e.setNoProcess(); + return true; + } + QString prg = getToken(t.tmpl.tmpl, '`', false); + prg = process(t, prg); + t.process = new QProcess(parent()); + connect(t.process, SIGNAL(processExited()), this, SLOT(ready())); + t.process->start(prg); + return false; +} + +QString Tmpl::process(TmplExpand &t, const QString &str) +{ + QString res; + QString s = str; + while (!s.isEmpty()){ + res += getToken(s, '&'); + if(s.isEmpty()) + break; + QString tag = getToken(s, ';'); + if (tag.isEmpty()) { + res += tag; + log(L_WARN, "Found '&' without ';' while parsing %s", qPrintable(str)); + continue; + } + Contact *contact; + if (tag.startsWith("My")){ + contact = getContacts()->owner(); + tag = tag.mid(2); + }else{ + contact = t.tmpl.contact; + } + + if (contact == NULL) + continue; + + if (tag == "TimeStatus"){ + QDateTime dt; + dt.setTime_t(CorePlugin::instance()->value("StatusTime").toUInt()); + res += dt.toString("hh:mm"); + continue; + } + + if (tag == "IntervalStatus"){ + res += QString::number(time(NULL) - CorePlugin::instance()->value("StatusTime").toUInt()); + continue; + } + + if (tag == "IP"){ + EventGetContactIP e(contact); + struct in_addr addr; + e.process(); + if (e.ip()) + addr.s_addr = e.ip()->ip(); + else + addr.s_addr = 0; + res += inet_ntoa(addr); + continue; + } + + if (tag == "Mail"){ + QString mails = contact->getEMails(); + QString mail = getToken(mails, ';', false); + res += getToken(mail, '/'); + continue; + } + + if (tag == "Phone"){ + QString phones = contact->getPhones(); + QString phone_item = getToken(phones, ';', false); + phone_item = getToken(phone_item, '/', false); + res += getToken(phone_item, ','); + continue; + } + + if (tag == "Unread"){ + unsigned nUnread = 0; + for (list::iterator it = CorePlugin::instance()->unread.begin(); it != CorePlugin::instance()->unread.end(); ++it){ + if (it->contact == contact->id()) + nUnread++; + } + res += QString::number(nUnread); + continue; + } + +// if (getTag(tag, &(contact->getGroup()), contact->dataDef(), res)) +// continue; + + clientData *data; + ClientDataIterator itc(contact->clientData); + while ((data = ++itc) != NULL){ + if (getTag(tag, &(data->Sign), itc.client()->protocol()->userDataDef(), res)) + break; + } + if (data) + continue; + +// UserDataDef *def; +// ContactList::UserDataIterator it; +// while ((def = ++it) != NULL){ +// SIM::Data *data = (SIM::Data*)contact->getUserData(def->id); +// if (data == NULL) +// continue; +// if (getTag(tag, data, def->def, res)){ +// break; +// } +// } + } + return res; +} + +bool Tmpl::getTag(const QString &name, SIM::Data *data, const DataDef *def, QString &res) +{ + const DataDef *d; + for (d = def; d->name; d++){ + if (name == d->name) + break; + data += d->n_values; + } + if (d->name == NULL) + return false; + + switch (d->type){ + case DATA_BOOL: + res += data->toBool() ? i18n("yes") : i18n("no"); + break; + case DATA_ULONG: + res += QString::number(data->toULong()); + break; + case DATA_LONG: + res += QString::number(data->toLong()); + break; + case DATA_STRING: + case DATA_UTF: + if(data->str().isEmpty()) + return false; // mabye we get a better one in the next contact + res += data->str(); + break; + case DATA_CSTRING: + if(data->cstr().isEmpty()) + return false; // mabye we get a better one in the next contact + // this is not encoded correct, but no other way atm + res += QString::fromLocal8Bit(data->cstr()); + break; + default: + break; + } + return true; +} + +/* +#ifndef NO_MOC_INCLUDES +#include "tmpl.moc" +#endif +*/ + + diff --git a/plugins/_core/tmpl.h b/plugins/_core/tmpl.h new file mode 100644 index 0000000..8db8ecc --- /dev/null +++ b/plugins/_core/tmpl.h @@ -0,0 +1,55 @@ +/*************************************************************************** + tmpl.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _TMPL_H +#define _TMPL_H + +#include +#include + +#include "event.h" +#include "misc.h" +#include "core_events.h" + +class QProcess; + +class Tmpl : public QObject, public SIM::EventReceiver +{ + Q_OBJECT +public: + Tmpl(QObject *parent); + ~Tmpl(); +protected slots: + void ready(); + void clear(); +protected: + struct TmplExpand + { + EventTemplate::TemplateExpand tmpl; + QProcess *process; + bool bReady; + QString res; + }; + virtual bool processEvent(SIM::Event*); + bool process(TmplExpand &t); + QString process(TmplExpand &t, const QString &str); + bool getTag(const QString &name, SIM::Data *data, const SIM::DataDef *def, QString &res); + QList tmpls; +}; + +#endif + diff --git a/plugins/_core/toolbar_container.cpp b/plugins/_core/toolbar_container.cpp new file mode 100644 index 0000000..d57fe88 --- /dev/null +++ b/plugins/_core/toolbar_container.cpp @@ -0,0 +1,143 @@ +/*************************************************************************** + toolbar_container.cpp + + This file contains subroutine that creates toolbar and it's submenu + for container window (One might call it chat-window, but in Sim-IM + terminology it is calld container). + Note that only static items are created here. Some items of MenuMessage + are created by MsgEdit::setupMessages(); (msgedit.cpp) while creating + message types. Some items somewhere else (I (shaplov) did not explore this + issue yet) + ------------------- + begin : Tue Nov 26 2008 + based on : core.cpp of Sim-IM by Vladimir Shutoff + and Sim-IM team + copyright : (C) 2002 - 2004 Vladimir Shutoff + (C) 2004 - 2008 Sim-IM Development Team + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "core.h" + +using namespace SIM; + +void CorePlugin::createContainerToolbar() +{ + Command cmd; + + EventToolbar(ToolBarContainer, EventToolbar::eAdd).process(); + + cmd->id = CmdMessageType; + cmd->text = I18N_NOOP("Message"); + cmd->icon = "message"; + cmd->bar_id = ToolBarContainer; + cmd->bar_grp = 0x2000; + cmd->menu_id = 0; + cmd->menu_grp = 0; + cmd->popup_id = MenuMessage; + cmd->flags = BTN_PICT; + EventCommandCreate(cmd).process(); + + cmd->id = CmdContainerContact; + cmd->text = I18N_NOOP("Contact"); + cmd->icon = "empty"; + cmd->bar_id = ToolBarContainer; + cmd->bar_grp = 0x6000; + cmd->popup_id = MenuContainerContact; + cmd->flags = BTN_PICT; + EventCommandCreate(cmd).process(); + + cmd->id = CmdContactGroup; + cmd->text = I18N_NOOP("Group"); + cmd->icon = "grp_on"; + cmd->bar_id = ToolBarContainer; + cmd->bar_grp = 0x7000; + cmd->popup_id = MenuContactGroup; + cmd->flags = COMMAND_DEFAULT; + EventCommandCreate(cmd).process(); + + cmd->id = CmdInfo; + cmd->text = I18N_NOOP("User &info"); + cmd->icon = "info"; + cmd->bar_id = ToolBarContainer; + cmd->bar_grp = 0x8000; + cmd->popup_id = 0; + cmd->flags = COMMAND_DEFAULT; + EventCommandCreate(cmd).process(); + + cmd->id = CmdHistory; + cmd->text = I18N_NOOP("&History"); + cmd->icon = "history"; + cmd->bar_id = ToolBarContainer; + cmd->bar_grp = 0x8010; + cmd->popup_id = 0; + cmd->flags = COMMAND_DEFAULT; + EventCommandCreate(cmd).process(); + + cmd->id = CmdChangeEncoding; + cmd->text = I18N_NOOP("Change &encoding"); + cmd->icon = "encoding"; + cmd->menu_id = 0; + cmd->menu_grp = 0; + cmd->bar_id = ToolBarContainer; + cmd->bar_grp = 0x8080; + cmd->popup_id = MenuEncoding; + cmd->flags = COMMAND_CHECK_STATE; + + EventCommandCreate(cmd).process(); + cmd->id = CmdClose; + cmd->text = I18N_NOOP("Close"); + cmd->icon = "exit"; + cmd->bar_id = ToolBarContainer; + cmd->bar_grp = 0xF000; + cmd->accel = "Esc"; + cmd->flags = COMMAND_DEFAULT; + cmd->popup_id = 0; + EventCommandCreate(cmd).process(); + + + // First menu of this tootbar: list of message types that can be sent to the contact + // displayed in chat window, and also list of different contact entities of meta-contact + // (if we have meta-contact) also with types of messages can be send to particular contact. + + // Some items ot this menu are added by MsgEdit::setupMessages(); (msgedit.cpp), witch is called at + // CorePlugin constructor, right after this function. MsgEdit::setupMessages() creates message + // types and creatins of message types creates menu item in MenuMessage (strange idea, isn't it?) + // And there are also plases where this menu is filled. Please use 'grep' to find them + + EventMenu(MenuMessage, EventMenu::eAdd).process(); + + cmd->id = CmdContactClients; + cmd->text = "_"; + cmd->icon = "NULL"; + cmd->bar_id = 0; + cmd->menu_id = MenuMessage; + cmd->menu_grp = 0x30FF; + cmd->accel = QString::null; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + + // Second menu of this toolbar: list of chats that are opened in this container + // To see where this menu is filled please use 'grep CmdContainerContacts *' + EventMenu(MenuContainerContact, EventMenu::eAdd).process(); + + cmd->id = CmdContainerContacts; + cmd->text = "_"; + cmd->icon = QString::null; + cmd->menu_id = MenuContainerContact; + cmd->menu_grp = 0x1000; + cmd->bar_id = 0; + cmd->bar_grp = 0; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + +} diff --git a/plugins/_core/toolbar_history.cpp b/plugins/_core/toolbar_history.cpp new file mode 100644 index 0000000..da13fe9 --- /dev/null +++ b/plugins/_core/toolbar_history.cpp @@ -0,0 +1,85 @@ +/*************************************************************************** + toolbar_history.cpp + + This file contains subroutine that creates toolbar for history window + ------------------- + begin : Tue Nov 26 2008 + based on : core.cpp of Sim-IM by Vladimir Shutoff + and Sim-IM team + copyright : (C) 2002 - 2004 Vladimir Shutoff + (C) 2004 - 2008 Sim-IM Development Team + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "core.h" + +using namespace SIM; + +void CorePlugin::createHistoryToolbar() +{ + EventToolbar(ToolBarHistory, EventToolbar::eAdd).process(); + Command cmd; + + cmd->id = CmdHistoryDirection; + cmd->text = I18N_NOOP("&Direction"); + cmd->icon = "1uparrow"; + cmd->icon_on = "1downarrow"; + cmd->bar_id = ToolBarHistory; + cmd->bar_grp = 0x2000; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdHistoryFind; + cmd->text = I18N_NOOP("&Filter"); + cmd->icon = "filter"; + cmd->icon_on = "filter"; + cmd->bar_id = ToolBarHistory; + cmd->bar_grp = 0x3000; + cmd->flags = BTN_COMBO_CHECK; + EventCommandCreate(cmd).process(); + + cmd->id = CmdHistoryPrev; + cmd->text = I18N_NOOP("&Previous page"); + cmd->icon = "1leftarrow"; + cmd->icon_on = QString::null; + cmd->bar_id = ToolBarHistory; + cmd->bar_grp = 0x5000; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdHistoryNext; + cmd->text = I18N_NOOP("&Next page"); + cmd->icon = "1rightarrow"; + cmd->bar_id = ToolBarHistory; + cmd->bar_grp = 0x5001; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdHistorySave; + cmd->text = I18N_NOOP("&Save as text"); + cmd->icon = "filesave"; + cmd->accel = "Ctrl+S"; + cmd->bar_id = ToolBarHistory; + cmd->bar_grp = 0x6000; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdChangeEncoding; + cmd->text = I18N_NOOP("Change &encoding"); + cmd->icon = "encoding"; + cmd->menu_id = 0; + cmd->bar_id = ToolBarHistory; + cmd->bar_grp = 0x8080; + cmd->popup_id = MenuEncoding; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + +} diff --git a/plugins/_core/toolbar_main.cpp b/plugins/_core/toolbar_main.cpp new file mode 100644 index 0000000..8b5178c --- /dev/null +++ b/plugins/_core/toolbar_main.cpp @@ -0,0 +1,356 @@ +/*************************************************************************** + toolbar_main.cpp + + This file contains subroutines for creating and processing main window + toolbar and it's pull-down menus. + ------------------- + begin : Tue Nov 26 2008 + based on : core.cpp of Sim-IM by Vladimir Shutoff + and Sim-IM team + copyright : (C) 2002 - 2004 Vladimir Shutoff + (C) 2004 - 2008 Sim-IM Development Team + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "core.h" +#include "log.h" + +using namespace SIM; + + +void CorePlugin::createMainToolbar() +{ + + log(L_DEBUG, "createMainToolbar()"); + Command cmd; + + // **** Main ToolBar **** + EventToolbar(ToolBarMain, EventToolbar::eAdd).process(); + + cmd->id = CmdOnline; + cmd->text = I18N_NOOP("Show &offline"); + cmd->icon = "online_off"; + cmd->icon_on = "online_on"; + cmd->bar_id = ToolBarMain; + cmd->bar_grp = 0x4000; + cmd->menu_id = MenuMain; + cmd->menu_grp = 0; + if (value("ShowOnLine").toBool()) cmd->flags |= COMMAND_CHECKED; + EventCommandCreate(cmd).process(); + + cmd->id = CmdGroupToolbarButton; + cmd->text = I18N_NOOP("&Groups"); + cmd->icon = value("GroupMode").toUInt() ? "grp_on" : "grp_off"; + cmd->icon_on = QString::null; + cmd->bar_id = ToolBarMain; + cmd->bar_grp = 0x4000; + cmd->menu_id = 0; + cmd->popup_id = MenuGroups; + EventCommandCreate(cmd).process(); + + // Status toolbar item is created at status.cpp line 197. May be it should be moved here too... + + cmd->id = CmdMenu; + cmd->text = I18N_NOOP("&Menu"); + cmd->icon = "1downarrow"; + cmd->icon_on = QString::null; + cmd->bar_id = ToolBarMain; + cmd->bar_grp = 0x8000; + cmd->menu_id = 0; + cmd->menu_grp = 0; + cmd->popup_id = MenuMain; + cmd->flags = 0; + EventCommandCreate(cmd).process(); + + // **** Main Menu **** + + EventMenu(MenuMain, EventMenu::eAdd).process(); + + cmd->id = CmdSearch; + cmd->text = I18N_NOOP("Search / Add contact"); + cmd->icon = "find"; + cmd->bar_id = ToolBarMain; + cmd->bar_grp = 0; + cmd->menu_id = MenuMain; + cmd->menu_grp = 0x2080; + cmd->popup_id = 0; + cmd->flags = COMMAND_DEFAULT; + EventCommandCreate(cmd).process(); + + cmd->id = CmdSendSMS; + cmd->text = I18N_NOOP("&Send SMS"); + cmd->icon = "sms"; + cmd->bar_id = ToolBarMain; + cmd->bar_grp = 0; + cmd->menu_id = MenuMain; + cmd->menu_grp = 0x2081; + cmd->popup_id = 0; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdUnread; + cmd->text = I18N_NOOP("Unread messages"); + cmd->icon = "message"; + cmd->bar_id = 0; + cmd->bar_grp = 0; + cmd->menu_id = MenuMain; + cmd->menu_grp = 0x3000; + cmd->flags = COMMAND_IMPORTANT | COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + // Status menu item is created at status.cpp line 56. May be it should be moved here too... + + cmd->id = CmdGroup; + cmd->text = I18N_NOOP("&Groups"); + cmd->icon = "grp_on"; + cmd->icon_on = QString::null; + cmd->bar_id = 0; + cmd->menu_id = MenuMain; + cmd->menu_grp = 0x6001; + cmd->popup_id = MenuGroups; + cmd->flags = COMMAND_DEFAULT; + EventCommandCreate(cmd).process(); + + cmd->id = CmdPhones; + cmd->text = I18N_NOOP("&Phone service"); + cmd->icon = "phone"; + cmd->bar_id = 0; + cmd->bar_grp = 0; + cmd->menu_id = MenuMain; + cmd->menu_grp = 0x60F0; + cmd->popup_id = MenuPhones; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + // "Always on top" menu item is created by "ontop" plugin + + // "Network monitor" menu item is created by "netmonitor" plugin + + // "Connections" or "Connection manager" menu item (whitch one depends on number of + // client plugins loaded) is created by CorePlugin::loadMenu() in core.cpp + // May be should moved here once... + + cmd->id = CmdConfigure; + cmd->text = I18N_NOOP("Setup"); + cmd->icon = "configure"; + cmd->bar_id = ToolBarMain; + cmd->bar_grp = 0; + cmd->menu_id = MenuMain; + cmd->menu_grp = 0x8080; + cmd->popup_id = 0; + cmd->flags = COMMAND_DEFAULT; + EventCommandCreate(cmd).process(); + + // "About KDE" menu item is created by "about" plugin if KDE is enabled + + // "Bug report / Requests" menu item is created by "about" plugin + + // "About Sim-IM" menu item is created by "about" plugin + + cmd->id = CmdProfileChange; + cmd->text = I18N_NOOP("Change profile"); + cmd->icon = QString::null; + cmd->bar_id = 0; + cmd->bar_grp = 0; + cmd->menu_id = MenuMain; + cmd->menu_grp = 0x10040; + cmd->popup_id = 0; + cmd->flags = COMMAND_DEFAULT; // May be COMMAND_IMPORTANT? Do we need this menu item in tray menu by default? + EventCommandCreate(cmd).process(); + + cmd->id = CmdQuit; + cmd->text = I18N_NOOP("Quit"); + cmd->icon = "exit"; + cmd->bar_id = ToolBarMain; + cmd->bar_grp = 0; + cmd->menu_id = MenuMain; + cmd->menu_grp = 0x10080; + cmd->popup_id = 0; + cmd->flags = COMMAND_IMPORTANT; + EventCommandCreate(cmd).process(); + + // **** Groups menu **** + + EventMenu(MenuGroups, EventMenu::eAdd).process(); + + cmd->id = CmdGrpOff; + cmd->text = I18N_NOOP("Do&n't show groups"); + cmd->icon = "grp_off"; + cmd->bar_id = 0; + cmd->menu_id = MenuGroups; + cmd->menu_grp = 0x1000; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdGrpMode1; + cmd->text = I18N_NOOP("Group mode 1"); + cmd->icon = "grp_on"; + cmd->bar_id = 0; + cmd->menu_id = MenuGroups; + cmd->menu_grp = 0x1001; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdGrpMode2; + cmd->text = I18N_NOOP("Group mode 2"); + cmd->icon = "grp_on"; //TODO: Make icon for GroupMode2 independant from icon for GroupMode1 + cmd->bar_id = 0; + cmd->menu_id = MenuGroups; + cmd->menu_grp = 0x1002; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdOnline; + cmd->text = I18N_NOOP("Show &offline"); + cmd->icon = "online_off"; + cmd->icon_on = "online_on"; + cmd->bar_id = 0; + cmd->menu_id = MenuGroups; + cmd->menu_grp = 0x8000; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdEmptyGroup; + cmd->text = I18N_NOOP("Show &empty groups"); + cmd->icon = QString::null; + cmd->icon_on = QString::null; + cmd->bar_id = 0; + cmd->menu_id = MenuGroups; + cmd->menu_grp = 0x8001; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdGrpCreate; + cmd->text = I18N_NOOP("&Create group"); + cmd->icon = "grp_create"; + cmd->icon_on = QString::null; + cmd->bar_id = 0; + cmd->menu_id = MenuGroups; + cmd->menu_grp = 0xA000; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + // **** Phone service submenu **** + + EventMenu(MenuPhones, EventMenu::eAdd).process(); + + cmd->id = CmdPhoneLocation; + cmd->text = I18N_NOOP("&Location"); + cmd->icon = QString::null; + cmd->icon_on = QString::null; + cmd->bar_id = 0; + cmd->menu_id = MenuPhones; + cmd->menu_grp = 0x1000; + cmd->popup_id = MenuPhoneLocation; + cmd->flags = COMMAND_DEFAULT; + EventCommandCreate(cmd).process(); + + EventMenu(MenuPhoneLocation, EventMenu::eAdd).process(); + + cmd->id = CmdPhoneLocation; //FIXME: Is it ok that we have two CmdPhoneLocation menu items in different menus? + cmd->text = "_"; + cmd->icon = QString::null; + cmd->bar_id = 0; + cmd->menu_id = MenuPhoneLocation; + cmd->menu_grp = 0x1000; + cmd->popup_id = 0; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdPhoneState; + cmd->text = I18N_NOOP("&Status"); + cmd->icon = QString::null; + cmd->icon_on = QString::null; + cmd->bar_id = 0; + cmd->menu_id = MenuPhones; + cmd->menu_grp = 0x1010; + cmd->popup_id = MenuPhoneState; + cmd->flags = COMMAND_DEFAULT; + EventCommandCreate(cmd).process(); + + EventMenu(MenuPhoneState, EventMenu::eAdd).process(); + + cmd->id = CmdPhoneNoShow; + cmd->text = I18N_NOOP("&No show"); + cmd->icon = QString::null; + cmd->icon_on = QString::null; + cmd->bar_id = 0; + cmd->menu_id = MenuPhoneState; + cmd->menu_grp = 0x1000; + cmd->popup_id = 0; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdPhoneAvailable; + cmd->text = I18N_NOOP("&Available"); + cmd->icon = "phone"; + cmd->bar_id = 0; + cmd->menu_id = MenuPhoneState; + cmd->menu_grp = 0x1001; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdPhoneBusy; + cmd->text = I18N_NOOP("&Busy"); + cmd->icon = "nophone"; + cmd->bar_id = 0; + cmd->menu_id = MenuPhoneState; + cmd->menu_grp = 0x1002; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdPhoneBook; + cmd->text = I18N_NOOP("&Phone book"); + cmd->icon = QString::null; + cmd->icon_on = QString::null; + cmd->bar_id = 0; + cmd->menu_id = MenuPhones; + cmd->menu_grp = 0x1020; + cmd->popup_id = 0; + cmd->flags = COMMAND_DEFAULT; + EventCommandCreate(cmd).process(); +} + +bool CorePlugin::updateMainToolbar(unsigned long commandID) +{ + bool bUpdateAll = (commandID == ~((unsigned long) 0)); + + if ( ( commandID == CmdGroupToolbarButton ) || bUpdateAll ) + { + Command cmd; + cmd->id = CmdGroupToolbarButton; + cmd->text = I18N_NOOP("&Groups"); + cmd->icon = value("GroupMode").toUInt() ? "grp_on" : "grp_off"; + cmd->bar_id = ToolBarMain; + cmd->bar_grp = 0x4000; + cmd->menu_id = 0; + cmd->menu_grp = 0; + cmd->popup_id = MenuGroups; + EventCommandChange(cmd).process(); + } + + if ( ( commandID == CmdOnline ) || bUpdateAll ) + { + Command cmd; + cmd->id = CmdOnline; + cmd->text = I18N_NOOP("Show &offline"); + cmd->icon = "online_off"; + cmd->icon_on = "online_on"; + cmd->bar_id = ToolBarMain; + cmd->bar_grp = 0x4000; + cmd->menu_id = MenuGroups; + cmd->menu_grp = 0x8000; + cmd->flags = COMMAND_CHECK_STATE; + if (value("ShowOnLine").toBool()) cmd->flags |= COMMAND_CHECKED; + EventCommandChange(cmd).process(); + } + return bUpdateAll; +} diff --git a/plugins/_core/toolbar_msgedit.cpp b/plugins/_core/toolbar_msgedit.cpp new file mode 100644 index 0000000..f582a0b --- /dev/null +++ b/plugins/_core/toolbar_msgedit.cpp @@ -0,0 +1,196 @@ +/*************************************************************************** + toolbar_msgedit.cpp + + This file contains subroutine that creates toolbar for MsgEdit part of + chat window. + Note that not all items of that menu created here. Some items is a result + of some other actions. Such items only mentions as a comments here, with + specifing where the item is relly created. + ------------------- + begin : Tue Nov 26 2008 + based on : core.cpp of Sim-IM by Vladimir Shutoff + and Sim-IM team + copyright : (C) 2002 - 2004 Vladimir Shutoff + (C) 2004 - 2008 Sim-IM Development Team + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "core.h" +#include "simgui/textshow.h" // for CmdBgColor and all others... +#include "icons.h" // for getIcons(), getSmiles() +using namespace SIM; + +void CorePlugin::createMsgEditToolbar() +{ + Command cmd; + + EventToolbar(ToolBarMsgEdit, EventToolbar::eAdd).process(); + + cmd->id = CmdBgColor; + cmd->text = I18N_NOOP("Back&ground color"); + cmd->icon = "bgcolor"; + cmd->icon_on = QString::null; + cmd->bar_id = ToolBarMsgEdit; + cmd->bar_grp = 0x1000; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdFgColor; + cmd->text = I18N_NOOP("Fo®round color"); + cmd->icon = "fgcolor"; + cmd->bar_id = ToolBarMsgEdit; + cmd->bar_grp = 0x1001; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdBold; + cmd->text = I18N_NOOP("&Bold"); + cmd->icon = "text_bold"; + cmd->icon_on = "text_bold"; + cmd->bar_id = ToolBarMsgEdit; + cmd->bar_grp = 0x1002; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdItalic; + cmd->text = I18N_NOOP("It&alic"); + cmd->icon = "text_italic"; + cmd->icon_on = "text_italic"; + cmd->bar_id = ToolBarMsgEdit; + cmd->bar_grp = 0x1003; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdUnderline; + cmd->text = I18N_NOOP("&Underline"); + cmd->icon = "text_under"; + cmd->icon_on = "text_under"; + cmd->bar_id = ToolBarMsgEdit; + cmd->bar_grp = 0x1004; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdFont; + cmd->text = I18N_NOOP("Select f&ont"); + cmd->icon = "text"; + cmd->icon_on = QString::null; + cmd->bar_id = ToolBarMsgEdit; + cmd->bar_grp = 0x1005; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdFileName; + cmd->text = I18N_NOOP("Select &file"); + cmd->icon = "file"; + cmd->icon_on = QString::null; + cmd->bar_id = ToolBarMsgEdit; + cmd->bar_grp = 0x1010; + cmd->flags = BTN_EDIT | COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdPhoneNumber; + cmd->text = I18N_NOOP("&Phone number"); + cmd->icon = "cell"; + cmd->icon_on = QString::null; + cmd->bar_id = ToolBarMsgEdit; + cmd->bar_grp = 0x1020; + cmd->flags = BTN_COMBO | BTN_NO_BUTTON | COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + /***** URL (CmdUrlInput, grp=0x1030) *****/ + // Toolbar item 'URL' is created in plugins/icq/icqmessage.cpp in function ICQPlugin::registerMessages() + // And this item will exist even if icq plugin is not loaded. Because it were loaded while initing Sim-IM + // and 'URL' menu item were created. Then it was not destroed somehow. + // FIXME: may be 'URL' toolbar item _should_ be destroed when icq plugin is unloaded. Check it. + + // **** Quote (CmdMsgQuote + CmdReceived, grp=0x1041) *****/ + // Theoreticly another toolbar item should be created here... It is "Quote" item, and it is created while + // creating MenuMsgCommand. But (FIXME:) for some reason this item is missing when looking at item list + // when costumising toolbar. Why I do not know.... + + /***** Forward (CmdMsgForward + CmdReceived, grp=0x1042) *****/ + // Same as Quote. (FIXME: see fixme note for Quote few lines beforee) + + /***** Grant (CmdGrantAuth, grp=0x1080) *****/ + // Toolbar item is defined at msgedit.cpp in authRequestCommands structure and created at MsgEdit::setupMessages + // while creating MessageAuthRequest. So make sure MsgEdit::setupMessages is called after createMsgEditToolbar() + + /***** Refuse (CmdRefuseAuth, grp=0x1081) *****/ + // Same as for Grant. + + /***** Accept (CmdFileAccept, grp=0x1090) *****/ + // Toolbar item is defined at msgedit.cpp in fileCommands structure and created at MsgEdit::setupMessages + // while creating MessageFile. So make sure MsgEdit::setupMessages is called after createMsgEditToolbar() + + /***** Decline (CmdFileDecline, grp=0x1091) *****/ + // Same as for Accept. + + cmd->id = CmdSmile; + cmd->text = I18N_NOOP("I&nsert smile"); + cmd->icon = QString::null; + cmd->bar_id = ToolBarMsgEdit; + cmd->bar_grp = 0x7000; + cmd->flags = COMMAND_CHECK_STATE; + // Now checking are there any smile icons... if yes use one as item icon, if no hide 'Insert Smile' toolbar item + QStringList smiles; + getIcons()->getSmiles(smiles); + if (smiles.empty()) cmd->flags |= BTN_HIDE; + else cmd->icon = smiles.front(); + EventCommandCreate(cmd).process(); + + cmd->id = CmdTranslit; + cmd->text = I18N_NOOP("Send in &translit"); + cmd->icon = "translit"; + cmd->icon_on = "translit"; + cmd->bar_id = ToolBarMsgEdit; + cmd->bar_grp = 0x7010; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdSendClose; + cmd->text = I18N_NOOP("C&lose after send"); + cmd->icon = "fileclose"; + cmd->icon_on = "fileclose"; + cmd->bar_id = ToolBarMsgEdit; + cmd->bar_grp = 0x7020; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdSend; + cmd->text = I18N_NOOP("&Send"); + cmd->icon = "mail_generic"; + cmd->icon_on = QString::null; + cmd->bar_id = ToolBarMsgEdit; + cmd->bar_grp = 0x8000; + cmd->flags = BTN_PICT | COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdNextMessage; + cmd->text = I18N_NOOP("&Next"); + cmd->icon = "message"; + cmd->bar_id = ToolBarMsgEdit; + cmd->bar_grp = 0x8000; + cmd->flags = BTN_PICT | COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + /***** Answer (CmdMsgAnswer grp= 0x8000) *****/ + // This toolbar item is created while creating MenuMsgCommand + + cmd->id = CmdMultiply; + cmd->text = I18N_NOOP("Multi&ply send"); + cmd->icon = "1rightarrow"; + cmd->icon_on = "1leftarrow"; + cmd->bar_id = ToolBarMsgEdit; + cmd->bar_grp = 0xF010; + cmd->flags = COMMAND_DEFAULT; + EventCommandCreate(cmd).process(); +} + diff --git a/plugins/_core/toolbar_textedit.cpp b/plugins/_core/toolbar_textedit.cpp new file mode 100644 index 0000000..65cb1a7 --- /dev/null +++ b/plugins/_core/toolbar_textedit.cpp @@ -0,0 +1,88 @@ +/*************************************************************************** + toolbar_textedit.cpp + + This file contains subroutine that creates ToolBarTextEdit toolbar and + fills that toolbar with toolbar items. This toolbar is used as a default + toolbar for RichTextEdit (sim/textshow.cpp), but I (shaplov) have not + found any plase where this toolbar is really shown, so: + TODO: Check if this toolbar is really used, and may be remove it as unused code. + ------------------- + begin : Tue Nov 26 2008 + based on : core.cpp of Sim-IM by Vladimir Shutoff + and Sim-IM team + copyright : (C) 2002 - 2004 Vladimir Shutoff + (C) 2004 - 2008 Sim-IM Development Team + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +#include "core.h" +#include "simgui/textshow.h" // for CmdBgColor and all others... + +using namespace SIM; + +void CorePlugin::createTextEditToolbar() +{ + EventToolbar(ToolBarTextEdit, EventToolbar::eAdd).process(); + + Command cmd; + + cmd->id = CmdBgColor; + cmd->text = I18N_NOOP("Back&ground color"); + cmd->icon = "bgcolor"; + cmd->icon_on = QString::null; + cmd->bar_id = ToolBarTextEdit; + cmd->bar_grp = 0x1000; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdFgColor; + cmd->text = I18N_NOOP("Fo®round color"); + cmd->icon = "fgcolor"; + cmd->bar_id = ToolBarTextEdit; + cmd->bar_grp = 0x1010; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdBold; + cmd->text = I18N_NOOP("&Bold"); + cmd->icon = "text_bold"; + cmd->icon_on = "text_bold"; + cmd->bar_id = ToolBarTextEdit; + cmd->bar_grp = 0x2000; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdItalic; + cmd->text = I18N_NOOP("It&alic"); + cmd->icon = "text_italic"; + cmd->icon_on = "text_italic"; + cmd->bar_id = ToolBarTextEdit; + cmd->bar_grp = 0x2010; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdUnderline; + cmd->text = I18N_NOOP("&Underline"); + cmd->icon = "text_under"; + cmd->icon_on = "text_under"; + cmd->bar_id = ToolBarTextEdit; + cmd->bar_grp = 0x2020; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdFont; + cmd->text = I18N_NOOP("Select f&ont"); + cmd->icon = "text"; + cmd->icon_on = "text"; + cmd->bar_id = ToolBarTextEdit; + cmd->bar_grp = 0x3000; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); +} diff --git a/plugins/_core/toolbarcfg.cpp b/plugins/_core/toolbarcfg.cpp new file mode 100644 index 0000000..40103ac --- /dev/null +++ b/plugins/_core/toolbarcfg.cpp @@ -0,0 +1,52 @@ +/*************************************************************************** + toolbarcfg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "misc.h" + +#include "toolbarcfg.h" + +#include +#include +#include + +ToolbarsCfg::ToolbarsCfg() +{ + qApp->installEventFilter(this); +} + +ToolbarsCfg::~ToolbarsCfg() +{ +} + +bool ToolbarsCfg::eventFilter(QObject *o, QEvent *e) +{ + if((e->type() == QEvent::Show) && o->inherits("CMenu")) + { + QObject *parent = o->parent(); + if(parent && (parent->inherits("MainWindow") || parent->inherits("CToolBar"))) + { + QMenu *popup = static_cast(o); + popup->addAction(i18n("Customize toolbar..."), this, SLOT(popupActivated())); + } + } + return QObject::eventFilter(o, e); +} + +void ToolbarsCfg::popupActivated() +{ +} + diff --git a/plugins/_core/toolbarcfg.h b/plugins/_core/toolbarcfg.h new file mode 100644 index 0000000..5897f83 --- /dev/null +++ b/plugins/_core/toolbarcfg.h @@ -0,0 +1,38 @@ +/*************************************************************************** + toolbarcfg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _TOOLBARCFG_H +#define _TOOLBARCFG_H + +#include "qobject.h" + +#include + +class ToolbarsCfg : public QObject +{ + Q_OBJECT +public: + ToolbarsCfg(); + virtual ~ToolbarsCfg(); +protected slots: + void popupActivated(); +protected: + bool eventFilter(QObject *o, QEvent *e); +}; + +#endif + diff --git a/plugins/_core/toolsetup.cpp b/plugins/_core/toolsetup.cpp new file mode 100644 index 0000000..2f63b37 --- /dev/null +++ b/plugins/_core/toolsetup.cpp @@ -0,0 +1,258 @@ +/*************************************************************************** + toolsetup.cpp - description + ------------------- + begin : Sun Mar 24 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "cmddef.h" +#include "icons.h" +#include "misc.h" + +#include "toolsetup.h" +#include "commands.h" + + +#include +#include +#include + +using namespace std; +using namespace SIM; + +ToolBarSetup::ToolBarSetup(Commands *bars, CommandsDef *def) : QDialog(NULL) +{ + setupUi(this); + setObjectName("toolbar_setup"); + SET_WNDPROC("configure") + setWindowIcon(Icon("configure")); + setWindowTitle(def->isMenu() ? + i18n("Customize menu") : + i18n("Customize toolbar")); + + setButtonsPict(this); + m_def = def; + m_bars = bars; + + CommandsList list(*m_def); + CommandDef *s; + while ((s = ++list) != NULL){ + if (s->id && (s->text.isEmpty())) + continue; + active.push_back(s->id); + } + + setWindowIcon(Icon("setup")); + connect(btnClose, SIGNAL(clicked()), this, SLOT(close())); + connect(lstButtons, SIGNAL(itemSelectionChanged()), this, SLOT(selectionChanged())); + connect(lstActive, SIGNAL(itemSelectionChanged()), this, SLOT(selectionChanged())); + connect(btnAdd, SIGNAL(clicked()), this, SLOT(addClick())); + connect(btnRemove, SIGNAL(clicked()), this, SLOT(removeClick())); + connect(btnUp, SIGNAL(clicked()), this, SLOT(upClick())); + connect(btnDown, SIGNAL(clicked()), this, SLOT(downClick())); + connect(btnOk, SIGNAL(clicked()), this, SLOT(okClick())); + connect(btnApply, SIGNAL(clicked()), this, SLOT(applyClick())); + + setButtons(); + lstActive->clear(); + for (vector::iterator it = active.begin(); it != active.end(); ++it) + addButton(lstActive, *it); + + selectionChanged(); + bDirty = false; +} + +ToolBarSetup::~ToolBarSetup() +{ +} + +void ToolBarSetup::okClick() +{ + applyClick(); + close(); +} + +void ToolBarSetup::applyClick() +{ + if (bDirty) + { + QByteArray config; + vector::iterator it; + for (it = active.begin(); it != active.end(); ++it){ + if (config.length()) + config += ','; + config += QByteArray::number(*it); + } + bool bFirst = true; + CommandsList list(*m_def, true); + CommandDef *s; + while ((s = ++list) != NULL){ + if ((s->id == 0) || ((m_def->isMenu() ? s->menu_grp : s->bar_grp) == 0)) + continue; + unsigned id = s->id; + for (it = active.begin(); it != active.end(); ++it) + if ((*it) == id) + break; + if (it != active.end()) + continue; + if (bFirst){ + config += '/'; + bFirst = false; + }else{ + config += ','; + } + config += QByteArray::number(id); + } + m_def->setConfig(QString(config)); + m_bars->set(m_def, config); + bDirty = false; + } +} + +void ToolBarSetup::addButton(QListWidget *lst, unsigned id) +{ + if (id == 0){ + QListWidgetItem* item = new QListWidgetItem(i18n("Separator"), lst); + item->setIcon(Pict("separator")); + lst->addItem(item); + return; + } + CommandsList list(*m_def, true); + CommandDef *s; + while ((s = ++list) != NULL){ + if ((s->id == id) && !s->text.isEmpty()){ + QString name = i18n(s->text); + name = name.remove('&'); + QListWidgetItem* item = new QListWidgetItem(name, lst); + if (!s->icon.isEmpty()){ + item->setIcon(Pict(s->icon)); + } + return; + } + } +} + +void ToolBarSetup::selectionChanged() +{ + //orig + /* + btnAdd->setEnabled(lstButtons->currentItem() >= 0); + btnRemove->setEnabled(lstActive->currentItem() >= 0); + btnUp->setEnabled(lstActive->currentItem() > 0); + */ + + /* new*/ + btnAdd->setEnabled(lstButtons->count() >= 0); + btnRemove->setEnabled(lstActive->count() >= 0); + btnUp->setEnabled(lstActive->currentRow() > 0); + + btnDown->setEnabled((lstActive->currentRow() >= 0) && + (lstActive->currentRow() < (int)(lstActive->count() - 1))); +} + +void ToolBarSetup::setButtons() +{ + lstButtons->clear(); + CommandsList list(*m_def, true); + CommandDef *s; + while ((s = ++list) != NULL){ + unsigned id = s->id; + vector::iterator it_active; + for (it_active = active.begin(); it_active != active.end(); ++it_active) + if ((*it_active) == id) + break; + if (it_active != active.end()) + continue; + addButton(lstButtons, id); + } + addButton(lstButtons, 0); +} + +void ToolBarSetup::addClick() +{ + int i = lstButtons->currentRow(); + if (i < 0) + return; + if (i == (int)(lstButtons->count() - 1)) + { + active.push_back(0); + addButton(lstActive, 0); + lstActive->setCurrentRow(lstActive->count() - 1); + return; + } + int n = i; + CommandsList list(*m_def, true); + CommandDef *s; + while (((s = ++list) != NULL) && (i >= 0)){ + unsigned id = s->id; + vector::iterator it_active; + for (it_active = active.begin(); it_active != active.end(); ++it_active) + if ((*it_active) == id) + break; + if (it_active != active.end()) + continue; + if (i-- == 0){ + active.push_back(id); + addButton(lstActive, id); + delete lstButtons->item(n); + lstActive->setCurrentRow(lstActive->count() - 1); + bDirty = true; + return; + } + } +} + +void ToolBarSetup::removeClick() +{ + int i = lstActive->currentRow(); + if (i < 0) return; + delete lstActive->item(i); + vector::iterator it = active.begin(); + for (; i > 0; i--, ++it) {}; + active.erase(it); + setButtons(); + bDirty = true; +} + +void ToolBarSetup::upClick() +{ + int i = lstActive->currentRow(); + if (i <= 0) return; + + lstActive->insertItem ( i - 1, lstActive->takeItem ( i ) ); + lstActive->setCurrentRow(i - 1); + + unsigned old = active[i - 1]; + active[i - 1] = active[i]; + active[i] = old; + + bDirty = true; +} + +void ToolBarSetup::downClick() +{ + int i = lstActive->currentRow(); + if ((i < 0) || (i >= (int)(lstActive->count() - 1))) return; + + lstActive->insertItem ( i + 1, lstActive->takeItem ( i ) ); + lstActive->setCurrentRow(i + 1); + + unsigned old = active[i + 1]; + active[i + 1] = active[i]; + active[i] = old; + + bDirty = true; +} + +// vim: set expandtab: + diff --git a/plugins/_core/toolsetup.h b/plugins/_core/toolsetup.h new file mode 100644 index 0000000..506177d --- /dev/null +++ b/plugins/_core/toolsetup.h @@ -0,0 +1,53 @@ +/*************************************************************************** + toolsetup.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _TOOLSETUP_H +#define _TOOLSETUP_H + +#include + +#include "event.h" +#include "ui_toolsetupbase.h" + +class Commands; + +class ToolBarSetup : public QDialog, public Ui::ToolBarSetup +{ + Q_OBJECT +public: + ToolBarSetup(Commands*, SIM::CommandsDef*); + ~ToolBarSetup(); +protected slots: + void selectionChanged(); + void addClick(); + void removeClick(); + void upClick(); + void downClick(); + void applyClick(); + void okClick(); +protected: + SIM::CommandsDef *m_def; + Commands *m_bars; + std::vector active; + bool bDirty; + void addButton(QListWidget *lst, unsigned id); + void setButtons(); + friend class Commands; +}; + +#endif + diff --git a/plugins/_core/toolsetupbase.ui b/plugins/_core/toolsetupbase.ui new file mode 100644 index 0000000..6757730 --- /dev/null +++ b/plugins/_core/toolsetupbase.ui @@ -0,0 +1,256 @@ + + + ToolBarSetup + + + + 0 + 0 + 551 + 300 + + + + Toolbar setup + + + + 6 + + + 11 + + + + + 6 + + + 0 + + + + + 6 + + + 0 + + + + + All buttons: + + + false + + + + + + + + + + + + 6 + + + 0 + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + &Add -> + + + + + + + <- &Remove + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + + 6 + + + 0 + + + + + Active: + + + false + + + + + + + + + + + + 6 + + + 0 + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + &Up + + + + + + + &Down + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + + + + QFrame::HLine + + + QFrame::Sunken + + + + + + + 6 + + + 0 + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + &Apply + + + + + + + &OK + + + true + + + + + + + &Close + + + + + + + + qPixmapFromMimeSource + + + diff --git a/plugins/_core/usercfg.cpp b/plugins/_core/usercfg.cpp new file mode 100644 index 0000000..d6fee77 --- /dev/null +++ b/plugins/_core/usercfg.cpp @@ -0,0 +1,624 @@ +/*************************************************************************** + usercfg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "icons.h" +#include "usercfg.h" +#include "prefcfg.h" +#include "maininfo.h" +#include "core.h" +#include "arcfg.h" +#include "log.h" +#include "contacts/clientdataiterator.h" +#include "contacts/contact.h" +#include "contacts/group.h" +#include "contacts/client.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace SIM; + +class ConfigItem : public QTreeWidgetItem +{ +public: + ConfigItem(QTreeWidgetItem *item, bool bShowUpdate = false); + ConfigItem(QTreeWidget *view, bool bShowUpdate = false); + ~ConfigItem(); + void show(); + unsigned id() { return m_id; } + static unsigned curIndex; +protected: + unsigned m_id; + bool m_bShowUpdate; + static unsigned defId; + void init(); + virtual QWidget *getWidget(UserConfig *dlg); + QWidget *m_widget; +}; + +unsigned ConfigItem::defId = 0x10000; +unsigned ConfigItem::curIndex; + +ConfigItem::ConfigItem(QTreeWidget *view, bool bShowUpdate) + : QTreeWidgetItem(view) + , m_bShowUpdate(bShowUpdate) +{ + init(); +} + +ConfigItem::ConfigItem(QTreeWidgetItem *item, bool bShowUpdate) + : QTreeWidgetItem(item) + , m_widget(NULL) + , m_bShowUpdate(bShowUpdate) +{ + init(); +} + +ConfigItem::~ConfigItem() +{ + //delete m_widget; +} + +void ConfigItem::init() +{ + QString key = QString::number(++curIndex); + while (key.length() < 4) + key = '0' + key; + setText(1, key); +} + +void ConfigItem::show() +{ + UserConfig *dlg = qobject_cast(treeWidget()->topLevelWidget()); + if(!dlg) + return; + if(m_widget == NULL) + { + m_widget = getWidget(dlg); //Fixme: Crash, second time: m_widget is 0xcccccc + if (m_widget == NULL) + return; + m_id = dlg->wnd->addWidget(m_widget/*, id() ? id() : defId++*/); + dlg->wnd->setMinimumSize(dlg->wnd->sizeHint()); + QObject::connect(dlg, SIGNAL(applyChanges()), m_widget, SLOT(apply())); + } + dlg->showUpdate(m_bShowUpdate); + dlg->wnd->setCurrentWidget(m_widget); +} + +QWidget *ConfigItem::getWidget(UserConfig *dlg) +{ + return dlg; //Fixme +} + +class PrefItem : public ConfigItem +{ +public: + PrefItem(QTreeWidgetItem *parent, CommandDef *cmd); +protected: + virtual QWidget *getWidget(UserConfig *dlg); + CommandDef *m_cmd; +}; + +PrefItem::PrefItem(QTreeWidgetItem *parent, CommandDef *cmd) + : ConfigItem(parent) +{ + m_cmd = cmd; + QString title = i18n(cmd->text); + title = title.remove('&'); + setText(0, title); + setIcon(0, Pict(cmd->icon)); +} + +QWidget *PrefItem::getWidget(UserConfig *dlg) +{ + return new PrefConfig(dlg->wnd, m_cmd, dlg->m_contact, dlg->m_group); +} + +class ClientItem : public ConfigItem +{ +public: + ClientItem(QTreeWidget *view, Client *client, void *_data, CommandDef *cmd); + ClientItem(QTreeWidgetItem *item, Client *client, void *_data, CommandDef *cmd); +protected: + void init(CommandDef *cmd); + virtual QWidget *getWidget(UserConfig *dlg); + Client *m_client; + void *m_data; + CommandDef *m_cmd; +}; + +ClientItem::ClientItem(QTreeWidget *view, Client *client, void *data, CommandDef *cmd) + : ConfigItem(view, true) +{ + m_client = client; + m_data = data; + init(cmd); +} + +ClientItem::ClientItem(QTreeWidgetItem *item, Client *client, void *data, CommandDef *cmd) + : ConfigItem(item, true) +{ + m_client = client; + m_data = data; + init(cmd); +} + +void ClientItem::init(CommandDef *cmd) +{ + m_cmd = cmd; + if (!cmd->text_wrk.isEmpty()){ + setText(0, cmd->text_wrk); + cmd->text_wrk = QString::null; + }else{ + setText(0, i18n(cmd->text)); + } + if (!cmd->icon.isEmpty()) + setIcon(0, Pict(cmd->icon)); +} + +QWidget *ClientItem::getWidget(UserConfig *dlg) +{ + void *data = m_data; + Client *client = dlg->m_contact->clientData.activeClient(data, m_client); + if (client == NULL) + return NULL; + return client->infoWindow(dlg, dlg->m_contact, data, m_cmd->id); +} + +class MainInfoItem : public ConfigItem +{ +public: + MainInfoItem(QTreeWidget *view, unsigned id); +protected: + virtual QWidget *getWidget(UserConfig *dlg); +}; + +MainInfoItem::MainInfoItem(QTreeWidget *view, unsigned id) + : ConfigItem(view, id) +{ + setText(0, i18n("User info")); + setIcon(0, Pict("info")); +} + +QWidget *MainInfoItem::getWidget(UserConfig *dlg) +{ + return new MainInfo(dlg, dlg->m_contact); +} + +class ARItem : public ConfigItem +{ +public: + ARItem(QTreeWidgetItem *item, const CommandDef *def); +protected: + virtual QWidget *getWidget(UserConfig *dlg); + unsigned m_status; +}; + +ARItem::ARItem(QTreeWidgetItem *item, const CommandDef *def) + : ConfigItem(item, 0) + , m_status(def->id) + +{ + QString icon; + + setText(0, i18n(def->text)); + switch (m_status){ + case STATUS_ONLINE: + icon="SIM_online"; + break; + case STATUS_AWAY: + icon="SIM_away"; + break; + case STATUS_NA: + icon="SIM_na"; + break; + case STATUS_DND: + icon="SIM_dnd"; + break; + case STATUS_OCCUPIED: + icon="SIM_occupied"; + break; + case STATUS_FFC: + icon="SIM_ffc"; + break; + case STATUS_OFFLINE: + icon="SIM_offline"; + break; + default: + icon=def->icon; + break; + } + setIcon(0, Pict(icon)); +} + +QWidget *ARItem::getWidget(UserConfig *dlg) +{ + return new ARConfig(dlg, m_status, text(0), dlg->m_contact); +} + +static unsigned itemWidth(QTreeWidgetItem *item, QFontMetrics &fm) +{ + unsigned w = fm.width(item->text(0)) + 64; + for(int i = 0; i < item->childCount(); i++) + { + QTreeWidgetItem *child = item->child(i); + w = qMax(w, itemWidth(child, fm)); + } + return w; +} + +UserConfig::UserConfig(Contact *contact, Group *group) + : QDialog (NULL) + , m_parentItem(NULL) + , m_contact (contact) + , m_group (group) + , m_nUpdates (0) +{ + setupUi(this); + setObjectName("userconfig"); + setAttribute(Qt::WA_DeleteOnClose); + setModal(false); + SET_WNDPROC("configure") + setWindowIcon(Icon(contact ? "info" : "configure")); + setButtonsPict(this); + setTitle(); + btnUpdate->setIcon(Icon("webpress")); + btnUpdate->hide(); + + lstBox->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + lstBox->sortItems(1, Qt::AscendingOrder); + lstBox->header()->hide(); + + fill(); + + connect(lstBox, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)), + this, SLOT(itemSelected(QTreeWidgetItem*, QTreeWidgetItem*))); + connect(buttonApply, SIGNAL(clicked()), this, SLOT(apply())); + connect(btnUpdate, SIGNAL(clicked()), this, SLOT(updateInfo())); + + lstBox->setCurrentItem(lstBox->topLevelItem(0)); + itemSelected(lstBox->topLevelItem(0), 0); +} + +UserConfig::~UserConfig() +{ + if (m_contact && (m_contact->getFlags() & CONTACT_TEMPORARY)) + { + Contact *contact = m_contact; + m_contact = NULL; + delete contact; + } +} + +void UserConfig::setTitle() +{ + QString title; + if (m_contact) + { + if (m_contact->id()) + title = i18n("User info '%1'") .arg(m_contact->getName()); + else + title = i18n("New contact"); + } + else + { + QString groupName; + if (m_group && m_group->id()) + groupName = m_group->getName(); + else + groupName = i18n("Not in list"); + title = i18n("Setting for group '%1'") .arg(groupName); + } + if (m_nUpdates) + { + title += ' '; + title += i18n("[Update info]"); + } + setWindowTitle(title); +} + +void UserConfig::fill() +{ + ConfigItem::curIndex = 1; + lstBox->clear(); + if (m_contact) + { + m_parentItem = new MainInfoItem(lstBox, CmdInfo); + ClientDataIterator it(m_contact->clientData); + void *data; //WUUUARH, Fixme + while ((data = ++it) != NULL) + { + Client *client = m_contact->clientData.activeClient(data, it.client()); + if (client == NULL) + continue; + CommandDef *cmds = client->infoWindows(m_contact, data); + if (cmds) + { + m_parentItem = NULL; + for (; !cmds->text.isEmpty(); cmds++) + { + if (m_parentItem) + new ClientItem(m_parentItem, it.client(), data, cmds); + else + { + m_parentItem = new ClientItem(lstBox, it.client(), data, cmds); + m_parentItem->setExpanded(true); + } + } + } + } + } + + m_parentItem = NULL; + ClientUserData* data; + if (m_contact) + data = &m_contact->clientData; + else + data = &m_group->clientData; + ClientDataIterator it(*data); + list st; + ARItem *tmp=NULL; + while (++it) + { + if ((it.client()->protocol()->description()->flags & PROTOCOL_AR_USER) == 0) + continue; + if (m_parentItem == NULL) + { + m_parentItem = new ConfigItem(lstBox, 0); + m_parentItem->setText(0, i18n("Autoreply")); + m_parentItem->setExpanded(true); + } + for (const CommandDef *d = it.client()->protocol()->statusList(); !d->text.isEmpty(); d++) + { + if ((d->id == STATUS_ONLINE) || (d->id == STATUS_OFFLINE)) + continue; + list::iterator it; + for (it = st.begin(); it != st.end(); ++it) + if ((*it) == d->id) + break; + if (it != st.end()) + continue; + st.push_back(d->id); + tmp=new ARItem(m_parentItem, d); + } + } + + delete tmp; + + m_parentItem = new ConfigItem(lstBox, 0); + m_parentItem->setText(0, i18n("Settings")); + m_parentItem->setIcon(0, Pict("configure")); + m_parentItem->setExpanded(true); + CommandDef *cmd; + CommandsMapIterator itc(CorePlugin::instance()->preferences); + m_defaultPage = 0; + while((cmd = ++itc) != NULL) + { + new PrefItem(m_parentItem, cmd); + if (m_defaultPage == 0) + m_defaultPage = cmd->id; + } + + QFontMetrics fm(lstBox->font()); + unsigned w = 0; + for(int i = 0; i < lstBox->topLevelItemCount(); i++) + { + QTreeWidgetItem *item = lstBox->topLevelItem(i); + w = qMax(w, itemWidth(item, fm)); + } + lstBox->setFixedWidth(w); + lstBox->setColumnWidth(0, w - 2); +} + +bool UserConfig::raisePage(unsigned id) +{ + for(int i = 0; i < lstBox->topLevelItemCount(); i++) + { + QTreeWidgetItem *item = lstBox->topLevelItem(i); + if (raisePage(id, item)) + return true; + } + return false; +} + +bool UserConfig::raiseDefaultPage() +{ + return raisePage(m_defaultPage); +} + +bool UserConfig::raisePage(unsigned id, QTreeWidgetItem *item) +{ + unsigned item_id = static_cast(item)->id(); + if (item_id && ((item_id == id) || (id == 0))) + { + lstBox->setCurrentItem(item); + return true; + } + for(int i = 0; i < item->childCount(); i++) + { + QTreeWidgetItem* it = item->child(i); + if (raisePage(id, it)) + return true; + } + return false; +} + +void UserConfig::apply() +{ + emit applyChanges(); + if (m_contact) + getContacts()->addContact(m_contact); + EventSaveState e; + e.process(); +} + +void UserConfig::itemSelected(QTreeWidgetItem *item, QTreeWidgetItem* /* previous */) +{ + static_cast(item)->show(); +} + +bool UserConfig::processEvent(Event *e) +{ + switch (e->type()){ + case eEventGroup: + { + EventGroup *ev = static_cast(e); + Group *group = ev->group(); + switch(ev->action()) { + case EventGroup::eDeleted: + if (group == m_group) + close(); + return false; + case EventGroup::eChanged: + if (group == m_group) + setTitle(); + return false; + case EventGroup::eAdded: + return false; + } + break; + } + case eEventContact: + { + EventContact *ec = static_cast(e); + Contact *contact = ec->contact(); + if (contact != m_contact) + break; + switch(ec->action()) { + case EventContact::eCreated: + if (m_nUpdates) + m_nUpdates--; + btnUpdate->setEnabled(m_nUpdates == 0); + setTitle(); + case EventContact::eDeleted: + close(); + break; + case EventContact::eChanged: + if (m_nUpdates) + m_nUpdates--; + btnUpdate->setEnabled(m_nUpdates == 0); + setTitle(); + break; + case EventContact::eFetchInfoFailed: + if (m_nUpdates){ + if (--m_nUpdates == 0){ + btnUpdate->setEnabled(true); + setTitle(); + } + } + break; + default: + break; + } + break; + } + case eEventCommandRemove: + { + EventCommandRemove *ecr = static_cast(e); + removeCommand(ecr->id()); + return false; + } + case eEventLanguageChanged: + case eEventPluginChanged: + case eEventClientsChanged: + fill(); + return false; + default: + break; + } + return false; +} + +void UserConfig::removeCommand(unsigned id) +{ + for(int i = 0; i < lstBox->topLevelItemCount(); i++) + { + QTreeWidgetItem *item = lstBox->topLevelItem(i); + removeCommand(id, item); + } +} + +bool UserConfig::removeCommand(unsigned id, QTreeWidgetItem *item) +{ + if (item->text(1).toUInt() == id) + { + delete item; + return true; + } + for(int i = 0; i < item->childCount(); i++) + { + QTreeWidgetItem *it= item->child(i); + if (removeCommand(id, it)) + return true; + } + return false; +} + +void UserConfig::updateInfo() +{ + if (m_nUpdates || (m_contact == NULL)) + return; + ClientDataIterator it(m_contact->clientData); + void *data; + while ((data = ++it) != NULL) + { + Client *client = m_contact->clientData.activeClient(data, it.client()); + if (client == NULL) + continue; + m_nUpdates++; + client->updateInfo(m_contact, data); + } + btnUpdate->setEnabled(m_nUpdates == 0); + setTitle(); +} + +void UserConfig::showUpdate(bool bShow) +{ + if (bShow) + { + btnUpdate->show(); + btnUpdate->setEnabled(m_nUpdates == 0); + } + else btnUpdate->hide(); + +} + +void UserConfig::accept() +{ + apply(); + QDialog::accept(); +} + +void UserConfig::resizeEvent(QResizeEvent *e) +{ + QDialog::resizeEvent(e); + /* Fixme Todin + if (isVisible()){ + CorePlugin::instance()->data.CfgGeometry[WIDTH].asLong() = width(); + CorePlugin::instance()->data.CfgGeometry[HEIGHT].asLong() = height(); + } + */ +} + +// vim: set expandtab: diff --git a/plugins/_core/usercfg.h b/plugins/_core/usercfg.h new file mode 100644 index 0000000..6842464 --- /dev/null +++ b/plugins/_core/usercfg.h @@ -0,0 +1,60 @@ +/*************************************************************************** + usercfg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _USERCFG_H +#define _USERCFG_H + +#include "ui_cfgdlgbase.h" +#include "event.h" +#include + +class CorePlugin; + +class UserConfig : public QDialog, public Ui::ConfigureDialogBase, public SIM::EventReceiver +{ + Q_OBJECT +public: + UserConfig(SIM::Contact *conatct, SIM::Group *group); + ~UserConfig(); + SIM::Contact *m_contact; + SIM::Group *m_group; + bool raisePage(unsigned id); + bool raiseDefaultPage(); + void showUpdate(bool); +signals: + void applyChanges(); +protected slots: + void apply(); + void itemSelected(QTreeWidgetItem*, QTreeWidgetItem*); + void updateInfo(); +protected: + virtual void accept(); + virtual bool processEvent(SIM::Event*); + void resizeEvent(QResizeEvent*); + void setTitle(); + void fill(); + unsigned m_nUpdates; + unsigned m_defaultPage; + bool raisePage(unsigned id, QTreeWidgetItem*); + void removeCommand(unsigned id); + bool removeCommand(unsigned id, QTreeWidgetItem*); +private: + QTreeWidgetItem *m_parentItem; +}; + +#endif + diff --git a/plugins/_core/userhistorycfg.cpp b/plugins/_core/userhistorycfg.cpp new file mode 100644 index 0000000..ef25cd8 --- /dev/null +++ b/plugins/_core/userhistorycfg.cpp @@ -0,0 +1,70 @@ +/*************************************************************************** + userhistorycfg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "userhistorycfg.h" +#include "core.h" + +#include +#include +#include + +UserHistoryCfg::UserHistoryCfg(QWidget *parent, SIM::PropertyHubPtr data) : QWidget(parent) + //: UserHistoryCfgBase(parent) +{ + setupUi(this); + chkDays->setChecked(data->value("CutDays").toBool()); + chkSize->setChecked(data->value("CutSize").toBool()); + edtDays->setValue(data->value("Days").toUInt()); + edtSize->setValue(data->value("MaxSize").toUInt()); + toggledDays(chkDays->isChecked()); + toggledSize(chkSize->isChecked()); + connect(chkDays, SIGNAL(toggled(bool)), this, SLOT(toggledDays(bool))); + connect(chkSize, SIGNAL(toggled(bool)), this, SLOT(toggledSize(bool))); +} + +UserHistoryCfg::~UserHistoryCfg() +{ +} + +void UserHistoryCfg::apply(SIM::PropertyHubPtr data) +{ + data->setValue("CutDays", chkDays->isChecked()); + data->setValue("CutSize", chkSize->isChecked()); + data->setValue("Days", edtDays->text().toUInt()); + data->setValue("MaxSize", edtSize->text().toUInt()); +} + +void UserHistoryCfg::toggledDays(bool bState) +{ + lblDays->setEnabled(bState); + lblDays1->setEnabled(bState); + edtDays->setEnabled(bState); +} + +void UserHistoryCfg::toggledSize(bool bState) +{ + lblSize->setEnabled(bState); + lblSize1->setEnabled(bState); + edtSize->setEnabled(bState); +} + +/* +#ifndef NO_MOC_INCLUDES +#include "userhistorycfg.moc" +#endif +*/ + diff --git a/plugins/_core/userhistorycfg.h b/plugins/_core/userhistorycfg.h new file mode 100644 index 0000000..5505131 --- /dev/null +++ b/plugins/_core/userhistorycfg.h @@ -0,0 +1,40 @@ +/*************************************************************************** + userhistorycfg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _USERHISTORYCFG_H +#define _USERHISTORYCFG_H + + +#include "propertyhub.h" +#include "ui_userhistorycfgbase.h" + +class UserHistoryCfg : public QWidget, public Ui::UserHistoryCfgBase +{ + Q_OBJECT +public: + UserHistoryCfg(QWidget *parent, SIM::PropertyHubPtr data); + ~UserHistoryCfg(); +public slots: + void apply(SIM::PropertyHubPtr data); + void toggledDays(bool); + void toggledSize(bool); +protected: + SIM::PropertyHubPtr m_data; +}; + +#endif + diff --git a/plugins/_core/userhistorycfgbase.ui b/plugins/_core/userhistorycfgbase.ui new file mode 100644 index 0000000..88b0be3 --- /dev/null +++ b/plugins/_core/userhistorycfgbase.ui @@ -0,0 +1,158 @@ + + + + + UserHistoryCfgBase + + + + 0 + 0 + 285 + 145 + + + + Form1 + + + + 11 + + + 6 + + + + + 1000 + + + + + + + Mb + + + false + + + + + + + + + + + + + + Max history file size + + + Qt::AlignVCenter|Qt::AlignRight + + + false + + + + + + + 1000 + + + + + + + days + + + false + + + + + + + Keep history + + + Qt::AlignVCenter|Qt::AlignRight + + + false + + + + + + + + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Horizontal + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Vertical + + + + + + + + QWidget + QWidget +
QWidget
+ + -1 + -1 + + 0 + + 5 + 5 + + image0 + + text + +
+
+ + + 789c6dd2c10ac2300c00d07bbf2234b7229d1be245fc04c5a3201e4615f430059d0711ff5ddb2e6bb236ec90eed134cb5a19d8ef36602af5ecdbfeeac05dda0798d3abebde87e3faa374d3807fa0d633a52d38d8de6f679fe33fc776e196f53cd010188256a3600a292882096246517815ca99884606e18044a3a40d91824820924265a7923a2e8bcd05f33db1173e002913175f2a6be6d3294871a2d95fa00e8a94ee017b69d339d90df1e77c57ea072ede6758 + + +
diff --git a/plugins/_core/userlist.cpp b/plugins/_core/userlist.cpp new file mode 100644 index 0000000..691c4b5 --- /dev/null +++ b/plugins/_core/userlist.cpp @@ -0,0 +1,1162 @@ +/*************************************************************************** + userlist.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "userlist.h" +#include "core.h" +#include "icons.h" +#include "userview.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "contacts/contact.h" +#include "contacts/group.h" + +using namespace std; +using namespace SIM; + +UserViewItemBase::UserViewItemBase(UserListBase *parent) + : ListViewItem(parent) +{ +} + +UserViewItemBase::UserViewItemBase(UserViewItemBase *parent) + : ListViewItem(parent) +{ +} + +void UserViewItemBase::setup() +{ +} + +void UserViewItemBase::setCheckable( bool bCheckable ) { + if( bCheckable ) { + setFlags( flags() | Qt::ItemIsUserCheckable ); + setCheckState( 0, Qt::Unchecked ); + } + else { + setFlags( flags() & ~Qt::ItemIsUserCheckable ); + } +} + +DivItem::DivItem(UserListBase *view, unsigned type) + : UserViewItemBase(view) +{ + m_type = type; + setText(0, QString::number(m_type)); + setExpandable(true); + //setSelectable(false); +} + +QVariant DivItem::data( int column, int role ) const +{ + QVariant result; + + switch( role ) + { + case Qt::DisplayRole : { + QString text; + switch( m_type ) + { + case DIV_ONLINE: + text = i18n("Online"); + break; + case DIV_OFFLINE: + text = i18n("Offline"); + break; + } + result = QVariant( text ); + break; + } + default : + return UserViewItemBase::data( column, role ); + } + + return result; +} + +GroupItem::GroupItem(UserListBase *view, Group *grp, bool bOffline, bool bCheckable ) + : UserViewItemBase(view) +{ + m_id = grp->id(); + m_bOffline = bOffline; + init(grp); + setCheckable( bCheckable ); +} + +GroupItem::GroupItem( UserViewItemBase *view, Group *grp, bool bOffline, bool bCheckable ) + : UserViewItemBase(view) +{ + m_id = grp->id(); + m_bOffline = bOffline; + init(grp); + setCheckable( bCheckable ); +} + +void GroupItem::init(Group *grp) +{ + m_unread = 0; + m_nContacts = 0; + m_nContactsOnline = 0; + setExpandable(true); + //setSelectable(true); + SIM::PropertyHubPtr data = grp->getUserData("list"); + if (data.isNull()){ + setOpen(true); + }else{ + if (m_bOffline){ + setOpen(data->value("OfflineOpen").toBool()); + }else{ + setOpen(data->value("OnlineOpen").toBool()); + } + } + update(grp, true); +} + +void GroupItem::update(Group *grp, bool bInit) +{ + QString s; + s = "A"; + if (grp->id()){ + s = QString::number(getContacts()->groupIndex(grp->id())); + while (s.length() < 12){ + s = QString("0") + s; + } + } + if (s == text(0)) + return; + setText(0, s); + if (bInit) + return; + ListViewItem *p = static_cast(parent()); + if (p){ + //p->sort(); + return; + } + //listView()->sort(); +} + +void GroupItem::setOpen(bool bOpen) +{ + //UserViewItemBase::setOpen(bOpen); + Group *grp = getContacts()->group(m_id); + if (grp){ + SIM::PropertyHubPtr data = grp->getUserData("list", !bOpen); + if (!data.isNull()){ + if (m_bOffline){ + data->setValue("OfflineOpen", bOpen); + }else{ + data->setValue("OnlineOpen", bOpen); + } + } + } +} + +QVariant GroupItem::data( int column, int role ) const { + QVariant result; + + switch( role ) + { + case Qt::DisplayRole : { + QString text; + if (id()){ + Group *grp = getContacts()->group(id()); + if (grp){ + text = grp->getName(); + }else{ + text = "???"; + } + }else{ + text = i18n("Not in list"); + } + if (m_nContacts){ + text += " ("; + if (m_nContactsOnline){ + text += QString::number(m_nContactsOnline); + text += '/'; + } + text += QString::number(m_nContacts); + text += ')'; + } + result = QVariant( text ); + break; + } + default : + return UserViewItemBase::data( column, role ); + } + + return result; +} + +void GroupItem::setData( int column, int role, const QVariant &value ) { + if( Qt::CheckStateRole == role ) { + Qt::CheckState cs = (Qt::CheckState)value.toInt(); + for( int i = 0 ; i < childCount() ; i++ ) { + child( i )->setCheckState( 0, cs ); + } + } + + UserViewItemBase::setData( column, role, value ); +} + +ContactItem::ContactItem( UserViewItemBase *view, Contact *contact, unsigned status, unsigned style, const QString &icons, unsigned unread, bool bCheckable ) + : UserViewItemBase(view) +{ + m_id = contact->id(); + init(contact, status, style, icons, unread); + setExpandable(false); + setCheckable( bCheckable ); + setFlags( flags() | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsSelectable ); +} + +void ContactItem::init(Contact *contact, unsigned status, unsigned style, const QString &icons, unsigned unread) +{ + m_bOnline = false; + m_bBlink = false; + update(contact, status, style, icons, unread); +} + +bool ContactItem::update(Contact *contact, unsigned status, unsigned style, const QString &icons, unsigned unread) +{ + m_unread = unread; + m_style = style; + m_status = status; + QString active; + active.sprintf("%08lX", (long unsigned int)(0xFFFFFFFF - contact->getLastActive())); + m_sExtraIcons = icons; + QString icon = getToken(m_sExtraIcons, ','); + m_Icon = Icon(icon); + setText(CONTACT_ICONS, icons); + setText(CONTACT_ACTIVE, active); + setText(CONTACT_STATUS, QString::number(9 - status)); + setup(); + return true; +} + +QString ContactItem::key(int column/*, bool ascending */) const //Fixme? +{ + if (column == 0){ + unsigned mode = CorePlugin::instance()->value("SortMode").toUInt(); + QString res; + for (;;){ + int n = 0; + switch (mode & 0xFF){ + case SORT_STATUS: + n = CONTACT_STATUS; + break; + case SORT_ACTIVE: + n = CONTACT_ACTIVE; + break; + case SORT_NAME: + n = CONTACT_TEXT; + break; + } + if (n == 0) + break; + res += text(n).toLower(); + mode = mode >> 8; + } + return res; + } + return QString::null; //UserViewItemBase::key(column, ascending); +} + +QVariant ContactItem::data( int column, int role ) const +{ + Contact *contact = getContacts()->contact( m_id ); + if( NULL == contact ) + return QVariant(); + + QVariant result; + + switch( role ) + { + case Qt::DisplayRole : { + result = QVariant( contact->getName() ); + break; + } + case Qt::DecorationRole : { + QIcon icon = m_Icon; + UserView* uv = dynamic_cast( treeWidget() ); + if( m_unread && uv->m_bUnreadBlink ) { + CommandDef *def = CorePlugin::instance()->messageTypes.find( m_unread ); + if (def) + icon = Icon( def->icon ); + } + result = QVariant( icon ); + break; + } + case Qt::ToolTipRole : { + result = QVariant( contact->tipText() ); + break; + } + case SIM::ExtraIconsRole : { + result = QVariant( m_sExtraIcons ); + break; + } + default : + return UserViewItemBase::data( column, role ); + } + + return result; +} + +UserListBase::UserListBase(QWidget *parent) + : ListView(parent) + , m_bInit (false) + , m_bDirty (false) + , m_groupMode (1) + , m_bShowOnline (false) + , m_bShowEmpty (false) + , m_bCheckable (false) + , updTimer (new QTimer(this)) + , m_contactItem (NULL) +{ + //header()->hide(); + addColumn(""); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + //setSorting(0); //Fixme + connect(updTimer, SIGNAL(timeout()), this, SLOT(drawUpdates())); + + setExpandingColumn(0); +} + +UserListBase::~UserListBase() +{ +} + +void UserListBase::drawUpdates() +{ + m_bDirty = false; + updTimer->stop(); + ListViewItem *item; +// int x = viewport()->x(); +// int y = viewport()->y(); + viewport()->setUpdatesEnabled(false); + bool bChanged = false; + list::iterator it; + for (it = updGroups.begin(); it != updGroups.end(); ++it){ + Group *group = getContacts()->group(*it); + if (group == NULL) + continue; + switch (m_groupMode){ + case 1: + item = findGroupItem(group->id()); + if (item){ + if (!m_bShowEmpty && (item->child(0) == NULL)){ + delete item; + bChanged = true; + }else{ + static_cast(item)->update(group); + addUpdatedItem(item); + } + }else{ + if (m_bShowEmpty){ + new GroupItem( this, group, true, m_bCheckable ); + bChanged = true; + } + } + break; + case 2: + for(int c = 0; c < topLevelItemCount(); c++) + { + item = static_cast(topLevelItem(c)); + UserViewItemBase *i = static_cast(item); + if (i->type() != DIV_ITEM) continue; + DivItem *divItem = static_cast(i); + GroupItem *grpItem = findGroupItem(group->id(), divItem); + if (grpItem){ + if (!m_bShowEmpty && (item->child(0) == NULL)){ + delete grpItem; + bChanged = true; + }else{ + grpItem->update(group); + addUpdatedItem(grpItem); + } + }else{ + if (m_bShowEmpty){ + new GroupItem( divItem, group, divItem->state() == DIV_OFFLINE, m_bCheckable ); + bChanged = true; + } + } + } + break; + } + } + updGroups.clear(); + DivItem *itemOnline = NULL; + DivItem *itemOffline = NULL; + if (updContacts.size()){ + if (m_groupMode != 1){ + for(int c = 0; c < topLevelItemCount(); c++) + { + item = static_cast(topLevelItem(c)); + UserViewItemBase *i = static_cast(item); + if (i->type() != DIV_ITEM) continue; + DivItem *divItem = static_cast(i); + if (divItem->state() == DIV_ONLINE) + itemOnline = divItem; + if (divItem->state() == DIV_OFFLINE) + itemOffline = divItem; + } + } + } + for (it = updContacts.begin(); it != updContacts.end(); ++it){ //Fixme, got crash: list operator not incremenable! + Contact *contact = getContacts()->contact(*it); + if (contact == NULL) + continue; + GroupItem *grpItem; + unsigned style; + QString icons; + unsigned status = getUserStatus(contact, style, icons); + unsigned unread = getUnread(contact->id()); + bool bShow = false; + SIM::PropertyHubPtr data = contact->getUserData("list"); + if (!data.isNull() && data->value("ShowAlways").toBool()) + bShow = true; + switch (m_groupMode){ + case 0: + if (status <= STATUS_OFFLINE){ + if (itemOnline){ + m_contactItem = findContactItem(contact->id(), itemOnline); + if (m_contactItem){ + deleteItem(m_contactItem); //<== crash + bChanged = true; + if (itemOnline->child(0) == NULL){ + deleteItem(itemOnline); + itemOnline = NULL; + } + } + } + if ((unread == 0) && !bShow && m_bShowOnline){ + if (itemOffline){ + m_contactItem = findContactItem(contact->id(), itemOffline); + if (m_contactItem){ + deleteItem(m_contactItem); + bChanged = true; + if (itemOffline->child(0) == NULL){ + deleteItem(itemOffline); + itemOffline = NULL; + } + } + } + break; + } + if (itemOffline == NULL){ + itemOffline = new DivItem(this, DIV_OFFLINE); + setOpen(itemOffline, true); + bChanged = true; + } + m_contactItem = findContactItem(contact->id(), itemOffline); + if (m_contactItem) + { + if (m_contactItem->update(contact, status, style, icons, unread)) + addSortItem(itemOffline); + addUpdatedItem(m_contactItem); + } + else + { + m_contactItem = new ContactItem( itemOffline, contact, status, style, icons, unread, m_bCheckable ); + bChanged = true; + } + } + else + { + if (itemOffline) + { + m_contactItem = findContactItem(contact->id(), itemOffline); + if (m_contactItem){ + deleteItem(m_contactItem); + bChanged = true; + if (itemOffline->child(0) == NULL){ + deleteItem(itemOffline); + itemOffline = NULL; + } + } + } + if (itemOnline == NULL){ + itemOnline = new DivItem(this, DIV_ONLINE); + setOpen(itemOnline, true); + bChanged = true; + } + m_contactItem = findContactItem(contact->id(), itemOnline); + if (m_contactItem) + { + if (m_contactItem->update(contact, status, style, icons, unread)) + addSortItem(itemOnline); + addUpdatedItem(m_contactItem); + } + else + { + m_contactItem = new ContactItem( itemOnline, contact, status, style, icons, unread, m_bCheckable ); + bChanged = true; + } + } + break; + case 1: + m_contactItem = findContactItem(contact->id()); + grpItem = NULL; + if (m_contactItem){ + grpItem = static_cast(m_contactItem->parent()); + if (((status <= STATUS_OFFLINE) && (unread == 0) && !bShow && m_bShowOnline) || + (contact->getGroup() != (int)grpItem->id())){ + grpItem->m_nContacts--; + if (m_contactItem->m_bOnline) + grpItem->m_nContactsOnline--; + addGroupForUpdate(grpItem->id()); + deleteItem(m_contactItem); + bChanged = true; + if (!m_bShowEmpty && (grpItem->child(0) == NULL)) + delete grpItem; + m_contactItem = NULL; + grpItem = NULL; + } + } + if ((status > STATUS_OFFLINE) || unread || bShow || !m_bShowOnline){ + if (grpItem == NULL){ + grpItem = findGroupItem(contact->getGroup()); + if (grpItem == NULL){ + Group *grp = getContacts()->group(contact->getGroup()); + if (grp){ + grpItem = new GroupItem( this, grp, true, m_bCheckable ); + bChanged = true; + } + } + } + if (grpItem){ + if (m_contactItem){ + if (m_contactItem->update(contact, status, style, icons, unread)) + addSortItem(grpItem); + addUpdatedItem(m_contactItem); + if (!m_bShowOnline && + (m_contactItem->m_bOnline != (status > STATUS_OFFLINE))){ + if (status <= STATUS_OFFLINE) + { + grpItem->m_nContactsOnline--; + m_contactItem->m_bOnline = false; + } + else + { + grpItem->m_nContactsOnline++; + m_contactItem->m_bOnline = true; + } + addGroupForUpdate(grpItem->id()); + } + } + else + { + bChanged = true; + m_contactItem = new ContactItem( grpItem, contact, status, style, icons, unread, m_bCheckable ); + grpItem->m_nContacts++; + if (!m_bShowOnline && (status > STATUS_OFFLINE)) + { + grpItem->m_nContactsOnline++; + m_contactItem->m_bOnline = true; + } + addGroupForUpdate(grpItem->id()); + } + } + } + break; + case 2: + m_contactItem = findContactItem(contact->id(), itemOnline); + grpItem = NULL; + if (m_contactItem){ + grpItem = static_cast(m_contactItem->parent()); + if ((status <= STATUS_OFFLINE) || ((int)grpItem->id() != contact->getGroup())){ + grpItem->m_nContacts--; + addGroupForUpdate(grpItem->id()); + deleteItem(m_contactItem); + bChanged = true; + if (!m_bShowEmpty && (grpItem->child(0) == NULL)) + delete grpItem; + grpItem = NULL; + m_contactItem = NULL; + } + } + if (itemOffline){ + m_contactItem = findContactItem(contact->id(), itemOffline); + grpItem = NULL; + if (m_contactItem){ + grpItem = static_cast(m_contactItem->parent()); + if ((status > STATUS_OFFLINE) || ((int)grpItem->id() != contact->getGroup())){ + grpItem->m_nContacts--; + addGroupForUpdate(grpItem->id()); + deleteItem(m_contactItem); + m_contactItem = NULL; + bChanged = true; + if (m_bShowOnline && (grpItem->child(0) == NULL)){ + deleteItem(grpItem); + grpItem = NULL; + if (itemOffline->child(0) == NULL){ + deleteItem(itemOffline); + itemOffline = NULL; + } + } + } + } + } + if ((unread == 0) && !bShow && (status <= STATUS_OFFLINE) && m_bShowOnline) + break; + DivItem *divItem; + if (status <= STATUS_OFFLINE) + { + if (itemOffline == NULL) + { + bChanged = true; + itemOffline = new DivItem(this, DIV_OFFLINE); + setOpen(itemOffline, true); + } + divItem = itemOffline; + } + else + divItem = itemOnline; + + grpItem = findGroupItem(contact->getGroup(), divItem); + if (grpItem == NULL) + { + Group *grp = getContacts()->group(contact->getGroup()); + if (grp == NULL) + break; + bChanged = true; + grpItem = new GroupItem( divItem, grp, true, m_bCheckable ); + addSortItem(divItem); + } + m_contactItem = findContactItem(contact->id(), grpItem); + if (m_contactItem) + { + if (m_contactItem->update(contact, status, style, icons, unread)) + addSortItem(grpItem); + } + else + { + bChanged = true; + new ContactItem( grpItem, contact, status, style, icons, unread, m_bCheckable ); + grpItem->m_nContacts++; + addGroupForUpdate(grpItem->id()); + } + } + } + updContacts.clear(); + for (list::iterator it_sort = sortItems.begin(); it_sort != sortItems.end(); ++it_sort){ + if ((*it_sort)->child(0) == NULL) + continue; + //(*it_sort)->sort(); + bChanged = true; + } + sortItems.clear(); + //center(x, y, 0, 0); + viewport()->setUpdatesEnabled(true); + if (bChanged){ + viewport()->repaint(); + }else{ + for (list::iterator it = updatedItems.begin(); it != updatedItems.end(); ++it) + (*it)->repaint(); + } + updatedItems.clear(); +} + +const unsigned UPDATE_TIME = 800; + +void UserListBase::addGroupForUpdate(unsigned long id) +{ + for (list::iterator it = updGroups.begin(); it != updGroups.end(); ++it){ + if (*it == id) + return; + } + updGroups.push_back(id); + if (!m_bDirty){ + m_bDirty = true; + updTimer->start(800); + } +} + +void UserListBase::addContactForUpdate(unsigned long id) +{ + for (list::iterator it = updContacts.begin(); it != updContacts.end(); ++it){ + if (*it == id) + return; + } + updContacts.push_back(id); + if (!m_bDirty){ + m_bDirty = true; + updTimer->start(800); + } +} + +void UserListBase::addSortItem(ListViewItem *item) +{ + for (list::iterator it = sortItems.begin(); it != sortItems.end(); ++it){ + if ((*it) == item) + return; + } + sortItems.push_back(item); +} + +void UserListBase::addUpdatedItem(ListViewItem *item) +{ + for (list::iterator it = updatedItems.begin(); it != updatedItems.end(); ++it){ + if ((*it) == item) + return; + } + updatedItems.push_back(item); +} + +unsigned UserListBase::getUnread(unsigned) +{ + return 0; +} + +void UserListBase::fill() +{ + m_pressedItem = NULL; + clear(); + GroupItem *grpItem; + UserViewItemBase *divItem; + UserViewItemBase *divItemOnline = NULL; + UserViewItemBase *divItemOffline = NULL; + ContactList *list = getContacts(); + ContactList::GroupIterator grp_it; + ContactList::ContactIterator contact_it; + Group *grp; + Contact *contact; + switch (m_groupMode){ + case 0: + divItemOnline = NULL; + divItemOffline = NULL; + while ((contact = ++contact_it) != NULL){ + if (contact->getIgnore() || (contact->getFlags() & CONTACT_TEMPORARY)) + continue; + unsigned style; + QString icons; + unsigned status = getUserStatus(contact, style, icons); + unsigned unread = getUnread(contact->id()); + bool bShow = false; + + SIM::PropertyHubPtr data = contact->getUserData("list"); + if (!data.isNull() && data->value("ShowAlways").toBool()) + bShow = true; + if ((unread == 0) && !bShow && (status <= STATUS_OFFLINE) && m_bShowOnline) + continue; + divItem = (status <= STATUS_OFFLINE) ? divItemOffline : divItemOnline; + if (divItem == NULL){ + if (status <= STATUS_OFFLINE){ + divItemOffline = new DivItem(this, DIV_OFFLINE); + setOpen(divItemOffline, true); + divItem = divItemOffline; + }else{ + divItemOnline = new DivItem(this, DIV_ONLINE); + setOpen(divItemOnline, true); + divItem = divItemOnline; + } + } + new ContactItem( divItem, contact, status, style, icons, unread, m_bCheckable ); + } + break; + case 1: + if (m_bShowEmpty){ + while ((grp = ++grp_it) != NULL){ + if (grp->id() == 0) + continue; + grpItem = new GroupItem( this, grp, true, m_bCheckable ); + } + grpItem = new GroupItem( this, list->group(0), true, m_bCheckable ); + } + while ((contact = ++contact_it) != NULL){ + if (contact->getIgnore() || (contact->getFlags() & CONTACT_TEMPORARY)) + continue; + unsigned style; + QString icons; + unsigned status = getUserStatus(contact, style, icons); + unsigned unread = getUnread(contact->id()); + bool bShow = false; + SIM::PropertyHubPtr data = contact->getUserData("list"); + if (!data.isNull() && data->value("ShowAlways").toBool()) + bShow = true; + if ((status <= STATUS_OFFLINE) && !bShow && (unread == 0) && m_bShowOnline) + continue; + grpItem = findGroupItem(contact->getGroup()); + if (grpItem == NULL){ + grp = list->group(contact->getGroup()); + if (grp) + grpItem = new GroupItem( this, grp, true, m_bCheckable ); + if (grpItem == NULL) + continue; + } + m_contactItem = new ContactItem( grpItem, contact, status, style, icons, unread, m_bCheckable ); + grpItem->m_nContacts++; + if ((status > STATUS_OFFLINE) && !m_bShowOnline){ + grpItem->m_nContactsOnline++; + m_contactItem->m_bOnline = true; + } + } + break; + case 2: + divItemOnline = new DivItem(this, DIV_ONLINE); + setOpen(divItemOnline, true); + if (m_bShowEmpty){ + while ((grp = ++grp_it) != NULL){ + if (grp->id() == 0) + continue; + grpItem = new GroupItem( divItemOnline, grp, false, m_bCheckable ); + } + grpItem = new GroupItem( divItemOnline, list->group(0), false, m_bCheckable ); + } + if (!m_bShowOnline){ + divItemOffline = new DivItem(this, DIV_OFFLINE); + setOpen(divItemOffline, true); + grp_it.reset(); + if (m_bShowEmpty){ + while ((grp = ++grp_it) != NULL){ + if (grp->id() == 0) + continue; + grpItem = new GroupItem( divItemOffline, grp, true, m_bCheckable ); + } + grpItem = new GroupItem( divItemOffline, list->group(0), true, m_bCheckable ); + } + } + while ((contact = ++contact_it) != NULL){ + if (contact->getIgnore() || (contact->getFlags() & CONTACT_TEMPORARY)) + continue; + unsigned style; + QString icons; + unsigned status = getUserStatus(contact, style, icons); + unsigned unread = getUnread(contact->id()); + bool bShow = false; + SIM::PropertyHubPtr data = contact->getUserData("list"); + if (!data.isNull() && data->value("ShowAlways").toBool()) + bShow = true; + if ((unread == 0) && !bShow && (status <= STATUS_OFFLINE) && m_bShowOnline) + continue; + if (status <= STATUS_OFFLINE){ + if (divItemOffline == NULL){ + divItemOffline = new DivItem(this, DIV_OFFLINE); + setOpen(divItemOffline, true); + } + divItem = divItemOffline; + }else{ + divItem = divItemOnline; + } + grpItem = findGroupItem(contact->getGroup(), divItem); + if (grpItem == NULL){ + Group *grp = getContacts()->group(contact->getGroup()); + if (grp == NULL) + continue; + grpItem = new GroupItem( divItem, grp, true, m_bCheckable ); + } + new ContactItem( grpItem, contact, status, style, icons, unread, m_bCheckable ); + grpItem->m_nContacts++; + } + break; + } + adjustColumn(); +} + +static void resort(ListViewItem *item) +{ + /* + if (!item->isExpandable()) + return; + item->sort(); + for (item = item->firstChild(); item; item = item->nextSibling()) + resort(item); + */ +} + +bool UserListBase::processEvent(Event *e) +{ + if (e->type() == eEventRepaintView){ + //sort(); + for(int c = 0; c < topLevelItemCount(); c++) + { + ListViewItem *item = static_cast(topLevelItem(c)); + resort(item); + } + viewport()->repaint(); + } + if (m_bInit){ + switch (e->type()){ + case eEventGroup:{ + EventGroup *ev = static_cast(e); + Group *g = ev->group(); + switch (ev->action()) { + case EventGroup::eAdded: + case EventGroup::eChanged: + addGroupForUpdate(g->id()); + break; + case EventGroup::eDeleted: + for (list::iterator it = updGroups.begin(); it != updGroups.end(); ++it){ + if (*it == g->id()){ + updGroups.erase(it); + break; + } + } + GroupItem *grpItem; + switch (m_groupMode){ + case 1: + grpItem = findGroupItem(g->id()); + deleteItem(grpItem); + break; + case 2: + for(int c = 0; c < topLevelItemCount(); c++) + { + ListViewItem *item = static_cast(topLevelItem(c)); + UserViewItemBase *i = static_cast(item); + if (i->type() != DIV_ITEM) continue; + DivItem *divItem = static_cast(i); + grpItem = findGroupItem(g->id(), divItem); + deleteItem(grpItem); + } + break; + } + } + break; + } + case eEventContact: { + EventContact *ec = static_cast(e); + Contact *contact = ec->contact(); + switch(ec->action()) { + case EventContact::eDeleted: { + for (list::iterator it = updContacts.begin(); it != updContacts.end(); ++it){ + if (*it == contact->id()){ + updContacts.erase(it); + break; + } + } + ContactItem *item = findContactItem(contact->id()); + if (item){ + if (m_groupMode){ + GroupItem *grpItem = static_cast(item->parent()); + grpItem->m_nContacts--; + if (item->m_bOnline) + grpItem->m_nContactsOnline--; + addGroupForUpdate(grpItem->id()); + deleteItem(item); + if ((m_groupMode == 2) && + (grpItem->child(0) == NULL) && + m_bShowOnline){ + DivItem *div = static_cast(grpItem->parent()); + if (div->state() == DIV_OFFLINE){ + deleteItem(grpItem); + if (div->child(0) == NULL) + deleteItem(div); + } + } + }else{ + ListViewItem *p = static_cast(item->parent()); + deleteItem(item); + if (p->child(0) == NULL) + deleteItem(p); + } + } + break; + } + case EventContact::eStatus: + case EventContact::eChanged: { + if (!contact->getIgnore() && ((contact->getFlags() & CONTACT_TEMPORARY) == 0)){ + addContactForUpdate(contact->id()); + }else{ + EventContact e(contact, EventContact::eDeleted); + processEvent(&e); + e.setNoProcess(); + } + break; + } + default: + break; + } + break; + } + case eEventMessageReceived:{ + EventMessage *em = static_cast(e); + Message *msg = em->msg(); + if (msg->type() == MessageStatus){ + Contact *contact = getContacts()->contact(msg->contact()); + if (contact) + addContactForUpdate(contact->id()); + } + break; + } + default: + break; + } + } + return ListView::processEvent(e); +} + +GroupItem *UserListBase::findGroupItem(unsigned id, ListViewItem *p) +{ + for(int c = 0; c < (p ? p->childCount() : topLevelItemCount()); c++) + { + ListViewItem *item = static_cast(!p ? topLevelItem(c) : p->child(c)); + UserViewItemBase *i = static_cast(item); + if (i->type() == GRP_ITEM){ + GroupItem *grpItem = static_cast(item); + if (grpItem->id() == id) + return grpItem; + } + //if (item->isExpandable()) + { + GroupItem *res = findGroupItem(id, item); + if (res) + return res; + } + } + return NULL; +} + +ContactItem *UserListBase::findContactItem(unsigned id, ListViewItem *p) +{ + for(int c = 0; c < (p ? p->childCount() : topLevelItemCount()); c++) + { + ListViewItem *item = static_cast(p ? p->child(c) : topLevelItem(c)); + UserViewItemBase *i = static_cast(item); + if (i->type() == USR_ITEM){ + ContactItem *contactItem = static_cast(item); + if (contactItem->id() == id) + return contactItem; + } + //if (item->isExpandable()) + { + ContactItem *res = findContactItem(id, item); + if (res) + return res; + } + } + return NULL; +} + +unsigned UserListBase::getUserStatus(Contact *contact, unsigned &style, QString &icons) +{ + style = 0; + QSet wrkIcons; + QString statusIcon; + unsigned long status = contact->contactInfo(style, statusIcon, &wrkIcons); + if (!statusIcon.isEmpty()) + icons = statusIcon; + QStringList sl = wrkIcons.toList(); + icons += QLatin1Char(',') + sl.join(","); + return status; +} + +void UserListBase::deleteItem(ListViewItem *item) +{ + if (item == NULL) + return; + /* + if (item == currentItem()) + { + + ListViewItem *nextItem = static_cast(item->nextSibling()); + if (nextItem == NULL){ + if (item->parent()){ + nextItem = static_cast(item->parent())->child(0); + }else{ + nextItem = static_cast(topLevelItem(0)); + } + for (; nextItem ; nextItem = nextItem->nextSibling()) + if (nextItem->nextSibling() == item) + break; + } + if ((nextItem == NULL) && item->parent()){ + nextItem = static_cast(item->parent()); + if (nextItem->firstChild() && (nextItem->firstChild() != item)){ + for (nextItem = nextItem->firstChild(); nextItem; nextItem = nextItem->nextSibling()) + if (nextItem->nextSibling() == item) + break; + } + } + if (nextItem) + { + setCurrentItem(nextItem); + //ensureItemVisible(nextItem); + //scrollTo(item); + } + } + */ + delete item; +} + +UserList::UserList(QWidget *parent) + : UserListBase(parent) +{ + m_bCheckable = true; + m_bInit = true; + setMenu(0); + fill(); +} + +UserList::~UserList() +{ +} + +void UserList::select( unsigned int id ) { + ContactItem *pItem = this->findContactItem( id, NULL ); + if( NULL != pItem ) + pItem->setCheckState( 0, Qt::Checked ); +} + +bool UserList::isHaveSelected() { + QList< unsigned int > list = selected(); + return ( list.count() > 0 ); +} + +QList< unsigned int > UserList::selected( QTreeWidgetItem *pItem ) { + QList< unsigned int > list; + + QList< QTreeWidgetItem* > listSubItems; + + if( NULL == pItem ) { + for( int i = 0 ; i < topLevelItemCount() ; i++ ) { + listSubItems.push_back( topLevelItem( i ) ); + } + } + else { + for( int i = 0 ; i < pItem->childCount() ; i++ ) { + listSubItems.push_back( pItem->child( i ) ); + } + } + + foreach( QTreeWidgetItem* pSubItem, listSubItems ) { + UserViewItemBase *pBaseItem = static_cast( pSubItem ); + if( GRP_ITEM == pBaseItem->type() ) { + list.append( selected( pSubItem ) ); + } + else if( ( USR_ITEM == pBaseItem->type() ) && ( Qt::Checked == pSubItem->checkState( 0 ) ) ) { + ContactItem *pContactItem = static_cast( pSubItem ); + list.push_back( pContactItem->id() ); + } + } + + return list; +} + +QList< unsigned int > UserList::selected() { + return selected( NULL ); +} + +// vim: set expandtab: diff --git a/plugins/_core/userlist.h b/plugins/_core/userlist.h new file mode 100644 index 0000000..435b457 --- /dev/null +++ b/plugins/_core/userlist.h @@ -0,0 +1,173 @@ +/*************************************************************************** + userlist.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _USERLIST_H +#define _USERLIST_H + +#include +#include "simgui/listview.h" +#include + +using namespace std; + +class UserListBase; +class QTimer; +class UserViewDelegate; + +const unsigned DIV_ITEM = 0; +const unsigned GRP_ITEM = 1; +const unsigned USR_ITEM = 2; + +const unsigned DIV_ONLINE = 0; +const unsigned DIV_OFFLINE = 1; + +const unsigned CONTACT_TEXT = 1; +const unsigned CONTACT_ICONS = 2; +const unsigned CONTACT_ACTIVE = 3; +const unsigned CONTACT_STATUS = 4; + +namespace SIM { + enum ItemDataRole { + ExtraIconsRole = Qt::UserRole + 0, + }; +} + +class UserViewItemBase : public ListViewItem +{ +public: + UserViewItemBase(UserListBase *view); + UserViewItemBase(UserViewItemBase *parent); + virtual unsigned type() = 0; + virtual void setup(); +protected: + void setCheckable( bool bCheckable ); +}; + +class DivItem : public UserViewItemBase +{ +public: + DivItem(UserListBase *view, unsigned type); + unsigned type() { return DIV_ITEM; } + unsigned state() { return m_type; } +protected: + unsigned m_type; + friend class UserListBase; + friend class UserViewDelegate; + virtual QVariant data( int column, int role ) const; +}; + +class GroupItem : public UserViewItemBase +{ +public: + GroupItem(UserListBase *view, SIM::Group *grp, bool bOffline, bool bCheckable ); + GroupItem(UserViewItemBase *view, SIM::Group *grp, bool bOffline, bool bCheckable ); + unsigned type() { return GRP_ITEM; } + unsigned long id() const { return m_id; } + void update(SIM::Group *grp, bool bInit=false); + unsigned m_nContacts; + unsigned m_nContactsOnline; + unsigned m_unread; + virtual QVariant data( int column, int role ) const; + virtual void setData( int column, int role, const QVariant &value ); +protected: + virtual void setOpen(bool bOpen); + void init(SIM::Group *grp); + unsigned long m_id; + bool m_bOffline; +}; + +class ContactItem : public UserViewItemBase +{ +public: + ContactItem(UserViewItemBase *view, SIM::Contact *contact, unsigned status, unsigned style, const QString &icons, unsigned unread, bool bCheckable ); + unsigned type() { return USR_ITEM; } + unsigned long id() { return m_id; } + unsigned style() { return m_style; } + unsigned status() { return m_status; } + bool update(SIM::Contact *grp, unsigned status, unsigned style, const QString &icons, unsigned unread); + bool m_bOnline; + bool m_bBlink; + unsigned m_unread; + virtual QVariant data( int column, int role ) const; +protected: + virtual QString key(int column/*, bool ascending*/) const; + void init(SIM::Contact *contact, unsigned status, unsigned style, const QString &icons, unsigned unread); + unsigned long m_id; + unsigned m_style; + unsigned m_status; + QIcon m_Icon; + QString m_sExtraIcons; + SIM::Contact *contact; +}; + +class UserListBase : public ListView +{ + Q_OBJECT +public: + UserListBase(QWidget *parent); + ~UserListBase(); + virtual void fill(); +protected slots: + void drawUpdates(); +protected: + unsigned m_groupMode; + unsigned m_bShowOnline; + unsigned m_bShowEmpty; + virtual bool processEvent(SIM::Event*); + unsigned getUserStatus(SIM::Contact *contact, unsigned &style, QString &icons); + virtual unsigned getUnread(unsigned contact_id); + GroupItem *findGroupItem(unsigned id, ListViewItem *p = NULL); + ContactItem *findContactItem(unsigned id, ListViewItem *p = NULL); + void addSortItem(ListViewItem *item); + void addUpdatedItem(ListViewItem *item); + void addGroupForUpdate(unsigned long id); + void addContactForUpdate(unsigned long id); + virtual void deleteItem(ListViewItem *item); + std::list sortItems; + std::list updatedItems; + std::list updGroups; + std::list updContacts; + bool m_bDirty; + bool m_bInit; + QTimer *updTimer; + friend class UserViewItemBase; + bool m_bCheckable; + ContactItem *m_contactItem; +}; + +class UserList + : public UserListBase +{ + Q_OBJECT +public: + UserList( QWidget *parent ); + virtual ~UserList(); + + void select( unsigned int id ); + bool isHaveSelected(); + QList< unsigned int > selected(); + +signals: + void selectChanged(); + +protected: + QList< unsigned int > selected( QTreeWidgetItem *pItem ); +}; + +#endif + +// vim: set expandtab: diff --git a/plugins/_core/userview.cpp b/plugins/_core/userview.cpp new file mode 100644 index 0000000..4dfd464 --- /dev/null +++ b/plugins/_core/userview.cpp @@ -0,0 +1,1419 @@ +/*************************************************************************** + userview.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "icons.h" +#include "log.h" + +#include "userview.h" +#include "core.h" +#include "simgui/intedit.h" +#include "simgui/ballonmsg.h" +#include "simgui/linklabel.h" +#include "container.h" +#include "userviewdelegate.h" +#include "history.h" +#include "contacts/contact.h" +#include "contacts/client.h" +#include "contacts/group.h" +#include "contacts/clientdataiterator.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace SIM; + +const unsigned BLINK_TIMEOUT = 500; +const unsigned BLINK_COUNT = 8; + +struct JoinContacts +{ + unsigned contact1; + unsigned contact2; +}; + +static JoinContacts joinContactsData; + +UserView::UserView() + : UserListBase(NULL) + , m_bBlink (false) + , m_bUnreadBlink(false) + , m_blinkTimer (new QTimer(this)) + , m_unreadTimer (new QTimer(this)) + , m_current (NULL) + , mTipItem (NULL) //Refactor: rename to m_TipItem + , m_dropContactId(0) + , m_dropItem (NULL) + , m_searchItem (NULL) + , m_edtGroup (new IntLineEdit(viewport())) + , m_edtContact (new IntLineEdit(viewport())) + , m_userWnd (NULL) +{ + m_bShowOnline =CorePlugin::instance()->value("ShowOnLine").toBool(); + m_bShowEmpty =CorePlugin::instance()->value("ShowEmptyGroup").toBool(); + m_bShowOnline =CorePlugin::instance()->value("ShowOnLine").toBool(); + m_bShowEmpty =CorePlugin::instance()->value("ShowEmptyGroup").toBool(); + + + setItemDelegate(new UserViewDelegate(this)); + setRootIsDecorated(false); + setHeaderHidden(true); + setAnimated(true); + setIndentation(0); + setVerticalScrollBarPolicy(CorePlugin::instance()->value("NoScroller").toBool() ? Qt::ScrollBarAlwaysOff : Qt::ScrollBarAsNeeded); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + connect(m_blinkTimer, SIGNAL(timeout()), this, SLOT(blink())); + connect(m_unreadTimer, SIGNAL(timeout()), this, SLOT(unreadBlink())); + + topLevelWidget()->installEventFilter(this); + viewport()->installEventFilter(this); + + setFrameStyle(QFrame::StyledPanel); + setFrameShadow(QFrame::Sunken); + EventAddWidget(this, true, EventAddWidget::eMainWindow).process(); + clear(); + + setGroupMode(CorePlugin::instance()->value("GroupMode").toUInt(), true); + + m_edtGroup->hide(); + m_edtContact->hide(); + QFont font; + int size = font.pixelSize(); + if (size <= 0) + { + size = font.pointSize(); + font.setPointSize(size * 3 / 4); + } + else font.setPixelSize(size * 3 / 4); + font.setBold(true); + m_edtGroup->setFont(font); + connect(m_edtGroup, SIGNAL(escape()), this, SLOT(editEscape())); + connect(m_edtGroup, SIGNAL(returnPressed()), this, SLOT(editGroupEnter())); + connect(m_edtGroup, SIGNAL(lostFocus()), this, SLOT(editGroupEnter())); + connect(m_edtContact, SIGNAL(escape()), this, SLOT(editEscape())); + connect(m_edtContact, SIGNAL(returnPressed()), this, SLOT(editContactEnter())); + connect(m_edtContact, SIGNAL(lostFocus()), this, SLOT(editContactEnter())); + + setDragDropMode( QAbstractItemView::DragDrop ); + setDropIndicatorShown( true ); +} + +UserView::~UserView() +{ +} + +bool UserView::processEvent(Event *e) +{ + switch (e->type()) + { + case eEventRepaintView: + setVerticalScrollBarPolicy(CorePlugin::instance()->value("NoScroller").toBool() ? Qt::ScrollBarAlwaysOff : Qt::ScrollBarAsNeeded); + break; + case eEventInit: + m_bInit = true; + fill(); + break; + case eEventContact: + { + EventContact *ec = static_cast(e); + if(ec->action() != EventContact::eOnline) + break; + Contact *contact = ec->contact(); + if (m_bInit){ + bool bStart = blinks.empty(); + list::iterator it; + for (it = blinks.begin(); it != blinks.end(); ++it){ + if (it->id == contact->id()) + break; + } + if (it != blinks.end()){ + it->count = BLINK_COUNT; + return false; + } + BlinkCount bc; + bc.id = contact->id(); + bc.count = BLINK_COUNT; + blinks.push_back(bc); + if (bStart) + m_blinkTimer->start(BLINK_TIMEOUT); + return false; + } + break; + } + case eEventMessageReceived: + case eEventMessageDeleted: + case eEventMessageRead: + { + EventMessage *em = static_cast(e); + Message *msg = em->msg(); + addContactForUpdate(msg->contact()); + break; + } + case eEventCommandExec: + { + EventCommandExec *ece = static_cast(e); + CommandDef *cmd = ece->cmd(); + if (cmd->menu_id == MenuContact){ + Contact *contact = getContacts()->contact((unsigned long)(cmd->param)); + if (contact){ + if (cmd->id == CmdContactDelete){ + ListViewItem *item = findContactItem(contact->id()); + if (item){ + //scrollTo(model()->index(item->row(), item->column())); + QRect rc = visualItemRect(item); + QPoint p = viewport()->mapToGlobal(rc.topLeft()); + rc = QRect(p.x(), p.y(), rc.width(), rc.height()); + m_bRemoveHistory = CorePlugin::instance()->value("RemoveHistory").toBool(); + BalloonMsg::ask((void*)contact->id(), + i18n("Delete \"%1\"?") .arg(contact->getName()), + this, SLOT(deleteContact(void*)), NULL, &rc, NULL, + i18n("Remove history"), &m_bRemoveHistory); + } + return true; + } + if (cmd->id == CmdContactRename){ + ListViewItem *item = findContactItem(contact->id()); + if (item){ + setCurrentItem(item); + renameContact(); + } + return true; + } + if (cmd->id == CmdShowAlways){ + SIM::PropertyHubPtr data = contact->getUserData("list", true); + if (!data.isNull()){ + bool bShow = false; + if (cmd->flags & COMMAND_CHECKED) + bShow = true; + if (data->value("ShowAlways").toBool() != bShow){ + data->setValue("ShowAlways", bShow); + EventContact(contact, EventContact::eChanged).process(); + } + } + return true; + } + if (cmd->id == CmdClose){ + UserWnd *wnd = NULL; + QWidgetList list = QApplication::topLevelWidgets(); + QWidget * w; + foreach(w,list) + { + if (w->inherits("Container")){ + Container *c = static_cast(w); + wnd = c->wnd((unsigned long)(cmd->param)); + if (wnd) + break; + } + } + if (wnd){ + delete wnd; + return true; + } + } + if (cmd->id > CmdSendMessage){ + Command c; + c->id = cmd->id - CmdSendMessage; + c->menu_id = MenuMessage; + c->param = (void*)(contact->id()); + c->flags = cmd->flags; + EventCommandExec eCmd(c); + if (eCmd.process()) + return true; + } + } + } + if (cmd->menu_id == MenuContactGroup){ + Contact *contact = getContacts()->contact((unsigned long)(cmd->param)); + if (contact){ + Group *grp = getContacts()->group(cmd->id - CmdContactGroup); + if (grp && ((int)grp->id() != contact->getGroup())){ + contact->setGroup(grp->id()); + EventContact(contact, EventContact::eChanged).process(); + return true; + } + } + } + if (cmd->menu_id == MenuContainer) + { + Contact *contact = getContacts()->contact((unsigned long)(cmd->param)); + if (contact){ + Container *from = NULL; + Container *to = NULL; + QWidgetList list = QApplication::topLevelWidgets(); + QWidget * w; + unsigned max_id = 0; + foreach(w,list) + { + if (w->inherits("Container")){ + Container *c = static_cast(w); + if (c->getId() == cmd->id) + to = c; + if (c->wnd(contact->id())) + from = c; + if (!(c->getId() & CONTAINER_GRP)){ + if (max_id < c->getId()) + max_id = c->getId(); + } + } + } + if (from && to && (from == to)) + return true; + if (from) + { + m_userWnd = from->wnd(contact->id()); + from->removeUserWnd(m_userWnd); + delete m_userWnd; + } + if (from->wnd(contact->id()) == NULL) + m_userWnd = new UserWnd(contact->id(), NULL, true, true); + if (to == NULL) + to = new Container(max_id + 1); + to->init(); + to->addUserWnd(m_userWnd, true); + to->setNoSwitch(true); + raiseWindow(to); + to->setNoSwitch(false); + delete m_userWnd; + } + return true; + } + if (cmd->id == CmdOnline){ + CorePlugin::instance()->setValue("ShowOnLine", ((cmd->flags & COMMAND_CHECKED) != 0)); + m_bShowOnline = (cmd->flags & COMMAND_CHECKED); + if (cmd->menu_id){ + CommandDef c = *cmd; + c.bar_id = ToolBarMain; + c.bar_grp = 0x4000; + EventCommandChange(&c).process(); + } + fill(); + } + if (cmd->id == CmdEmptyGroup){ + CorePlugin::instance()->setValue("ShowEmptyGroup", ((cmd->flags & COMMAND_CHECKED) != 0)); + m_bShowEmpty = (cmd->flags & COMMAND_CHECKED); + fill(); + } + if (cmd->id == CmdGrpOff) + setGroupMode(0); + if (cmd->id == CmdGrpMode1) + setGroupMode(1); + if (cmd->id == CmdGrpMode2) + setGroupMode(2); + if (cmd->id == CmdGrpCreate){ + if (CorePlugin::instance()->value("GroupMode").toUInt()){ + /* Show empty groups because a new group is empty... */ + CorePlugin::instance()->setValue("ShowEmptyGroup", true); + m_bShowEmpty = true; + fill(); + Group *g = getContacts()->group(0, true); + drawUpdates(); + ListViewItem *item = findGroupItem(g->id()); + if (item){ + setCurrentItem(item); + QTimer::singleShot(0, this, SLOT(renameGroup())); + } + } + return true; + } + if (cmd->id == CmdGrpRename){ + ListViewItem *item = findGroupItem((unsigned long)(cmd->param)); + if (item){ + setCurrentItem(item); + renameGroup(); + } + return true; + } + if (cmd->id == CmdGrpUp){ + unsigned long grp_id = (unsigned long)(cmd->param); + getContacts()->moveGroup(grp_id, true); + ListViewItem *item = findGroupItem(grp_id); + if (item){ + //scrollTo(model()->index(item->row(), item->column())); + setCurrentItem(item); + } + return true; + } + if (cmd->id == CmdGrpDown){ + unsigned long grp_id = (unsigned long)(cmd->param); + getContacts()->moveGroup(grp_id, false); + ListViewItem *item = findGroupItem(grp_id); + if (item){ + //scrollTo(model()->index(item->row(), item->column())); + setCurrentItem(item); + } + return true; + } + if (cmd->id == CmdGrpDelete){ + unsigned long grp_id = (unsigned long)(cmd->param); + ListViewItem *item = findGroupItem(grp_id); + Group *g = getContacts()->group(grp_id); + if (item && g){ + //scrollTo(model()->index(item->row(), item->column())); + QRect rc = visualItemRect(item); + QPoint p = viewport()->mapToGlobal(rc.topLeft()); + rc = QRect(p.x(), p.y(), rc.width(), rc.height()); + BalloonMsg::ask((void*)grp_id, + i18n("Delete \"%1\"?") .arg(g->getName()), + this, SLOT(deleteGroup(void*)), NULL, &rc); + } + } + break; + } + case eEventCheckCommandState:{ + EventCheckCommandState *ecs = static_cast(e); + CommandDef *cmd = ecs->cmd(); + if (cmd->menu_id == MenuGroups){ + cmd->flags = cmd->flags & (~COMMAND_CHECKED); + if (((cmd->id == CmdGrpOff) && (CorePlugin::instance()->value("GroupMode").toUInt() == 0)) || + ((cmd->id == CmdGrpMode1) && (CorePlugin::instance()->value("GroupMode").toUInt() == 1)) || + ((cmd->id == CmdGrpMode2) && (CorePlugin::instance()->value("GroupMode").toUInt() == 2)) || + ((cmd->id == CmdOnline) && CorePlugin::instance()->value("ShowOnLine").toBool())) + cmd->flags |= COMMAND_CHECKED; + if (cmd->id == CmdEmptyGroup){ + if (CorePlugin::instance()->value("GroupMode").toUInt() == 0) + return false; + if (CorePlugin::instance()->value("ShowEmptyGroup").toBool()) + cmd->flags |= COMMAND_CHECKED; + } + return true; + } + if (cmd->menu_id == MenuContact){ + if (cmd->id == CmdContactTitle){ + Contact *contact = getContacts()->contact((unsigned long)(cmd->param)); + if (contact){ + cmd->text_wrk = contact->getName(); + return true; + } + } + if (cmd->id == CmdShowAlways){ + Contact *contact = getContacts()->contact((unsigned long)(cmd->param)); + if (contact){ + SIM::PropertyHubPtr data = contact->getUserData("list", true); + cmd->flags &= ~COMMAND_CHECKED; + if (!data.isNull() && data->value("ShowAlways").toBool()) + cmd->flags |= COMMAND_CHECKED; + return true; + } + } + if (cmd->id == CmdClose){ + UserWnd *wnd = NULL; + QWidgetList list = QApplication::topLevelWidgets(); + QWidget * w; + foreach(w,list) + { + if (w->inherits("Container")){ + wnd = static_cast(w)->wnd((unsigned long)(cmd->param)); + if (wnd) + break; + } + } + if (wnd) + return true; + } + if (cmd->id == CmdSendMessage){ + EventMenuGetDef eMenu(MenuMessage); + eMenu.process(); + CommandsDef *cmdsMsg = eMenu.defs(); + unsigned nCmds = 1; + { + CommandsList it(*cmdsMsg, true); + while (++it) + nCmds++; + } + + CommandDef *cmds = new CommandDef[nCmds]; + nCmds = 0; + + CommandsList it(*cmdsMsg, true); + CommandDef *c; + while ((c = ++it) != NULL){ + cmds[nCmds] = *c; + cmds[nCmds].id = CmdSendMessage + c->id; + cmds[nCmds].menu_id = MenuContact; + nCmds++; + } + cmd->param = cmds; + cmd->flags |= COMMAND_RECURSIVE; + return true; + } + if (cmd->id > CmdSendMessage){ + Command c; + c->id = cmd->id - CmdSendMessage; + c->menu_id = MenuMessage; + c->param = cmd->param; + bool res = EventCheckCommandState(c).process(); + if (res && (c->flags & COMMAND_RECURSIVE)){ + cmd->flags |= COMMAND_RECURSIVE; + cmd->param = c->param; + } + if (res) { + cmd->flags = c->flags; + } + return res; + } + } + if (cmd->menu_id == MenuContactGroup){ + if (cmd->id == CmdContactGroup){ + unsigned grpId = 0; + Contact *contact = getContacts()->contact((unsigned long)(cmd->param)); + if (contact) + grpId = contact->getGroup(); + unsigned nGroups = 0; + Group *grp; + ContactList::GroupIterator it; + while ((grp = ++it) != NULL) + nGroups++; + CommandDef *cmds = new CommandDef[nGroups + 1]; + it.reset(); + nGroups = 0; + while ((grp = ++it) != NULL){ + if (grp->id() == 0) continue; + CommandDef &c = cmds[nGroups++]; + c = *cmd; + c.id = CmdContactGroup + grp->id(); + c.flags = COMMAND_DEFAULT; + if ((grp->id() == grpId) && contact->id()) + c.flags |= COMMAND_CHECKED; + c.text_wrk = grp->getName(); + } + CommandDef &c = cmds[nGroups++]; + c = *cmd; + c.text = I18N_NOOP("Not in list"); + c.id = CmdContactGroup; + c.flags = COMMAND_DEFAULT; + if (grpId == 0) + c.flags = COMMAND_CHECKED; + cmds[nGroups].clear(); + cmd->flags |= COMMAND_RECURSIVE; + cmd->param = cmds; + return true; + } + } + if (cmd->menu_id == MenuGroup){ + unsigned long grp_id = (unsigned long)(cmd->param); + if (grp_id){ + if (cmd->id == CmdGrpTitle){ + Group *g = getContacts()->group(grp_id); + if (g) + cmd->text_wrk = g->getName(); + return true; + } + if ((cmd->id == CmdGrpDelete) || (cmd->id == CmdGrpRename)){ + cmd->flags &= ~COMMAND_CHECKED; + return true; + } + if (cmd->id == CmdGrpUp){ + if (getContacts()->groupIndex(grp_id) <= 1) + cmd->flags |= COMMAND_DISABLED; + cmd->flags &= ~COMMAND_CHECKED; + return true; + } + if (cmd->id == CmdGrpDown){ + if (getContacts()->groupIndex(grp_id) >= getContacts()->groupCount() - 1) + cmd->flags |= COMMAND_DISABLED; + cmd->flags &= ~COMMAND_CHECKED; + return true; + } + }else{ + if (cmd->id == CmdGrpTitle){ + cmd->text = I18N_NOOP("Not in list"); + return true; + } + } + } + if (cmd->id == CmdGrpCreate) { + cmd->flags &= ~COMMAND_CHECKED; + return CorePlugin::instance()->value("GroupMode").toUInt() ? true : false; + } + break; + } + case eEventIconChanged: + viewport()->repaint(); + break; + case eEventRaiseWindow:{ + EventRaiseWindow *w = static_cast(e); + QWidget *o = w->widget(); + if (o && o->inherits("MainWindow")) + QTimer::singleShot(0, this, SLOT(adjustColumn())); + break; + } + default: + break; + } + return UserListBase::processEvent(e); +} + +void UserView::deleteGroup(void *p) +{ + Group *grp = getContacts()->group((unsigned long)p); + if (grp) + delete grp; +} + +void UserView::deleteContact(void *p) +{ + Contact *contact = getContacts()->contact((unsigned long)p); + if (contact == NULL) + return; + ContactItem *item = findContactItem(contact->id()); + if (item) + setCurrentItem(item); + + // Looking for unread messages for this contact in order to delete them + int no_more_messages_flag; + do{ + no_more_messages_flag = 1; + // we should restart unread messages iteration after each message deletion + // because deleting message will change "unread" list + for (list::iterator it = CorePlugin::instance()->unread.begin(); it != CorePlugin::instance()->unread.end(); ++it){ + msg_id &message_id = *it; + if ( message_id.contact == contact->id()) + { + SIM::Message * message; + message = History::load(message_id.id,message_id.client,message_id.contact); + EventMessageDeleted(message).process(); + // may be we should do EventMessageRead instead of EventMessageDeleted when m_bRemoveHistory is flase + // I am not sure. shaplov. + no_more_messages_flag = 0; + break; + } + } + } while (!no_more_messages_flag); + + CorePlugin::instance()->setValue("RemoveHistory", m_bRemoveHistory); + if (!m_bRemoveHistory) + contact->setFlags(contact->getFlags() | CONTACT_NOREMOVE_HISTORY); + delete contact; +} + +void UserView::renameGroup() +{ + ListViewItem *item = currentItem(); + if (item == NULL) + return; + UserViewItemBase *i = static_cast(item); + if (i->type() != GRP_ITEM) + return; + GroupItem *grpItem = static_cast(item); + Group *g = getContacts()->group(grpItem->id()); + if (g){ + //scrollTo(model()->index(item->row(), item->column())); + QString name = g->getName(); + QRect rc = visualItemRect(item); + rc.setLeft(rc.left() + 18); + m_edtGroup->id = g->id(); + m_edtGroup->setGeometry(rc); + m_edtGroup->setText(name.length() ? name : i18n("New group")); + m_edtGroup->setSelection(0, m_edtGroup->text().length()); + m_edtGroup->show(); + m_edtGroup->setFocus(); + } +} + +void UserView::renameContact() +{ + ListViewItem *item = currentItem(); + if (item == NULL) + return; + UserViewItemBase *i = static_cast(item); + if (i->type() != USR_ITEM) + return; + ContactItem *contactItem = static_cast(item); + Contact *contact = getContacts()->contact(contactItem->id()); + if (contact){ + //scrollTo(model()->index(item->row(), item->column())); + QString name = contact->getName(); + QRect rc = visualItemRect(item); + rc.setLeft(rc.left() + 18); + m_edtContact->id = contact->id(); + m_edtContact->setGeometry(rc); + m_edtContact->setText(name); + m_edtContact->setSelection(0, m_edtContact->text().length()); + m_edtContact->show(); + m_edtContact->setFocus(); + } +} + +void UserView::setGroupMode(unsigned mode, bool bFirst) +{ + if (!bFirst && (CorePlugin::instance()->value("GroupMode").toUInt() == mode)) + return; + CorePlugin::instance()->setValue("GroupMode", mode); + m_groupMode = mode; + EventUpdateCommandState(CmdGroupToolbarButton).process(); + fill(); +} + +bool UserView::eventFilter(QObject *obj, QEvent *e) +{ + bool res = ListView::eventFilter(obj, e); + if (obj->inherits("QMainWindow")) + { + if (e->type() == QEvent::Show) + QTimer::singleShot(0, this, SLOT(repaintView())); + } + return res; +} + +void UserView::mousePressEvent(QMouseEvent *e) +{ + stopSearch(); + UserListBase::mousePressEvent(e); +} + +void UserView::focusOutEvent(QFocusEvent *e) +{ + stopSearch(); + UserListBase::focusOutEvent(e); +} + +void UserView::mouseReleaseEvent(QMouseEvent *e) +{ + ListViewItem *item = m_pressedItem; + UserListBase::mouseReleaseEvent(e); + if (item){ + if (!CorePlugin::instance()->value("UseDblClick").toBool()){ + m_current = item; + QTimer::singleShot(0, this, SLOT(doClick())); + } + } +} + +void UserView::mouseDoubleClickEvent(QMouseEvent *e) +{ + UserListBase::mouseDoubleClickEvent(e); + m_current = itemAt(e->pos()); + QTimer::singleShot(0, this, SLOT(doClick())); +} + +void UserView::doClick() +{ + if (m_current == NULL) + return; + if (m_current->isExpandable() && !CorePlugin::instance()->value("UseDblClick").toBool()) + { + m_current->setOpen(!m_current->isOpen()); + } + else if (static_cast(m_current)->type() == USR_ITEM) + { + ContactItem *item = static_cast(m_current); + EventDefaultAction(item->id()).process(); + } + m_current = NULL; +} + +void UserView::keyPressEvent(QKeyEvent *e) +{ + if (CorePlugin::instance()->value("UseDblClick").toBool() || m_searchItem){ + if (m_searchItem) { + int store = 0; + list items; + list::iterator it; + search(items); + if (!items.empty()) { + for (it = items.begin(); it != items.end(); ++it) + if (*it == m_searchItem) { + store = 1; + } + if (!store) m_searchItem = items.front(); + } else { + m_search = QString::null; + m_searchItem = NULL; + } + setCurrentItem(m_searchItem); + } + switch (e->key()){ + case Qt::Key_Return: + case Qt::Key_Enter: + m_current = currentItem(); + QTimer::singleShot(0, this, SLOT(doClick())); + return; + } + } + bool bTip = false; + if (m_searchItem && (m_searchItem == mTipItem)) + bTip = true; + list old_items; + list new_items; + switch (e->key()){ + case Qt::Key_Backspace: + if (m_search.isEmpty()){ + UserListBase::keyPressEvent(e); + return; + } + search(old_items); + m_search = m_search.left(m_search.length() - 1); + if (m_search.isEmpty()){ + m_searchItem = NULL; + list::iterator it; + for (it = closed_items.begin(); it != closed_items.end(); ++it) + (*it)->setOpen(false); + }else{ + search(new_items); + if (new_items.empty()){ + m_search = QString::null; + m_searchItem = NULL; + }else{ + m_searchItem = new_items.front(); + } + } + break; + case Qt::Key_Escape: + if (m_search.isEmpty()){ + UserListBase::keyPressEvent(e); + return; + } + stopSearch(); + return; + case Qt::Key_Up: + if (m_search.isEmpty()){ + UserListBase::keyPressEvent(e); + return; + } + if (m_searchItem){ + search(old_items); + list::iterator it_old; + for (it_old = old_items.begin(); it_old != old_items.end(); ++it_old) + if ((*it_old) == m_searchItem) + break; + if (it_old != old_items.begin()) + it_old--; + if (it_old == old_items.begin()){ + QApplication::beep(); + return; + } + m_searchItem = *it_old; + } + break; + case Qt::Key_Down: + if (m_search.isEmpty()){ + UserListBase::keyPressEvent(e); + return; + } + if (m_searchItem){ + search(old_items); + list::iterator it_old; + for (it_old = old_items.begin(); it_old != old_items.end(); ++it_old) + if ((*it_old) == m_searchItem) + break; + if (it_old != old_items.end()) + it_old++; + if (it_old == old_items.end()){ + QApplication::beep(); + return; + } + m_searchItem = *it_old; + } + break; + case Qt::Key_Plus: + case Qt::Key_Minus: + if (m_search.isEmpty()){ + ListViewItem *item = currentItem(); + if (item && item->isExpandable()){ + UserListBase::keyPressEvent(e); + return; + } + } + case Qt::Key_Delete: + // e->text() is not empty, but we don't need to specially handle Del + UserListBase::keyPressEvent(e); + return; + default: + QString t = e->text(); + if (t.isEmpty()){ + UserListBase::keyPressEvent(e); + return; + } + if (m_search.isEmpty()) { + closed_items.clear(); + for(int c = 0; c < topLevelItemCount(); c++) + { + ListViewItem *item = static_cast(topLevelItem(c)); + if (item->isExpandable() && !(item->isOpen())) + closed_items.push_back(item); + } + } + QString save_search = m_search; + search(old_items); + m_search += t; + search(new_items); + if (new_items.empty()){ + m_search = save_search; + search(new_items); + QApplication::beep(); + return; + }else{ + m_searchItem = new_items.front(); + } + } + list::iterator it_old; + list::iterator it_new; + for (it_old = old_items.begin(); it_old != old_items.end(); ++it_old){ + for (it_new = new_items.begin(); it_new != new_items.end(); ++it_new) + if (*it_new == *it_old) + break; + if (it_new == new_items.end()) + new_items.push_back(*it_old); + } + for (it_new = new_items.begin(); it_new != new_items.end(); ++it_new) + (*it_new)->repaint(); + setCurrentItem(m_searchItem); + if (m_searchItem){ + //scrollTo(model()->index(m_searchItem->row(), m_searchItem->column())); + } + if (m_search.isEmpty() || (m_searchItem == NULL)){ + QToolTip::hideText(); + }else{ + QString tip = i18n("Search: %1") .arg(m_search); + QRect tipRect = visualItemRect(m_searchItem); + QPoint p = viewport()->mapToGlobal(tipRect.topLeft()); + QToolTip::showText( mapToGlobal( tipRect.topLeft() ), tip, this, tipRect ); + } +} + +void UserView::stopSearch() +{ + if (m_search.isEmpty()) + return; + list old_items; + search(old_items); + m_search = QString::null; + m_searchItem = NULL; + list::iterator it_old; + for (it_old = old_items.begin(); it_old != old_items.end(); ++it_old) + (*it_old)->repaint(); + QToolTip::hideText(); +} + +bool UserView::getMenu(ListViewItem *list_item, unsigned long &id, void* ¶m) +{ + if (list_item == NULL) + return false; + + UserViewItemBase *item = static_cast(list_item); + switch (item->type()){ + case GRP_ITEM:{ + GroupItem *grpItem = static_cast(item); + id = MenuGroup; + param = (void*)(grpItem->id()); + return true; + } + case USR_ITEM:{ + ContactItem *contactItem = static_cast(item); + id = MenuContact; + param = (void*)(contactItem->id()); + return true; + } + } + return false; +} + +void UserView::editEscape() +{ + m_edtGroup->hide(); + m_edtContact->hide(); +} + +void UserView::editGroupEnter() +{ + m_edtGroup->hide(); + Group *g = getContacts()->group(m_edtGroup->id); + if (!(g && m_edtGroup->text().length())) return; + g->setName(m_edtGroup->text()); + EventGroup e(g, EventGroup::eChanged); + e.process(); +} + +void UserView::editContactEnter() +{ + m_edtContact->hide(); + Contact *c = getContacts()->contact(m_edtContact->id); + if (!(c && m_edtContact->text().length())) return; + c->setName(m_edtContact->text()); + EventContact(c, EventContact::eChanged).process(); +} + +unsigned UserView::getUnread(unsigned contact_id) +{ + for (list::iterator it = CorePlugin::instance()->unread.begin(); it != CorePlugin::instance()->unread.end(); ++it){ + if (it->contact == contact_id){ + if (!m_unreadTimer->isActive()){ + m_bUnreadBlink = true; + m_unreadTimer->start(BLINK_TIMEOUT); + } + return it->type; + } + } + return 0; +} + +static void resetUnread(ListViewItem *item, list &grp) +{ + if (static_cast(item)->type() == GRP_ITEM){ + list::iterator it; + for (it = grp.begin(); it != grp.end(); ++it) + if ((*it) == item) + break; + if (it == grp.end()){ + GroupItem *group = static_cast(item); + if (group->m_unread){ + group->m_unread = 0; + if (!group->isOpen()) + group->repaint(); + } + } + } + if (!item->isExpandable()) + return; + for(int c = 0; c < item->childCount(); c++) + { + ListViewItem *i= static_cast(item->child(c)); + resetUnread(i, grp); + } +} + +void UserView::unreadBlink() +{ + m_bUnreadBlink = !m_bUnreadBlink; + list blinks; + list::iterator itb; + for (list::iterator it = CorePlugin::instance()->unread.begin(); it != CorePlugin::instance()->unread.end(); ++it){ + for (itb = blinks.begin(); itb != blinks.end(); ++itb) + if ((*itb) == it->contact) + break; + if (itb != blinks.end()) + continue; + blinks.push_back(it->contact); + } + list grps; + if (blinks.empty()) + m_unreadTimer->stop(); + else + { + for (itb = blinks.begin(); itb != blinks.end(); ++itb){ + ContactItem *contact = findContactItem((*itb), NULL); + if (contact == NULL) + return; + update(); + //repaintItem(contact); + if (CorePlugin::instance()->value("GroupMode").toUInt() && !contact->parent()->isExpanded()){ + GroupItem *group = static_cast(contact->parent()); + group->m_unread = contact->m_unread; + update(); + grps.push_back(group); + } + } + } + if (CorePlugin::instance()->value("GroupMode").toUInt()){ + for(int c = 0; c < topLevelItemCount(); c++) + { + ListViewItem *i = static_cast(topLevelItem(c)); + resetUnread(i, grps); + } + } +} + +void UserView::blink() +{ + m_bBlink = !m_bBlink; + list::iterator it; + for (it = blinks.begin(); it != blinks.end();){ + ContactItem *contact = findContactItem(it->id, NULL); + if (contact == NULL){ + blinks.erase(it); + it = blinks.begin(); + break; + } + contact->m_bBlink = m_bBlink; + update(); + //repaintItem(contact); + ++it; + } + if (m_bBlink) + return; + for (it = blinks.begin(); it != blinks.end(); ++it) + it->count--; + for (it = blinks.begin(); it != blinks.end(); ){ + if (it->count){ + ++it; + continue; + } + blinks.erase(it); + it = blinks.begin(); + } + if (blinks.size() == 0) + m_blinkTimer->stop(); +} + +void UserView::deleteItem(ListViewItem *item) +{ + if (item == NULL) + return; + if (item == m_pressedItem) + m_pressedItem = NULL; + if (item == m_searchItem) + stopSearch(); + UserListBase::deleteItem(item); +} + +class UserViewContactDragObject : public ContactDragObject +{ +public: + UserViewContactDragObject( const UserView *view, Contact *contact ); + virtual ~UserViewContactDragObject(); +}; + +UserViewContactDragObject::UserViewContactDragObject( const UserView *view, Contact *contact ) + : ContactDragObject( contact ) +{ + QTimer *dragTimer = new QTimer(this); + connect(dragTimer, SIGNAL(timeout()), view, SLOT(dragScroll())); + dragTimer->start(200); +} + +UserViewContactDragObject::~UserViewContactDragObject() +{ +} + +QMimeData *UserView::mimeData( const QList items ) const +{ + if( items.count() != 1 ) + return NULL; + + QTreeWidgetItem *pItem = items.first(); + + UserViewItemBase *base_item = static_cast(pItem); + if (base_item->type() != USR_ITEM) + return NULL; + ContactItem *item = static_cast(base_item); + Contact *contact = getContacts()->contact(item->id()); + if (contact == NULL) + return NULL; + return new UserViewContactDragObject(this, contact); +} + +QMimeData *UserView::dragObject() +{ + if (currentItem() == NULL) + return NULL; + UserViewItemBase *base_item = static_cast(currentItem()); + if (base_item->type() != USR_ITEM) + return NULL; + ContactItem *item = static_cast(currentItem()); + Contact *contact = getContacts()->contact(item->id()); + if (contact == NULL) + return NULL; + return new UserViewContactDragObject(this, contact); +} + +void UserView::dragEnterEvent(QDragEnterEvent *e) +{ + dragEvent(e, false); +} + +void UserView::dragMoveEvent(QDragMoveEvent *e) +{ + dragEvent(e, false); +} + +void UserView::dropEvent(QDropEvent *e) +{ + dragEvent(e, true); +} + +void UserView::dragEvent(QDropEvent *e, bool isDrop) +{ + ListViewItem *list_item = itemAt(e->pos()); + if (list_item == NULL){ + e->ignore(); + return; + } + UserViewItemBase *item = static_cast(list_item); + switch (item->type()){ + case GRP_ITEM: + if (ContactDragObject::canDecode(e)){ + if (isDrop){ + Contact *contact = ContactDragObject::decode(e); + m_dropItem = item; + m_dropContactId = contact->id(); + contact->setFlags(contact->getFlags() & ~CONTACT_DRAG); + QTimer::singleShot(0, this, SLOT(doDrop())); + } + e->setDropAction( Qt::MoveAction ); + e->accept(); + return; + } + break; + case USR_ITEM:{ + if (ContactDragObject::canDecode(e)){ + Contact *contact = ContactDragObject::decode(e); + if (static_cast(item)->id() == contact->id()){ + e->setDropAction( Qt::IgnoreAction ); + e->accept(); + return; + } + if (isDrop){ + m_dropItem = item; + m_dropContactId = contact->id(); + contact->setFlags(contact->getFlags() & ~CONTACT_DRAG); + QTimer::singleShot(0, this, SLOT(doDrop())); + e->ignore(); + return; + } + e->setDropAction( Qt::MoveAction ); + e->accept(); + } + Message *msg = NULL; + CommandDef *cmd; + CommandsMapIterator it(CorePlugin::instance()->messageTypes); + while ((cmd = ++it) != NULL){ + MessageDef *def = (MessageDef*)(cmd->param); + if (def && def->drag){ + msg = def->drag(e); + if (msg){ + unsigned type = cmd->id; + Command cmd; + cmd->id = type; + cmd->menu_id = MenuMessage; + cmd->param = (void*)(static_cast(item)->id()); + if (EventCheckCommandState(cmd).process()) + break; + } + } + } + if (msg){ + if (isDrop){ + msg->setContact(static_cast(item)->id()); + EventOpenMessage(msg).process(); + } + delete msg; + return; + } + if (!e->mimeData()->text().isEmpty()) { + QString str = e->mimeData()->text(); + e->accept(); + if (isDrop) { + Message *msg = new Message(MessageGeneric); + msg->setText(str); + msg->setContact(static_cast(item)->id()); + EventOpenMessage(msg).process(); + delete msg; + } + return; + } + break; + } + } + e->accept(); +} + +void UserView::doDrop() +{ + if (m_dropItem == NULL) + return; + Contact *contact = getContacts()->contact(m_dropContactId); + if (contact == NULL) + return; + switch (static_cast(m_dropItem)->type()){ + case GRP_ITEM:{ + GroupItem *grp_item = static_cast(m_dropItem); + contact->setGroup(grp_item->id()); + contact->setIgnore(false); + contact->setFlags(contact->getFlags() & ~CONTACT_TEMPORARY); + EventContact(contact, EventContact::eChanged).process(); + break; + } + case USR_ITEM:{ + ContactItem *contact_item = static_cast(m_dropItem); + Contact *contact1 = getContacts()->contact(contact_item->id()); + if (contact1 == NULL) + break; + joinContactsData.contact1 = contact_item->id(); + joinContactsData.contact2 = m_dropContactId; + //scrollTo(model()->index(contact_item->row(), contact_item->column())); + QRect rc = visualItemRect(contact_item); + QPoint p = viewport()->mapToGlobal(rc.topLeft()); + rc = QRect(p.x(), p.y(), rc.width(), rc.height()); + BalloonMsg::ask(NULL, + i18n("Join \"%1\" and \"%2\"?") + .arg(contact1->getName()) + .arg(contact->getName()), + this, + SLOT(joinContacts(void*)), + SLOT(cancelJoinContacts(void*)), &rc); + break; + } + } + m_dropContactId = 0; + m_dropItem = NULL; +} + +void UserView::joinContacts(void*) +{ + Contact *contact1 = getContacts()->contact(joinContactsData.contact1); + Contact *contact2 = getContacts()->contact(joinContactsData.contact2); + if ((contact1 == NULL) || (contact2 == NULL)) + return; + contact1->clientData.join(contact2->clientData); + if (!contact2->getPhones().isEmpty()){ + QString phones = contact1->getPhones(); + if (!phones.isEmpty()) + phones += ';'; + phones += contact2->getPhones(); + contact1->setPhones(phones); + } + if (!contact2->getEMails().isEmpty()){ + QString mails = contact1->getEMails(); + if (!mails.isEmpty()) + mails += ';'; + mails += contact2->getEMails(); + contact1->setEMails(mails); + } + delete contact2; + contact1->setup(); + EventContact(contact1, EventContact::eChanged).process(); +} + +void UserView::cancelJoinContacts(void*) +{ + Contact *contact2 = getContacts()->contact(joinContactsData.contact2); + if (contact2 && (contact2->getFlags() & CONTACT_TEMPORARY)) + delete contact2; +} + +void UserView::sortAll() +{ + //sort(); + for(int c = 0; c < topLevelItemCount(); c++) + { + ListViewItem *item = static_cast(topLevelItem(c)); + sortAll(item); + } +} + +void UserView::sortAll(ListViewItem *item) +{ + //item->sort(); + for(int c = 0; c < topLevelItemCount(); c++) + { + ListViewItem *item = static_cast(topLevelItem(c)); + sortAll(item); + } +} + +void UserView::search(list &items) +{ + if (m_search.isEmpty()) + return; + list::iterator it; + for (it = closed_items.begin(); it != closed_items.end(); ++it) + (*it)->setOpen(false); + for(int c = 0; c < topLevelItemCount(); c++) + { + ListViewItem *item = static_cast(topLevelItem(c)); + search(item, items); + } +} + +void UserView::search(ListViewItem *item, list &items) +{ + if (item->isExpandable()){ + for(int c = 0; c < item->childCount(); c++) + { + ListViewItem *ch = static_cast(item->child(c)); + search(ch, items); + } + } + if (static_cast(item)->type() != USR_ITEM) + return; + QString name = item->text(CONTACT_TEXT); + //log(L_DEBUG, "Contact List search: Examining name %s", (const char *)name.local8Bit()); + //Search from the beginning of contact name + //if (name.left(m_search.length()).upper() == m_search.upper()) + //Search for substring in contact name + if (name.contains(m_search,Qt::CaseInsensitive)>0) { + //log(L_DEBUG, "Contact List search: Found name %s", (const char *)name.local8Bit()); + item->parent()->setExpanded(true); + items.push_back(item); + } else { + void *data; + Contact *contact = getContacts()->contact(static_cast(item)->id()); + ClientDataIterator it(contact->clientData); + while ((data = ++it) != NULL) + { + Client *client = contact->clientData.activeClient(data, it.client()); + if (client == NULL) + continue; + QString contactName = client->contactName(data); + //log(L_DEBUG, "Contact List search: Examining ID %s", (const char *)contactName.local8Bit()); + if (contactName.contains(m_search,Qt::CaseInsensitive)>0) + { + //log(L_DEBUG, "Contact List search: Found ID %s", (const char *)contactName.local8Bit()); + item->parent()->setExpanded(true); + items.push_back(item); + break; + } + } + } +} + +void UserView::dragScroll() //rewrite!? +{ + QPoint pos = QCursor::pos(); + pos = viewport()->mapFromGlobal(pos); + if ((pos.x() < 0) || (pos.x() > viewport()->width())) + return; + ListViewItem *item = NULL; + if (pos.y() < 0) + { + pos = QPoint(pos.x(), -1); + item = itemAt(pos); + } + else if (pos.y() > viewport()->height()) + { + pos = QPoint(pos.x(), viewport()->height() - 1); + item = itemAt(pos); //<== FIXME: crash, it does not return item, sometimes in QGList append() no mem allocation is possible :-/ ??? + if (item) + { + pos = QPoint(pos.x(), viewport()->height() - 1 + item->height()); + item = itemAt(pos); + } + } + + //if (item) + //scrollTo(model()->index(item->row(), item->column())); +} + +// vim: set expandtab: diff --git a/plugins/_core/userview.h b/plugins/_core/userview.h new file mode 100644 index 0000000..aa67371 --- /dev/null +++ b/plugins/_core/userview.h @@ -0,0 +1,107 @@ +/*************************************************************************** + userview.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _USERVIEW_H +#define _USERVIEW_H + +#include "userlist.h" +#include "userwnd.h" + +//#include +//#include +//#include +//#include +//#include +//#include +//#include + +class CorePlugin; +class IntLineEdit; +class QTimer; + +struct BlinkCount +{ + unsigned long id; + unsigned count; +}; + +class UserView : public UserListBase +{ + Q_OBJECT +public: + UserView(); + ~UserView(); + CorePlugin *m_plugin; + IntLineEdit *m_edtGroup; + IntLineEdit *m_edtContact; + ListViewItem *mTipItem; + bool m_bUnreadBlink; +public slots: + void editGroupEnter(); + void editContactEnter(); + void editEscape(); + void renameGroup(); + void renameContact(); + void deleteGroup(void*); + void deleteContact(void*); + void joinContacts(void*); + void cancelJoinContacts(void*); + void blink(); + void unreadBlink(); + void doDrop(); + void doClick(); + void dragScroll(); +protected: + virtual unsigned getUnread(unsigned contact_id); + virtual bool getMenu(ListViewItem *item, unsigned long &id, void* ¶m); + virtual bool processEvent(SIM::Event*); + bool eventFilter(QObject *obj, QEvent *e); + void setGroupMode(unsigned mode, bool bFirst=false); + void keyPressEvent(QKeyEvent *e); + void mousePressEvent(QMouseEvent *e); + void mouseReleaseEvent(QMouseEvent *e); + void mouseDoubleClickEvent(QMouseEvent *e); + void dragEnterEvent(QDragEnterEvent *e); + virtual void dragMoveEvent(QDragMoveEvent *e); + void dropEvent(QDropEvent *e); + void focusOutEvent(QFocusEvent*); + void sortAll(); + void sortAll(ListViewItem*); + void dragEvent(QDropEvent *e, bool isDrop); + void search(std::list &items); + void search(ListViewItem*, std::list &items); + void stopSearch(); + virtual QMimeData *mimeData( const QList items ) const; + QMimeData *dragObject(); + virtual void deleteItem(ListViewItem *item); + std::list blinks; + std::list closed_items; + unsigned long m_dropContactId; + ListViewItem *m_dropItem; + ListViewItem *m_current; + bool m_bBlink; + QTimer *m_blinkTimer; + QTimer *m_unreadTimer; + QString m_search; + bool m_bRemoveHistory; + ListViewItem *m_searchItem; + friend class UserViewDelegate; + UserWnd *m_userWnd; +}; + +#endif + diff --git a/plugins/_core/userviewcfg.cpp b/plugins/_core/userviewcfg.cpp new file mode 100644 index 0000000..de09ebd --- /dev/null +++ b/plugins/_core/userviewcfg.cpp @@ -0,0 +1,240 @@ +/*************************************************************************** + userviewcfg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "icons.h" +#include "userviewcfg.h" +#include "core.h" + +#include +#include +#include + +using namespace SIM; + +UserViewConfig::UserViewConfig(QWidget *parent) : QWidget(parent) +{ + setupUi(this); + chkDblClick->setChecked(CorePlugin::instance()->value("UseDblClick").toBool()); + chkSysColors->setChecked(CorePlugin::instance()->value("UseSysColors").toBool()); + btnOnline->setColor(CorePlugin::instance()->value("ColorOnline").toUInt()); + btnOffline->setColor(CorePlugin::instance()->value("ColorOffline").toUInt()); + btnAway->setColor(CorePlugin::instance()->value("ColorAway").toUInt()); + btnNA->setColor(CorePlugin::instance()->value("ColorNA").toUInt()); + btnDND->setColor(CorePlugin::instance()->value("ColorDND").toUInt()); + btnGroup->setColor(CorePlugin::instance()->value("ColorGroup").toUInt()); + chkGroupSeparator->setChecked(CorePlugin::instance()->value("GroupSeparator").toBool()); + chkSmallFont->setChecked(CorePlugin::instance()->value("SmallGroupFont").toBool()); + chkScroll->setChecked(CorePlugin::instance()->value("NoScroller").toBool()); + connect(chkSysColors, SIGNAL(toggled(bool)), this, SLOT(colorsToggled(bool))); + colorsToggled(chkSysColors->isChecked()); + fillBox(cmbSort1); + fillBox(cmbSort2); + fillBox(cmbSort3); + CorePlugin::instance()->setValue("SortMode", CorePlugin::instance()->value("SortMode").toUInt()); + connect(cmbSort1, SIGNAL(activated(int)), this, SLOT(sortChanged(int))); + connect(cmbSort2, SIGNAL(activated(int)), this, SLOT(sortChanged(int))); + connect(cmbSort3, SIGNAL(activated(int)), this, SLOT(sortChanged(int))); + btnAuth1->setIcon(Icon("text_strike")); + btnAuth2->setIcon(Icon("text_italic")); + btnAuth3->setIcon(Icon("text_under")); + btnVisible1->setIcon(Icon("text_strike")); + btnVisible2->setIcon(Icon("text_italic")); + btnVisible3->setIcon(Icon("text_under")); + btnInvisible1->setIcon(Icon("text_strike")); + btnInvisible2->setIcon(Icon("text_italic")); + btnInvisible3->setIcon(Icon("text_under")); + btnAuth1->setChecked(true); + btnAuth2->setChecked(true); + btnAuth3->setChecked(true); + btnVisible1->setChecked(true); + btnVisible2->setChecked(true); + btnVisible3->setChecked(true); + btnInvisible1->setChecked(true); + btnInvisible2->setChecked(true); + btnInvisible3->setChecked(true); + connect(btnAuth1, SIGNAL(toggled(bool)), this, SLOT(setFonts(bool))); + connect(btnAuth2, SIGNAL(toggled(bool)), this, SLOT(setFonts(bool))); + connect(btnAuth3, SIGNAL(toggled(bool)), this, SLOT(setFonts(bool))); + connect(btnVisible1, SIGNAL(toggled(bool)), this, SLOT(setFonts(bool))); + connect(btnVisible2, SIGNAL(toggled(bool)), this, SLOT(setFonts(bool))); + connect(btnVisible3, SIGNAL(toggled(bool)), this, SLOT(setFonts(bool))); + connect(btnInvisible1, SIGNAL(toggled(bool)), this, SLOT(setFonts(bool))); + connect(btnInvisible2, SIGNAL(toggled(bool)), this, SLOT(setFonts(bool))); + connect(btnInvisible3, SIGNAL(toggled(bool)), this, SLOT(setFonts(bool))); + btnAuth1->setChecked((CorePlugin::instance()->value("AuthStyle").toUInt() & STYLE_STRIKE) != 0); + btnAuth2->setChecked((CorePlugin::instance()->value("AuthStyle").toUInt() & STYLE_ITALIC) != 0); + btnAuth3->setChecked((CorePlugin::instance()->value("AuthStyle").toUInt() & STYLE_UNDER) != 0); + btnVisible1->setChecked((CorePlugin::instance()->value("VisibleStyle").toUInt() & STYLE_STRIKE) != 0); + btnVisible2->setChecked((CorePlugin::instance()->value("VisibleStyle").toUInt() & STYLE_ITALIC) != 0); + btnVisible3->setChecked((CorePlugin::instance()->value("VisibleStyle").toUInt() & STYLE_UNDER) != 0); + btnInvisible1->setChecked((CorePlugin::instance()->value("InvisibleStyle").toUInt() & STYLE_STRIKE) != 0); + btnInvisible2->setChecked((CorePlugin::instance()->value("InvisibleStyle").toUInt() & STYLE_ITALIC) != 0); + btnInvisible3->setChecked((CorePlugin::instance()->value("InvisibleStyle").toUInt() & STYLE_UNDER) != 0); + setFonts(true); +} + +UserViewConfig::~UserViewConfig() +{ +} + +void UserViewConfig::apply() +{ + CorePlugin::instance()->setValue("UseDblClick", chkDblClick->isChecked()); + CorePlugin::instance()->setValue("UseSysColors", chkSysColors->isChecked()); + CorePlugin::instance()->setValue("GroupSeparator", chkGroupSeparator->isChecked()); + CorePlugin::instance()->setValue("SortMode", getSortMode()); + CorePlugin::instance()->setValue("SmallGroupFont", chkSmallFont->isChecked()); + CorePlugin::instance()->setValue("NoScroller", chkScroll->isChecked()); + if (CorePlugin::instance()->value("UseSysColors").toBool()){ + CorePlugin::instance()->setValue("ColorOnline", 0); + CorePlugin::instance()->setValue("ColorOffline", 0); + CorePlugin::instance()->setValue("ColorAway", 0); + CorePlugin::instance()->setValue("ColorNA", 0); + CorePlugin::instance()->setValue("ColorDND", 0); + CorePlugin::instance()->setValue("ColorGroup", 0); + }else{ + CorePlugin::instance()->setValue("ColorOnline", btnOnline->color().rgb()); + CorePlugin::instance()->setValue("ColorOffline", btnOffline->color().rgb()); + CorePlugin::instance()->setValue("ColorAway", btnAway->color().rgb()); + CorePlugin::instance()->setValue("ColorNA", btnNA->color().rgb()); + CorePlugin::instance()->setValue("ColorDND", btnDND->color().rgb()); + CorePlugin::instance()->setValue("ColorGroup", btnGroup->color().rgb()); + } + unsigned style = 0; + if (btnAuth1->isChecked()) style |= STYLE_STRIKE; + if (btnAuth2->isChecked()) style |= STYLE_ITALIC; + if (btnAuth3->isChecked()) style |= STYLE_UNDER; + CorePlugin::instance()->setValue("AuthStyle", style); + style = 0; + if (btnVisible1->isChecked()) style |= STYLE_STRIKE; + if (btnVisible2->isChecked()) style |= STYLE_ITALIC; + if (btnVisible3->isChecked()) style |= STYLE_UNDER; + CorePlugin::instance()->setValue("VisibleStyle", style); + style = 0; + if (btnInvisible1->isChecked()) style |= STYLE_STRIKE; + if (btnInvisible2->isChecked()) style |= STYLE_ITALIC; + if (btnInvisible3->isChecked()) style |= STYLE_UNDER; + CorePlugin::instance()->setValue("InvisibleStyle", style); + EventRepaintView e; + e.process(); +} + +void UserViewConfig::colorsToggled(bool state) +{ + if (state){ + QColor textColor = palette().color(QPalette::Active, QPalette::Text); + QColor disabledColor = palette().color(QPalette::Disabled, QPalette::Text); + btnOnline->setColor(textColor); + btnOffline->setColor(disabledColor); + btnAway->setColor(disabledColor); + btnNA->setColor(disabledColor); + btnDND->setColor(disabledColor); + btnGroup->setColor(disabledColor); + } + btnOnline->setEnabled(!state); + btnOffline->setEnabled(!state); + btnAway->setEnabled(!state); + btnNA->setEnabled(!state); + btnDND->setEnabled(!state); + btnGroup->setEnabled(!state); + lblOnline->setEnabled(!state); + lblOffline->setEnabled(!state); + lblAway->setEnabled(!state); + lblNA->setEnabled(!state); + lblDND->setEnabled(!state); + lblGroup->setEnabled(!state); + lblColors->setEnabled(!state); +} + +void UserViewConfig::fillBox(QComboBox *cmb) +{ + cmb->insertItem(INT_MAX,i18n("Status")); + cmb->insertItem(INT_MAX,i18n("Last message time")); + cmb->insertItem(INT_MAX,i18n("Contact name")); + cmb->insertItem(INT_MAX,""); +} + +void UserViewConfig::setSortMode(unsigned mode) +{ + QComboBox *cmb[3] = { cmbSort1, cmbSort2, cmbSort3 }; + unsigned i; + for (i = 0; i < 3; i++){ + cmb[i]->setEnabled(true); + unsigned m = mode & 0xFF; + mode = mode >> 8; + if (m == 0){ + cmb[i++]->setCurrentIndex(3); + break; + } + cmb[i]->setCurrentIndex(m - 1); + } + for (;i < 3; i++){ + cmb[i]->setCurrentIndex(3); + cmb[i]->setEnabled(false); + } +} + +void UserViewConfig::sortChanged(int) +{ + setSortMode(getSortMode()); +} + +void UserViewConfig::setFonts(bool) +{ + QFont fAuth(font()); + fAuth.setStrikeOut(btnAuth1->isChecked()); + fAuth.setItalic(btnAuth2->isChecked()); + fAuth.setUnderline(btnAuth3->isChecked()); + lblAuth->setFont(fAuth); + QFont fVisible(font()); + fVisible.setStrikeOut(btnVisible1->isChecked()); + fVisible.setItalic(btnVisible2->isChecked()); + fVisible.setUnderline(btnVisible3->isChecked()); + lblVisible->setFont(fVisible); + QFont fInvisible(font()); + fInvisible.setStrikeOut(btnInvisible1->isChecked()); + fInvisible.setItalic(btnInvisible2->isChecked()); + fInvisible.setUnderline(btnInvisible3->isChecked()); + lblInvisible->setFont(fInvisible); +} + +unsigned UserViewConfig::getSortMode() +{ + unsigned m1 = cmbSort1->currentIndex() + 1; + if (m1 > 3) + m1 = 0; + unsigned m2 = cmbSort2->currentIndex() + 1; + if (m2 > 3) + m2 = 0; + unsigned m3 = cmbSort3->currentIndex() + 1; + if (m3 > 3) + m3 = 0; + if (m1){ + if (m2 == m1) + m2 = 0; + if (m2){ + if ((m3 == m1) || (m3 == m2)) + m3 = 0; + }else{ + m3 = 0; + } + }else{ + m2 = 0; + m3 = 0; + } + return (m3 << 16) + (m2 << 8) + m1; +} diff --git a/plugins/_core/userviewcfg.h b/plugins/_core/userviewcfg.h new file mode 100644 index 0000000..db85932 --- /dev/null +++ b/plugins/_core/userviewcfg.h @@ -0,0 +1,44 @@ +/*************************************************************************** + userviewcfg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _USERVIEWCFG_H +#define _USERVIEWCFG_H + +#include "simgui/qcolorbutton.h" +#include "ui_userviewcfgbase.h" + +class CorePlugin; + +class UserViewConfig : public QWidget, public Ui::ContactList +{ + Q_OBJECT +public: + UserViewConfig(QWidget *parent); + ~UserViewConfig(); +public slots: + void apply(); + void colorsToggled(bool); + void sortChanged(int); + void setFonts(bool); +protected: + void fillBox(QComboBox*); + void setSortMode(unsigned); + unsigned getSortMode(); +}; + +#endif + diff --git a/plugins/_core/userviewcfgbase.ui b/plugins/_core/userviewcfgbase.ui new file mode 100644 index 0000000..260b428 --- /dev/null +++ b/plugins/_core/userviewcfgbase.ui @@ -0,0 +1,475 @@ + + + ContactList + + + + 0 + 0 + 427 + 400 + + + + Form2 + + + + 11 + + + 6 + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + 0 + + + 6 + + + + + + + + Groups + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + Do not distrub + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + + + + Offline + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + Online: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Away + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + N/A + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + Colors: + + + false + + + + + + + + + + + + Use &double click + + + + + + + Use system &colors + + + + + + + Use small &font for group + + + + + + + Show group &separator + + + + + + + 6 + + + 0 + + + + + 0 + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + + + + Invisible + + + false + + + + + + + + + 6 + + + 0 + + + + + 0 + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + + + + Visible + + + false + + + + + + + + + 6 + + + 0 + + + + + 0 + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + + + + Awaiting authorization + + + false + + + + + + + + + No show scroller + + + + + + + Sorting + + + + + + 1st: + + + false + + + + + + + + 0 + 0 + + + + + + + + 2nd: + + + false + + + + + + + + 0 + 0 + + + + + + + + 3rd: + + + false + + + + + + + + 0 + 0 + + + + + + cmbSort1 + TextLabel2 + cmbSort2 + TextLabel3 + TextLabel1 + cmbSort3 + cmbSort1 + TextLabel2 + cmbSort2 + TextLabel3 + TextLabel1 + cmbSort3 + cmbSort1 + TextLabel2 + cmbSort2 + TextLabel3 + TextLabel1 + cmbSort3 + + + + + + + QColorButton + QWidget +
simgui/qcolorbutton.h
+
+
+ + chkDblClick + chkSysColors + chkSmallFont + chkGroupSeparator + chkScroll + btnAuth1 + btnAuth2 + btnAuth3 + btnVisible1 + btnVisible2 + btnVisible3 + btnInvisible1 + btnInvisible2 + btnInvisible3 + + + +
diff --git a/plugins/_core/userviewdelegate.cpp b/plugins/_core/userviewdelegate.cpp new file mode 100644 index 0000000..7f37cf4 --- /dev/null +++ b/plugins/_core/userviewdelegate.cpp @@ -0,0 +1,289 @@ +#include "userviewdelegate.h" + +#include + +#include "userview.h" +#include "log.h" +#include "core.h" +#include "icons.h" +#include "contacts/group.h" + +using namespace SIM; + +UserViewDelegate::UserViewDelegate(UserView* uv) : m_uv(uv) +{ +} + +void UserViewDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const +{ + UserViewItemBase *base = dynamic_cast(m_uv->itemFromIndex(index)); + if( NULL == base ) + return; + + painter->save(); + painter->translate(option.rect.x(), option.rect.y()); + + QPainter *p = painter; + QPalette cg = option.palette; + int width = option.rect.width(); + int height = option.rect.height(); + QSize itemsize = option.rect.size(); + int margin = 1; + + switch( base->type() ) + { + case GRP_ITEM: + { + GroupItem *item = static_cast(base); + QString text = index.data( Qt::DisplayRole ).toString(); + QImage img = Image( ( option.state & QStyle::State_Open ) ? "expanded" : "collapsed"); + if (!img.isNull()) + p->drawImage(2 + margin, (height - img.height()) / 2, img); + int x = 24 + margin; + if (!( option.state & QStyle::State_Open ) && item->m_unread){ + CommandDef *def = CorePlugin::instance()->messageTypes.find(item->m_unread); + if (def){ + img = Image(def->icon); + if (!img.isNull()){ + if (m_uv->m_bUnreadBlink) + p->drawImage(x, (height - img.height()) / 2, img); + x += img.width() + 2; + } + } + } + if (!CorePlugin::instance()->value("UseSysColors").toBool()) + p->setPen(CorePlugin::instance()->value("ColorGroup").toUInt()); + QFont f(option.font); + if (CorePlugin::instance()->value("SmallGroupFont").toBool()){ + int size = f.pixelSize(); + if (size <= 0){ + size = f.pointSize(); + f.setPointSize(size * 3 / 4); + }else{ + f.setPixelSize(size * 3 / 4); + } + } + f.setBold(true); + p->setFont(f); + x = drawText(p, x, itemsize, text); + if (CorePlugin::instance()->value("GroupSeparator").toBool()) + drawSeparator(p, x, itemsize, m_uv->style()); + break; + } + case USR_ITEM: + { + ContactItem *item = static_cast(base); + QFont f(option.font); + if (item->style() & CONTACT_ITALIC){ + if (CorePlugin::instance()->value("VisibleStyle").toUInt() & STYLE_ITALIC) + f.setItalic(true); + if (CorePlugin::instance()->value("VisibleStyle").toUInt() & STYLE_UNDER) + f.setUnderline(true); + if (CorePlugin::instance()->value("VisibleStyle").toUInt() & STYLE_STRIKE) + f.setStrikeOut(true); + } + if (item->style() & CONTACT_UNDERLINE){ + if (CorePlugin::instance()->value("AuthStyle").toUInt() & STYLE_ITALIC) + f.setItalic(true); + if (CorePlugin::instance()->value("AuthStyle").toUInt() & STYLE_UNDER) + f.setUnderline(true); + if (CorePlugin::instance()->value("AuthStyle").toUInt() & STYLE_STRIKE) + f.setStrikeOut(true); + } + if (item->style() & CONTACT_STRIKEOUT){ + if (CorePlugin::instance()->value("InvisibleStyle").toUInt() & STYLE_ITALIC) + f.setItalic(true); + if (CorePlugin::instance()->value("InvisibleStyle").toUInt() & STYLE_UNDER) + f.setUnderline(true); + if (CorePlugin::instance()->value("InvisibleStyle").toUInt() & STYLE_STRIKE) + f.setStrikeOut(true); + } + int x = margin; + QIcon mainIcon = index.data( Qt::DecorationRole ).value(); + if (!mainIcon.isNull()){ + QPixmap img = mainIcon.pixmap( 16 ); + x += 2; + p->drawPixmap(x, ( height - img.height() ) / 2, img); + x += img.width() + 2; + } + if (x < 24) + x = 24; + if (!item->isSelected() || !m_uv->hasFocus() || !CorePlugin::instance()->value("UseDblClick").toBool()){ + if (CorePlugin::instance()->value("UseSysColors").toBool()){ + if (item->status() != STATUS_ONLINE && item->status() != STATUS_FFC) + p->setPen(m_uv->palette().color(QPalette::Disabled,QPalette::Text)); + }else{ + switch (item->status()){ + case STATUS_ONLINE: + p->setPen(CorePlugin::instance()->value("ColorOnline").toUInt()); + break; + case STATUS_FFC: + p->setPen(CorePlugin::instance()->value("ColorOnline").toUInt()); + break; + case STATUS_AWAY: + p->setPen(CorePlugin::instance()->value("ColorAway").toUInt()); + break; + case STATUS_NA: + p->setPen(CorePlugin::instance()->value("ColorNA").toUInt()); + break; + case STATUS_DND: + p->setPen(CorePlugin::instance()->value("ColorDND").toUInt()); + break; + default: + p->setPen(CorePlugin::instance()->value("ColorOffline").toUInt()); + break; + } + } + } + if (item->m_bBlink) + f.setBold(true); + else + f.setBold(false); + + p->setFont(f); + QString highlight; + QString text = index.data( Qt::DisplayRole ).toString(); + int pos=0; + if(!m_uv->m_search.isEmpty()) + { + pos=text.toUpper().indexOf(m_uv->m_search.toUpper()); + //Search for substring in contact name + if (pos > -1) + highlight=text.mid(pos,m_uv->m_search.length()); + } + int save_x = x; + //p->setPen(QColor(0, 0, 0)); + x = drawText(p, x, itemsize, text); + if (pos > 0) + save_x = drawText(p, save_x, itemsize, text.left(pos)) - 4; + x += 2; + if (!highlight.isEmpty()) + { + QPen oldPen = p->pen(); + QColor oldBg = p->background().color(); + p->setBackgroundMode(Qt::OpaqueMode); + if (item == m_uv->m_searchItem){ + if ((item == m_uv->currentItem()) && CorePlugin::instance()->value("UseDblClick").toBool()){ + p->setBackground(cg.color(QPalette::HighlightedText)); + p->setPen(cg.color(QPalette::Highlight)); + }else{ + p->setBackground(cg.color(QPalette::Highlight)); + p->setPen(cg.color(QPalette::HighlightedText)); + } + }else{ + p->setBackground(oldPen.color()); + p->setPen(oldBg); + } + drawText(p, save_x, itemsize, highlight); + p->setPen(oldPen); + p->setBackground(oldBg); + p->setBackgroundMode(Qt::TransparentMode); + } + unsigned xIcon = width; + QString icons = index.data( SIM::ExtraIconsRole ).toString(); + while( !icons.isEmpty() ) { + QString icon = getToken(icons, ','); + QImage img = Image(icon); + if (!img.isNull()){ + xIcon -= img.width() + 2; + if (xIcon < (unsigned)x) + break; + p->drawImage(xIcon, (height - img.height()) / 2, img); + } + } + break; + } + case DIV_ITEM: + { + QString text = index.data( Qt::DisplayRole ).toString(); + QFont f(option.font); + int size = f.pixelSize(); + if (size <= 0) + { + size = f.pointSize(); + f.setPointSize(size * 3 / 4); + } + else + { + f.setPixelSize(size * 3 / 4); + } + p->setFont(f); + int x = drawText(p, 24 + margin, itemsize, text); + drawSeparator(p, x, itemsize, m_uv->style()); + break; + } + } + + painter->restore(); +} + +QSize UserViewDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const +{ + UserViewItemBase *base = dynamic_cast(m_uv->itemFromIndex(index)); + + QSize size; + if(!base) + return size; + + size.setWidth( m_uv->width() ); + + QFont f(option.font); + int h = 0; + if (base->type() == GRP_ITEM){ + if (CorePlugin::instance()->value("SmallGroupFont").toBool()){ + int size = f.pixelSize(); + if (size <= 0){ + size = f.pointSize(); + f.setPointSize(size * 3 / 4); + }else{ + f.setPixelSize(size * 3 / 4); + } + } + h = 14; + } + if (base->type() == USR_ITEM){ + ContactItem *item = static_cast(base); + QString icons = item->text(CONTACT_ICONS); + while (!icons.isEmpty()){ + QString icon = getToken(icons, ','); + QImage img = Image(icon); + if (img.height() > h) + h = img.height(); + } + if (item->m_unread){ + CommandDef *def = CorePlugin::instance()->messageTypes.find(item->m_unread); + if (def){ + QImage img = Image(def->icon); + if (img.height() > h) + h = img.height(); + } + } + } + QFontMetrics fm(f); + int fh = fm.height(); + if (fh > h) + h = fh; + + size.setHeight( h + 2 ); + + return size; +} + +int UserViewDelegate::drawText(QPainter *p, int x, QSize size, const QString &text) const +{ + QRect br; + p->drawText(x, 0, size.width(), size.height(), Qt::AlignLeft | Qt::AlignVCenter, text, &br); + return br.right() + 5; +} + +void UserViewDelegate::drawSeparator(QPainter *p, int x, QSize size, QStyle *style) const +{ + if (x < size.width() - 6) + { + QStyleOption option; + option.rect = QRect(x, size.height()/2, size.width() - 6 - x, 1); + style->drawPrimitive(QStyle::PE_Q3Separator, &option, p); + } +} + +// vim: set expandtab: diff --git a/plugins/_core/userviewdelegate.h b/plugins/_core/userviewdelegate.h new file mode 100644 index 0000000..e499d90 --- /dev/null +++ b/plugins/_core/userviewdelegate.h @@ -0,0 +1,25 @@ + +#ifndef CORE_USERVIEWDELEGATE_H +#define CORE_USERVIEWDELEGATE_H + +#include + +class UserView; +class UserViewDelegate : public QItemDelegate +{ +public: + UserViewDelegate(UserView* uv); + virtual void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; + virtual QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const; + +protected: + int drawText(QPainter *p, int x, QSize size, const QString &text) const; + void drawSeparator(QPainter *p, int x, QSize size, QStyle *style) const; + +private: + UserView* m_uv; +}; + +#endif + +// vim: set expandtab: diff --git a/plugins/_core/userwnd.cpp b/plugins/_core/userwnd.cpp new file mode 100644 index 0000000..8cedd4c --- /dev/null +++ b/plugins/_core/userwnd.cpp @@ -0,0 +1,340 @@ +/*************************************************************************** + userwnd.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "log.h" + +#include "userwnd.h" +#include "msgedit.h" +#include "msgview.h" +#include "simgui/toolbtn.h" +#include "userlist.h" +#include "core.h" +#include "container.h" +#include "history.h" +#include "contacts/contact.h" +#include "contacts/client.h" + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace SIM; + +static DataDef userWndData[] = + { + { "EditHeight", DATA_ULONG, 1, 0 }, + { "EditBar", DATA_LONG, 7, 0 }, + { "MessageType", DATA_ULONG, 1, 0 }, + { NULL, DATA_UNKNOWN, 0, 0 } + }; + +//FIXME: Obsolete? +//static void copyData(SIM::Data *dest, const SIM::Data *src, unsigned count) +//{ +// for(unsigned i = 0; i < count; i++) +// dest[i] = src[i]; +//} + +UserWnd::UserWnd(unsigned long id, Buffer *cfg, bool bReceived, bool bAdjust) + : QSplitter(Qt::Horizontal, NULL) +{ + load_data(userWndData, &data, cfg); + m_id = id; + m_bResize = false; + m_bClosed = false; + m_bTyping = false; + setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); + + m_splitter = new QSplitter(Qt::Vertical, this); + m_list = NULL; + m_view = NULL; + /* Fixme Todin + if (cfg == NULL) + copyData(data.editBar, CorePlugin::instance()->data.EditBar, 7); + */ + + m_bBarChanged = true; + if (CorePlugin::instance()->getContainerMode()) + bReceived = false; + addWidget(m_splitter); + m_edit = new MsgEdit(m_splitter, this); + setFocusProxy(m_edit); + restoreToolbar(m_edit->m_bar, data.editBar); + m_bBarChanged = false; + m_splitter->addWidget(m_edit); + + connect(m_edit->m_bar, SIGNAL(movableChanged(bool)), this, SLOT(toolbarChanged(bool))); + connect(CorePlugin::instance(), SIGNAL(modeChanged()), this, SLOT(modeChanged())); + connect(m_edit, SIGNAL(heightChanged(int)), this, SLOT(editHeightChanged(int))); + modeChanged(); + + if (!bAdjust && getMessageType() == 0) + return; + + if (!m_edit->adjustType()) + { + unsigned type = getMessageType(); + Message *msg = new Message(MessageGeneric); + setMessage(msg); + delete msg; + setMessageType(type); + } +} + +UserWnd::~UserWnd() +{ + emit closed(this); + free_data(userWndData, &data); + Contact *contact = getContacts()->contact(id()); + if (contact && (contact->getFlags() & CONTACT_TEMPORARY)){ + m_id = 0; + delete contact; + } +} + +QByteArray UserWnd::getConfig() +{ + return save_data(userWndData, &data); +} + +QString UserWnd::getName() +{ + Contact *contact = getContacts()->contact(m_id); + return contact ? contact->getName() : QString::null; +} + +QString UserWnd::getLongName() +{ + QString res; + if (CorePlugin::instance()->value("ShowOwnerName").toBool() && !getContacts()->owner()->getName().isEmpty()) + res += getContacts()->owner()->getName(); + if (!res.isEmpty()) + res += " - "; + Contact *contact = getContacts()->contact(m_id); + if (contact) + res += contact->getName(); + else + return QString::null; + void *data; + Client *client = m_edit->client(data, false, true, id()); + if (client && data){ + res += ' '; + res += client->contactName(data); + if (!m_edit->m_resource.isEmpty()) + { + res += '/'; + res += m_edit->m_resource; + } + bool bFrom = false; + for (unsigned i = 0; i < getContacts()->nClients(); i++){ + Client *pClient = getContacts()->getClient(i); + if (pClient == client) + continue; + Contact *contact; + clientData *data1 = (clientData*)data; + if (pClient->isMyData(data1, contact)){ + bFrom = true; + break; + } + } + if (bFrom){ + res += ' '; + if (m_edit->m_bReceived){ + res += i18n("to %1") .arg(client->name()); + }else{ + res += i18n("from %1") .arg(client->name()); + } + } + } + return res; +} + +QString UserWnd::getIcon() +{ + Contact *contact = getContacts()->contact(m_id); + if(!contact) { + log(L_ERROR, "Contact %lu not found!", m_id); + return QString::null; + } + unsigned long status = STATUS_UNKNOWN; + unsigned style; + QString statusIcon; + void *data; + Client *client = m_edit->client(data, false, true, id()); + if (client){ + client->contactInfo(data, status, style, statusIcon); + }else{ + contact->contactInfo(style, statusIcon); + } + return statusIcon; +} + +void UserWnd::modeChanged() +{ + if (CorePlugin::instance()->getContainerMode()) + { + if (m_view == NULL) + m_view = new MsgView(m_splitter, m_id); + m_splitter->insertWidget(0, m_view); + m_splitter->setStretchFactor(0, 0); + m_view->show(); + int editHeight = getEditHeight(); + if (editHeight == 0) + editHeight = CorePlugin::instance()->value("EditHeight").toInt(); //getEditHeight(); + if (editHeight){ + QList s; + s.append(1); + s.append(editHeight); + m_bResize = true; + m_splitter->setSizes(s); + m_bResize = false; + } + } + else + { + if (m_view){ + delete m_view; + m_view = NULL; + } + } +} + +void UserWnd::editHeightChanged(int h) +{ + if (!m_bResize && CorePlugin::instance()->getContainerMode()){ + setEditHeight(h); + CorePlugin::instance()->setValue("EditHeight", h); + } +} + +void UserWnd::toolbarChanged(bool) +{ + if (m_bBarChanged) + return; + //saveToolbar(m_edit->m_bar, data.editBar); + //copyData(CorePlugin::instance()->data.EditBar, data.editBar, 7); +} + +unsigned UserWnd::type() +{ + return m_edit->type(); +} + +void UserWnd::setMessage(Message *msg) +{ + bool bSetFocus = false; + + Container *container = NULL; + if (topLevelWidget() && topLevelWidget()->inherits("Container")) + { + container = static_cast(topLevelWidget()); + if (container->wnd() == this) + bSetFocus = true; + } + if (!m_edit->setMessage(msg, bSetFocus)) + { + // if this does not work as expected, we have to go back + // to EventOpenMessage with Message** :( + *msg = Message(MessageGeneric); + m_edit->setMessage(msg, bSetFocus); + } + if (container) + { + container->setMessageType(msg->baseType()); + container->contactChanged(getContacts()->contact(m_id)); + } + + if ((m_view == NULL) || (msg->id() == 0)) + return; + if (m_view->findMessage(msg)) + return; + m_view->addMessage(msg); +} + +void UserWnd::setStatus(const QString &status) +{ + m_status = status; + emit statusChanged(this); +} + +void UserWnd::showListView(bool bShow) +{ + if(bShow) + { + if (m_list == NULL) + { + m_list = new UserList(this); + setStretchFactor(indexOf(m_list), 1); + connect(m_list, SIGNAL(selectChanged()), this, SLOT(selectChanged())); + + if(topLevelWidget()->inherits("Container")) + { + Container *c = qobject_cast(topLevelWidget()); + list wnd = c->windows(); + for (list::iterator it = wnd.begin(); it != wnd.end(); ++it) + m_list->select((*it)->id()); + } + } + m_list->show(); + emit multiplyChanged(); + return; + } + if (m_list == NULL) + return; + delete m_list; + m_list = NULL; + emit multiplyChanged(); +} + +void UserWnd::selectChanged() +{ + emit multiplyChanged(); +} + +void UserWnd::closeEvent(QCloseEvent *e) +{ + QSplitter::closeEvent(e); + m_bClosed = true; + QTimer::singleShot(0, topLevelWidget(), SLOT(wndClosed())); +} + +void UserWnd::markAsRead() +{ + if (m_view == NULL) + return; + for (list::iterator it = CorePlugin::instance()->unread.begin(); it != CorePlugin::instance()->unread.end(); ) + { + if (it->contact != m_id) + { + ++it; + continue; + } + Message *msg = History::load(it->id, it->client, it->contact); + CorePlugin::instance()->unread.erase(it); + if (msg){ + EventMessageRead(msg).process(); + delete msg; + } + it = CorePlugin::instance()->unread.begin(); + } +} + diff --git a/plugins/_core/userwnd.h b/plugins/_core/userwnd.h new file mode 100644 index 0000000..a13fa64 --- /dev/null +++ b/plugins/_core/userwnd.h @@ -0,0 +1,87 @@ +/*************************************************************************** + userwnd.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _USERWND_H +#define _USERWND_H + +#include "cfg.h" +#include "message.h" + +#include +#include +#include + +class MsgEdit; +class MsgView; +class CorePlugin; +class QToolBar; +class UserList; + +struct UserWndData +{ + SIM::Data EditHeight; + SIM::Data editBar[7]; + SIM::Data MessageType; +}; + +class UserWnd : public QSplitter +{ + Q_OBJECT +public: + UserWnd(unsigned long id, Buffer *cfg, bool bReceived, bool bAdjust); + ~UserWnd(); + QByteArray getConfig(); + unsigned long id() const { return m_id; } + QString getName(); + QString getLongName(); + QString getIcon(); + unsigned type(); + void setMessage(SIM::Message*); + void setStatus(const QString&); + void showListView(bool bShow); + QString status() { return m_status; } + UserList *m_list; + void markAsRead(); + bool isClosed() { return m_bClosed; } + bool m_bTyping; + PROP_ULONG(MessageType); +signals: + void closed(UserWnd*); + void statusChanged(UserWnd*); + void multiplyChanged(); +protected slots: + void modeChanged(); + void editHeightChanged(int); + void toolbarChanged(bool); + void selectChanged(); +protected: + PROP_ULONG(EditHeight); + void closeEvent(QCloseEvent*); + MsgView *m_view; + MsgEdit *m_edit; + QSplitter *m_splitter; + QString m_status; + bool m_bResize; + bool m_bClosed; + bool m_bBarChanged; + unsigned long m_id; + UserWndData data; + friend class MsgEdit; +}; + +#endif + diff --git a/plugins/about/CMakeLists.txt b/plugins/about/CMakeLists.txt new file mode 100644 index 0000000..b682c4c --- /dev/null +++ b/plugins/about/CMakeLists.txt @@ -0,0 +1,24 @@ +################# +# about library # +################# +IF(BUILD_DROPPED) + +SET(about_SRCS + about.cpp + aboutdlg.cpp +) + +SET(about_HDRS + about.h + aboutdlg.h +) + +SET(about_UICS + aboutdlgbase.ui +) + +REMOVE_DEFINITIONS(-DQT3_SUPPORT) +REMOVE_DEFINITIONS(-DQT_3SUPPORT_LIB) +REMOVE_DEFINITIONS(-DQT3_SUPPORT_WARNINGS) +SIM_ADD_PLUGIN(about) +ENDIF(BUILD_DROPPED) diff --git a/plugins/about/about.cpp b/plugins/about/about.cpp new file mode 100644 index 0000000..5c35cf4 --- /dev/null +++ b/plugins/about/about.cpp @@ -0,0 +1,157 @@ +/*************************************************************************** + about.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "simapi.h" + +#ifdef USE_KDE +#include +#include +#else +#include "aboutdlg.h" +#endif +#include + +#include "misc.h" + +#include "about.h" +#include "aboutdata.h" +#include "core_consts.h" + +using namespace SIM; + +Plugin *createAboutPlugin(unsigned base, bool, Buffer*) +{ + Plugin *plugin = new AboutPlugin(base); + return plugin; +} + +static PluginInfo info = + { + I18N_NOOP("About"), + I18N_NOOP("Plugin provides about information"), + VERSION, + createAboutPlugin, + PLUGIN_DEFAULT + }; + +EXPORT_PROC PluginInfo* GetPluginInfo() +{ + return &info; +} + +AboutPlugin::AboutPlugin(unsigned base) + : Plugin(base) +{ + CmdBugReport = registerType(); + CmdAbout = registerType(); +#ifdef USE_KDE + CmdAboutKDE = registerType(); +#endif + + Command cmd; + cmd->id = CmdBugReport; + cmd->text = I18N_NOOP("&Bug report / Requests"); + cmd->bar_id = ToolBarMain; + cmd->menu_id = MenuMain; + cmd->menu_grp = 0xF000; + EventCommandCreate(cmd).process(); + + about = NULL; + cmd->id = CmdAbout; + cmd->text = I18N_NOOP("&About Sim-IM"); + cmd->icon = "SIM"; + EventCommandCreate(cmd).process(); + +#ifdef USE_KDE + about_kde = NULL; + cmd->id = CmdAboutKDE; + cmd->text = I18N_NOOP("About &KDE"); + cmd->icon = "about_kde"; + EventCommandCreate(cmd).process(); +#endif +} + +AboutPlugin::~AboutPlugin() +{ + if (about) + delete about; +#ifdef USE_KDE + if (about_kde) + delete about_kde; +#endif + EventCommandRemove(CmdBugReport).process(); + EventCommandRemove(CmdAbout).process(); +} + +bool AboutPlugin::processEvent(Event *e) +{ + if (e->type() == eEventCommandExec){ + EventCommandExec *ece = static_cast(e); + CommandDef *cmd = ece->cmd(); + if (cmd->id == CmdBugReport){ + QString s = "http://developer.berlios.de/bugs/?group_id=4482"; + EventGoURL eURL(s); + eURL.process(); + } + if (cmd->id == CmdAbout){ + if (about == NULL) + { + KAboutData *about_data = getAboutData(); + about_data->setTranslator( + I18N_NOOP("_: NAME OF TRANSLATORS\nYour names"), + I18N_NOOP("_: EMAIL OF TRANSLATORS\nYour emails")); + + about = new KAboutApplication( about_data, NULL, "about", false ); + connect(about, SIGNAL(finished()), this, SLOT(aboutDestroyed())); + } + raiseWindow(about); + } +#ifdef USE_KDE + if (cmd->id == CmdAboutKDE){ + if (about_kde == NULL) + { + about_kde = new KAboutKDE( NULL, "aboutkde", false); + connect(about_kde, SIGNAL(finished()), this, SLOT(aboutDestroyed())); + } + raiseWindow(about_kde); + } +#endif + } + return false; +} + +void AboutPlugin::aboutDestroyed() +{ + QTimer::singleShot( 0, this, SLOT(realDestroy()) ); +} + +void AboutPlugin::realDestroy() +{ + if ((about != NULL) && about->isVisible() == false ) + { + delete about; + about = NULL; + } +#ifdef USE_KDE + if ((about_kde != NULL) && about_kde->isVisible() == false ) + { + delete about_kde; + about_kde = NULL; + } +#endif +} + diff --git a/plugins/about/about.h b/plugins/about/about.h new file mode 100644 index 0000000..ceb66f0 --- /dev/null +++ b/plugins/about/about.h @@ -0,0 +1,49 @@ +/*************************************************************************** + about.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _ABOUT_H +#define _ABOUT_H + +#include + +#include "event.h" +#include "plugins.h" + +class QWidget; + +class AboutPlugin : public QObject, public SIM::Plugin, public SIM::EventReceiver +{ + Q_OBJECT +public: + AboutPlugin(unsigned); + virtual ~AboutPlugin(); +protected slots: + void aboutDestroyed(); + void realDestroy(); +protected: + virtual bool processEvent(SIM::Event*); + unsigned long CmdBugReport; + unsigned long CmdAbout; + QWidget *about; +#ifdef USE_KDE + unsigned CmdAboutKDE; + QWidget *about_kde; +#endif +}; + +#endif + diff --git a/plugins/about/about.rc b/plugins/about/about.rc new file mode 100644 index 0000000..5da6a7d --- /dev/null +++ b/plugins/about/about.rc @@ -0,0 +1,97 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,9,6,0 + PRODUCTVERSION 0,9,6,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Vladimir Shutoff\0" + VALUE "FileDescription", "About plugin\0" + VALUE "FileVersion", "0, 9, 6, 0\0" + VALUE "InternalName", "about\0" + VALUE "LegalCopyright", "Copyright © 2002-2003\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "about.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "SIM\0" + VALUE "ProductVersion", "0, 9, 6, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/about/about.vcproj b/plugins/about/about.vcproj new file mode 100644 index 0000000..05a8524 --- /dev/null +++ b/plugins/about/about.vcproj @@ -0,0 +1,438 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/about/aboutdlg.cpp b/plugins/about/aboutdlg.cpp new file mode 100644 index 0000000..667da67 --- /dev/null +++ b/plugins/about/aboutdlg.cpp @@ -0,0 +1,152 @@ +/*************************************************************************** + aboutdlg.cpp - description + ------------------- + begin : Sun Mar 24 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "simapi.h" + +#ifndef USE_KDE + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "aboutdata.h" +#include "icons.h" +#include "misc.h" +#include "simgui/textshow.h" + +#include "aboutdlg.h" +#include "about.h" + +using namespace SIM; + +KAboutApplication::KAboutApplication( const KAboutData *aboutData, QWidget *parent, const char *name, bool modal) + : QDialog(parent) +{ + setupUi(this); + SET_WNDPROC("about"); + setButtonsPict(this); + setObjectName(name); + setModal(modal); + + connect(btnOK, SIGNAL(clicked()), this, SLOT(close())); + setWindowIcon(SIM::Icon("SIM")); + QIcon icon = SIM::Icon("SIM"); + lblIcon->setPixmap(SIM::Pict("SIM")); + edtVersion->setText(i18n("%1 Version: %2") .arg(aboutData->appName()) .arg(aboutData->version())); + edtVersion->setReadOnly(true); + txtAbout->setText((QString("

%1

%2

") + + "%4

" + + i18n("Bug report") + ": %6
" + + i18n("Note: This is an english mailing list") + + "
") + .arg(quote(aboutData->shortDescription())) + .arg(quote(aboutData->copyrightStatement())) + .arg(quote(aboutData->homepage())) + .arg(quote(aboutData->homepage())) + .arg(quote(aboutData->bugAddress())) + .arg(quote(aboutData->bugAddress()))); + QString txt; + KAboutPerson person; + foreach( person, aboutData->authors() ) + { + txt += addPerson(&person); + txt += "
"; + } + txtAuthors->setText(txt); + txt = QString::null; + QList translators = aboutData->translators(); + QList::iterator itt; + if (!translators.isEmpty()) + { + for (itt = translators.begin(); itt != translators.end(); ++itt) + { + const KAboutTranslator &t = *itt; + txt += QString("
%1
<%3>") + .arg(quote(t.name())) + .arg(quote(t.emailAddress())) + .arg(quote(t.emailAddress())); + txt += "
"; + } + txtTranslations->setText(txt); + } + else + { + tabMain->removeTab(tabMain->indexOf(tabTranslation)); + } + QString license = aboutData->license(); + license += "\n\n"; + QFile f(SIM::app_file("COPYING")); + if (f.open(QIODevice::ReadOnly)) + { + for (;;) + { + QString s = QString(f.readLine(512)); + if(s.isEmpty() || s.isNull()) + break; + license += s; + } + } + txtLicence->setText(quote(license)); + this->setFixedSize(this->width()+50,this->height()); +} + +KAboutApplication::~KAboutApplication() +{ +} + +void KAboutApplication::closeEvent(QCloseEvent *e) +{ + QDialog::closeEvent(e); + emit finished(); +} + +QString KAboutApplication::addPerson(const KAboutPerson *p) +{ + QString res; + if (!p->task().isEmpty()){ + res += quote(p->task()); + res += ":
"; + } + res += QString("%1 <%3>
") + .arg(quote(p->name())) + .arg(quote(p->emailAddress())) + .arg(quote(p->emailAddress())); + if (!p->webAddress().isEmpty()) + res += QString("%2
") + .arg(quote(p->webAddress())) + .arg(quote(p->webAddress())); + return res; +} + +QString KAboutApplication::quote(const QString &s) +{ + QString res = s; + res.replace('&', "&"); + res.replace('\"', """); + res.replace('<', "<"); + res.replace('>', ">"); + res.replace('\n', "
"); + return res; +} + +#endif + diff --git a/plugins/about/aboutdlg.h b/plugins/about/aboutdlg.h new file mode 100644 index 0000000..3bfd97e --- /dev/null +++ b/plugins/about/aboutdlg.h @@ -0,0 +1,47 @@ +/*************************************************************************** + aboutdlg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _ABOUTDLG_H +#define _ABOUTDLG_H + +#include "simapi.h" +#include + +#ifndef USE_KDE + +#include "ui_aboutdlgbase.h" + +class KAboutData; +class KAboutPerson; + +class KAboutApplication : public QDialog, public Ui::AboutDlgBase +{ + Q_OBJECT +public: + KAboutApplication(const KAboutData *aboutData, QWidget *parent=0, const char *name=0, bool modal=true); + ~KAboutApplication(); +signals: + void finished(); +protected: + void closeEvent(QCloseEvent*); + QString addPerson(const KAboutPerson*); + QString quote(const QString &s); +}; + +#endif +#endif + diff --git a/plugins/about/aboutdlgbase.ui b/plugins/about/aboutdlgbase.ui new file mode 100644 index 0000000..8327799 --- /dev/null +++ b/plugins/about/aboutdlgbase.ui @@ -0,0 +1,194 @@ + + + AboutDlgBase + + + + 0 + 0 + 420 + 300 + + + + + 0 + 0 + + + + About Sim-IM + + + + 11 + + + + + + About + + + + 11 + + + + + + + + + Authors + + + + 11 + + + + + + 0 + 0 + + + + + + + + + Translation + + + + 11 + + + + + + + + + License + + + + 11 + + + + + + + + + + + + QFrame::HLine + + + QFrame::Sunken + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + &Close + + + + + + + + + + + + Qt::AlignCenter + + + false + + + + + + + + + + + + 255 + 255 + 255 + + + + + + + + + 255 + 255 + 255 + + + + + + + + + 212 + 208 + 200 + + + + + + + + false + + + + + + + + TextShow + QWidget +
simgui/textshow.h
+
+
+ + +
diff --git a/plugins/action/CMakeLists.txt b/plugins/action/CMakeLists.txt new file mode 100644 index 0000000..f854cc6 --- /dev/null +++ b/plugins/action/CMakeLists.txt @@ -0,0 +1,29 @@ +################## +# action library # +################## +IF(BUILD_DROPPED) +SET(action_SRCS + action.cpp + actioncfg.cpp + additem.cpp + menucfg.cpp +) + +SET(action_HDRS + action.h + actioncfg.h + additem.h + menucfg.h +) + +SET(action_UICS + actioncfgbase.ui + additembase.ui + menucfgbase.ui +) + +REMOVE_DEFINITIONS(-DQT3_SUPPORT) +REMOVE_DEFINITIONS(-DQT_3SUPPORT_LIB) +REMOVE_DEFINITIONS(-DQT3_SUPPORT_WARNINGS) +SIM_ADD_PLUGIN(action) +ENDIF(BUILD_DROPPED) diff --git a/plugins/action/action.cpp b/plugins/action/action.cpp new file mode 100644 index 0000000..9802d11 --- /dev/null +++ b/plugins/action/action.cpp @@ -0,0 +1,306 @@ +/*************************************************************************** + action.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include + +#include "log.h" +#include "unquot.h" +#include "core.h" + +#include "contacts/contact.h" + +#include "action.h" +#include "actioncfg.h" + +using namespace std; +using namespace SIM; + +Plugin *createActionPlugin(unsigned base, bool, Buffer*) +{ + Plugin *plugin = new ActionPlugin(base); + return plugin; +} + +static PluginInfo info = + { + I18N_NOOP("Action"), + I18N_NOOP("Plugin execute external programs on event or from contact menu"), + VERSION, + createActionPlugin, + PLUGIN_NOLOAD_DEFAULT + }; + +EXPORT_PROC PluginInfo* GetPluginInfo() +{ + return &info; +} + +static DataDef actionUserData[] = + { + { "OnLine", DATA_UTF, 1, 0 }, + { "Status", DATA_UTF, 1, 0 }, + { "Message", DATA_UTFLIST, 1, 0 }, + { "Menu", DATA_UTFLIST, 1, 0 }, + { "NMenu", DATA_ULONG, 1, 0 }, + { NULL, DATA_UNKNOWN, 0, 0 } + }; + +static ActionPlugin *plugin = NULL; + +static QWidget *getActionSetup(QWidget *parent, PropertyHubPtr data) +{ + return new ActionConfig(parent, data, plugin); +} + +ActionPlugin::ActionPlugin(unsigned base) + : Plugin(base), EventReceiver(HighPriority) +{ + plugin = this; + + //action_data_id = getContacts()->registerUserData(info.title, actionUserData); + CmdAction = registerType(); + + Command cmd; + cmd->id = action_data_id; + cmd->text = I18N_NOOP("&Action"); + cmd->icon = "run"; + cmd->param = (void*)getActionSetup; + EventAddPreferences(cmd).process(); + + cmd->id = CmdAction; + cmd->text = "_"; + cmd->icon = QString::null; + cmd->flags = COMMAND_CHECK_STATE; + cmd->menu_id = MenuContact; + cmd->menu_grp = 0xC000; + cmd->param = NULL; + EventCommandCreate(cmd).process(); +} + +ActionPlugin::~ActionPlugin() +{ + EventCommandRemove(CmdAction).process(); + EventRemovePreferences(action_data_id).process(); + getContacts()->unregisterUserData(action_data_id); +} + +QWidget *ActionPlugin::createConfigWindow(QWidget *parent) +{ + SIM::PropertyHubPtr data = getContacts()->getUserData("action"); + return new ActionConfig(parent, data, this); +} + +class MsgProcess : public QProcess +{ +protected: + Message *m_msg; +public: + MsgProcess(Message *msg, QObject *parent = 0) + : QProcess(parent), m_msg(msg) + {} + Message *msg() const { return m_msg; } +}; + +bool ActionPlugin::processEvent(Event *e) +{ + switch (e->type() ) { + case eEventCheckCommandState: { + EventCheckCommandState *ecs = static_cast(e); + CommandDef *cmd = ecs->cmd(); + if ((cmd->id == CmdAction) && (cmd->menu_id == MenuContact)){ + Contact *contact = getContacts()->contact((unsigned long)(cmd->param)); + if (contact == NULL) + return false; + PropertyHubPtr data = contact->getUserData("action"); + if (!data || data->value("NMenu").toInt() == 0) + return false; + CommandDef *cmds = new CommandDef[data->value("NMenu").toInt() + 1]; + unsigned n = 0; + for (int i = 0; i < data->value("NMenu").toInt(); i++){ + QString str = data->stringMapValue("Menu", i +1); + QString item = getToken(str, ';'); + int pos = item.indexOf("&IP;"); + if (pos >= 0) + { + EventGetContactIP e(contact); + if (!e.process()) + continue; + } + pos = item.indexOf("&Mail;"); + if (pos >= 0) + { + if (contact->getEMails().isEmpty()) + continue; + } + pos = item.indexOf("&Phone;"); + if (pos >= 0) + { + if (contact->getPhones().isEmpty()) + continue; + } + cmds[n].id = CmdAction + i; + cmds[n].text = "_"; + cmds[n].text_wrk = item; + n++; + } + if (n == 0) + { + delete[] cmds; + return false; + } + cmd->param = cmds; + cmd->flags |= COMMAND_RECURSIVE; + return true; + } + break; + } + case eEventCommandExec: { + EventCommandExec *ece = static_cast(e); + CommandDef *cmd = ece->cmd(); + if ((cmd->menu_id == MenuContact) && (cmd->id >= CmdAction)){ + unsigned n = cmd->id - CmdAction; + Contact *contact = getContacts()->contact((unsigned long)(cmd->param)); + PropertyHubPtr data = contact->getUserData("action"); + if (!contact || !data || n >= data->value("NMenu").toLongLong()) + return false; + + QString str = data->stringMapValue("Menu", n +1); + getToken(str, ';'); + EventTemplate::TemplateExpand t; + t.tmpl = str; + t.contact = contact; + t.receiver = this; + t.param = NULL; + EventTemplateExpand(&t).process(); + return true; + } + break; + } + case eEventContact: { + EventContact *ec = static_cast(e); + if(ec->action() != EventContact::eOnline) + break; + Contact *contact = ec->contact(); + if (contact == NULL) + return false; + PropertyHubPtr data = contact->getUserData("action"); + if (!data || data->value("OnLine").toString().isEmpty()) + return false; + EventTemplate::TemplateExpand t; + t.tmpl = data->value("OnLine").toString(); + t.contact = contact; + t.receiver = this; + t.param = NULL; + EventTemplateExpand(&t).process(); + return true; + } + case eEventMessageReceived: { + EventMessage *em = static_cast(e); + Message *msg = em->msg(); + Contact *contact = getContacts()->contact(msg->contact()); + if (contact == NULL) + return false; + PropertyHubPtr data = contact->getUserData("action"); + if (!data) + return false; + if (msg->type() == MessageStatus){ + if (data->value("Status").toString().isEmpty()) + return false; + EventTemplate::TemplateExpand t; + t.tmpl = data->value("Status").toString(); + t.contact = contact; + t.receiver = this; + t.param = NULL; + EventTemplateExpand(&t).process(); + return false; + } + QString cmd = data->stringMapValue("Message",msg->baseType()); + if (cmd.isEmpty()) + return false; + EventTemplate::TemplateExpand t; + t.tmpl = cmd; + t.contact = contact; + t.receiver = this; + t.param = msg; + EventTemplateExpand(&t).process(); + return true; + } + case eEventTemplateExpanded: { + EventTemplate *et = static_cast(e); + EventTemplate::TemplateExpand *t = et->templateExpand(); + Message *msg = (Message*)(t->param); + QProcess *proc; + if (msg){ + QString text = t->tmpl + unquoteText(msg->presentation()); + proc = new MsgProcess(msg, this); + connect(proc, SIGNAL(finished(int, QProcess::ExitStatus)), + this, SLOT(msg_ready(int, QProcess::ExitStatus))); + proc->start(text); + }else{ + proc = new QProcess(this); + connect(proc, SIGNAL(finished(int, QProcess::ExitStatus)), + this, SLOT(ready(int, QProcess::ExitStatus))); + proc->start(t->tmpl); + } + break; + } + default: + break; + } + return false; +} + +void ActionPlugin::ready(int exitCode, QProcess::ExitStatus exitStatus) +{ + // if this does not work as expected we've to remember the pid + QProcess ptr in a map + // using a list is not the correct way to go! + QProcess *p = qobject_cast(sender()); + if(!p) + return; + if (exitStatus != QProcess::NormalExit || exitCode != 0) + log(L_WARN, "QProcess fail: %u, %u", exitStatus, exitCode); + p->deleteLater(); +} + +void ActionPlugin::msg_ready(int exitCode, QProcess::ExitStatus exitStatus) +{ + // if this does not work as expected we've to remember the pid + QProcess ptr in a map + // using a list is not the correct way to go! + QProcess *p = qobject_cast(sender()); + if(!p) + return; + Message *msg = static_cast(p)->msg(); + if (exitStatus != QProcess::NormalExit || exitCode != 0) { + EventMessageReceived e(msg); + if (!e.process(this)) + delete msg; + }else{ + QByteArray bOut = p->readAllStandardOutput(); + if (!bOut.isEmpty()){ + msg->setFlags(msg->getFlags() & ~MESSAGE_RICHTEXT); + msg->setText(QString::fromLocal8Bit(bOut)); + EventMessageReceived e(msg); + if (!e.process(this)) + delete msg; + }else{ + delete msg; + } + } + p->deleteLater(); +} diff --git a/plugins/action/action.h b/plugins/action/action.h new file mode 100644 index 0000000..65a487f --- /dev/null +++ b/plugins/action/action.h @@ -0,0 +1,57 @@ +/*************************************************************************** + action.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _ACTION_H +#define _ACTION_H + +#include +#include +#include + +#include "cfg.h" +#include "event.h" +#include "plugins.h" + +class QProcess; + +struct ActionUserData +{ + SIM::Data OnLine; + SIM::Data Status; + SIM::Data Message; + SIM::Data Menu; + SIM::Data NMenu; +}; + +class ActionPlugin : public QObject, public SIM::Plugin, public SIM::EventReceiver +{ + Q_OBJECT +public: + ActionPlugin(unsigned); + virtual ~ActionPlugin(); + unsigned long action_data_id; +protected slots: + void ready(int, QProcess::ExitStatus); + void msg_ready(int, QProcess::ExitStatus); +protected: + unsigned long CmdAction; + virtual bool processEvent(SIM::Event*); + QWidget *createConfigWindow(QWidget *parent); +}; + +#endif + diff --git a/plugins/action/action.rc b/plugins/action/action.rc new file mode 100644 index 0000000..3842ee7 --- /dev/null +++ b/plugins/action/action.rc @@ -0,0 +1,97 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,9,6,0 + PRODUCTVERSION 0,9,6,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Vladimir Shutoff\0" + VALUE "FileDescription", "Action plugin\0" + VALUE "FileVersion", "0, 9, 6, 0\0" + VALUE "InternalName", "action\0" + VALUE "LegalCopyright", "Copyright © 2002-2003\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "action.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "SIM\0" + VALUE "ProductVersion", "0, 9, 6, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/action/action.vcproj b/plugins/action/action.vcproj new file mode 100644 index 0000000..f7edccc --- /dev/null +++ b/plugins/action/action.vcproj @@ -0,0 +1,592 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/action/actioncfg.cpp b/plugins/action/actioncfg.cpp new file mode 100644 index 0000000..cdfb9c6 --- /dev/null +++ b/plugins/action/actioncfg.cpp @@ -0,0 +1,160 @@ +/*************************************************************************** + actioncfg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "icons.h" +#include "actioncfg.h" +#include "menucfg.h" +#include "action.h" +#include "core.h" +#include "simgui/ballonmsg.h" +#include "simgui/editfile.h" + +#include +#include +#include + +using namespace SIM; + +unsigned CONTACT_ONLINE = 0x10000; +unsigned CONTACT_STATUS = 0x10001; + +static void addRow(QTableWidget *lstEvent, int row, const QIcon &icon, const QString &text, + unsigned int id, const QString &program) +{ + QTableWidgetItem *item; + lstEvent->setRowCount(row+1); + + item = new QTableWidgetItem(icon, text); + item->setData(Qt::UserRole, id); + item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled); + lstEvent->setItem(row, 0, item); + + item = new QTableWidgetItem(program); + item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled|Qt::ItemIsEditable); + lstEvent->setItem(row, 1, item); +} + +ActionConfig::ActionConfig(QWidget *parent, SIM::PropertyHubPtr data, ActionPlugin *plugin) + : QWidget(parent) + , m_menu(NULL) + , m_data(data) + , m_plugin(plugin) +{ + setupUi(this); + setButtonsPict(this); + + connect(btnHelp, SIGNAL(clicked()), this, SLOT(help())); + + int row = 0; + addRow(lstEvent, row, Icon("SIM"), i18n("Contact online"), CONTACT_ONLINE, data->value("OnLine").toString() ); + + row++; + addRow(lstEvent, row, Icon("SIM"), i18n("Status changed"), CONTACT_STATUS, data->value("Status").toString() ); + + CommandDef *cmd; + CorePlugin *core = GET_CorePlugin(); + CommandsMapIterator it(core->messageTypes); + while ((cmd = ++it) != NULL){ + MessageDef *def = (MessageDef*)(cmd->param); + if ((def == NULL) || (cmd->icon.isEmpty()) || + (def->flags & (MESSAGE_HIDDEN | MESSAGE_SENDONLY | MESSAGE_CHILD))) + continue; + if ((def->singular == NULL) || (def->plural == NULL) || + (*def->singular == 0) || (*def->plural == 0)) + continue; + QString type = i18n(def->singular, def->plural, 1); + int pos = type.indexOf("1 "); + if (pos == 0){ + type = type.mid(2); + }else if (pos > 0){ + type = type.left(pos); + } + type = type.left(1).toUpper() + type.mid(1); + + row++; + addRow(lstEvent, row, Icon(cmd->icon), type, cmd->id, data->stringMapValue("Message", cmd->id)); + } + EventTmplHelpList e; + e.process(); + LineEditDelegate *dg = new LineEditDelegate(1, lstEvent); + dg->setHelpList(e.helpList()); + lstEvent->setItemDelegate(dg); + lstEvent->resizeColumnToContents(0); + lstEvent->sortByColumn(0, Qt::AscendingOrder); + + for (QObject *p = parent; p != NULL; p = p->parent()){ + QTabWidget *tab = qobject_cast(p); + if (!tab) + continue; + m_menu = new MenuConfig(tab, data); + tab->addTab(m_menu, i18n("Menu")); + tab->adjustSize(); + break; + } +} + +ActionConfig::~ActionConfig() +{ +} + +void ActionConfig::apply() +{ + PropertyHubPtr data = getContacts()->getUserData("action"); + apply(data); +} + +void ActionConfig::apply(PropertyHubPtr data) +{ + //ActionUserData *data = (ActionUserData*)_data; + if (m_menu) + m_menu->apply(data); + + for (int row = 0; row < lstEvent->rowCount(); ++row) + { + unsigned id = lstEvent->item(row, 0)->data(Qt::UserRole).toUInt(); + const QString text = lstEvent->item(row, 1)->data(Qt::EditRole).toString(); + + if (id == CONTACT_ONLINE) + data->setValue("OnLine", text); + else if (id == CONTACT_STATUS) + data->setValue("Status", text); + else + data->setStringMapValue("Message",id, text); + } +} + +void ActionConfig::setEnabled(bool state) +{ + if (m_menu) + m_menu->setEnabled(state); + QWidget::setEnabled(state); +} + +void ActionConfig::help() +{ + QString helpString = i18n("In command line you can use:") + "\n"; + EventTmplHelp e(helpString); + e.process(); + helpString = e.help(); + helpString += "\n\n"; + helpString += i18n("For message events message text will be sent on standard input of the program.\n" + "If the program will return a zero error code message text will be replaced with program output.\n" + "If program output is empty, message will be destroyed.\n" + "Thus it is possible to organize additional messages filters.\n"); + BalloonMsg::message(helpString, btnHelp, false, 400); +} + diff --git a/plugins/action/actioncfg.h b/plugins/action/actioncfg.h new file mode 100644 index 0000000..333e7af --- /dev/null +++ b/plugins/action/actioncfg.h @@ -0,0 +1,48 @@ +/*************************************************************************** + actioncfg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _ACTIONCFG_H +#define _ACTIONCFG_H + +#include "ui_actioncfgbase.h" +#include "propertyhub.h" + +using namespace SIM; + +struct ActionUserData; +class ActionPlugin; +class MenuConfig; + +class ActionConfig : public QWidget, public Ui::ActionConfigBase +{ + Q_OBJECT +public: + ActionConfig(QWidget *parent, SIM::PropertyHubPtr data, ActionPlugin *plugin); + virtual ~ActionConfig(); +public slots: + void apply(); + void apply(PropertyHubPtr); + void help(); +protected: + MenuConfig *m_menu; + void setEnabled (bool); + SIM::PropertyHubPtr m_data; + ActionPlugin *m_plugin; +}; + +#endif + diff --git a/plugins/action/actioncfgbase.ui b/plugins/action/actioncfgbase.ui new file mode 100644 index 0000000..592f737 --- /dev/null +++ b/plugins/action/actioncfgbase.ui @@ -0,0 +1,97 @@ + + + ActionConfigBase + + + + 0 + 0 + 370 + 220 + + + + Form1 + + + + 11 + + + 6 + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + &Help + + + 4144 + + + + + + + true + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + false + + + true + + + false + + + true + + + false + + + 25 + + + 25 + + + + Event + + + + + Program + + + + + + + + + diff --git a/plugins/action/additem.cpp b/plugins/action/additem.cpp new file mode 100644 index 0000000..be3408b --- /dev/null +++ b/plugins/action/additem.cpp @@ -0,0 +1,64 @@ +/*************************************************************************** + additem.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "icons.h" +#include "additem.h" +#include "core.h" +#include "core_events.h" + +#include "simgui/ballonmsg.h" +#include "simgui/editfile.h" + +#include +#include +#include + +using namespace SIM; + +AddItem::AddItem(QWidget *parent) + : QDialog(parent) +{ + setupUi(this); + setModal(true); + setWindowIcon(Icon("run")); + setButtonsPict(this); + QTimer::singleShot(0, this, SLOT(changed())); + connect(edtItem, SIGNAL(textChanged(const QString&)), this, SLOT(changed(const QString&))); + connect(edtPrg, SIGNAL(textChanged(const QString&)), this, SLOT(changed(const QString&))); + connect(buttonHelp, SIGNAL(clicked()), this, SLOT(help())); + EventTmplHelpList e; + e.process(); + edtPrg->setHelpList(e.helpList()); +} + +void AddItem::changed() +{ + buttonOk->setEnabled(!edtItem->text().isEmpty() && !edtPrg->text().isEmpty()); +} + +void AddItem::changed(const QString&) +{ + changed(); +} + +void AddItem::help() +{ + QString helpString = i18n("In command line you can use:") + "\n"; + EventTmplHelp e(helpString); + e.process(); + BalloonMsg::message(e.help(), buttonHelp, false, 400); +} diff --git a/plugins/action/additem.h b/plugins/action/additem.h new file mode 100644 index 0000000..9d54ddd --- /dev/null +++ b/plugins/action/additem.h @@ -0,0 +1,35 @@ +/*************************************************************************** + additem.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _ADDITEM_H +#define _ADDITEM_H + +#include "ui_additembase.h" + +class AddItem : public QDialog, public Ui::AddItemBase +{ + Q_OBJECT +public: + AddItem(QWidget *parent); +public slots: + void changed(); + void changed(const QString&); + void help(); +}; + +#endif + diff --git a/plugins/action/additembase.ui b/plugins/action/additembase.ui new file mode 100644 index 0000000..640e0d0 --- /dev/null +++ b/plugins/action/additembase.ui @@ -0,0 +1,171 @@ + + + AddItemBase + + + + 0 + 0 + 387 + 170 + + + + Add Item + + + true + + + + 6 + + + 11 + + + + + Item: + + + false + + + + + + + + + + Program: + + + false + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + 6 + + + 0 + + + + + &Help + + + true + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + &OK + + + true + + + true + + + + + + + &Cancel + + + true + + + + + + + + + + LineEdit + QWidget +
simgui/editfile.h
+
+
+ + + + buttonOk + clicked() + AddItemBase + accept() + + + 20 + 20 + + + 20 + 20 + + + + + buttonCancel + clicked() + AddItemBase + reject() + + + 20 + 20 + + + 20 + 20 + + + + +
diff --git a/plugins/action/menucfg.cpp b/plugins/action/menucfg.cpp new file mode 100644 index 0000000..a17fa2a --- /dev/null +++ b/plugins/action/menucfg.cpp @@ -0,0 +1,116 @@ +/*************************************************************************** + menucfg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + + +#include "misc.h" +#include "menucfg.h" +#include "action.h" +#include "additem.h" + +#include "simgui/editfile.h" + +#include + +using namespace SIM; + +MenuConfig::MenuConfig(QWidget *parent, PropertyHubPtr data) + : QWidget(parent) + , m_data(data) +{ + setupUi(this); + + connect(lstMenu, SIGNAL(itemSelectionChanged()), this, SLOT(itemSelectionChanged())); + connect(btnAdd, SIGNAL(clicked()), this, SLOT(add())); + connect(btnEdit, SIGNAL(clicked()), this, SLOT(edit())); + connect(btnRemove, SIGNAL(clicked()), this, SLOT(remove())); + + for (int row = 0; row < m_data->value("NMenu").toInt(); row++){ + lstMenu->setRowCount(row+1); + + const QStringList sl = data->stringMapValue("Menu", row +1).split(';'); + if(sl.count() != 2) + continue; + + QTableWidgetItem *item = new QTableWidgetItem(sl[0]); + lstMenu->setItem(row, 0, item); + + item = new QTableWidgetItem(sl[1]); + lstMenu->setItem(row, 1, item); + } + itemSelectionChanged(); +} + +MenuConfig::~MenuConfig() +{ +} + +void MenuConfig::itemSelectionChanged() +{ + const bool rowSelected = (lstMenu->selectedItems().count() == 2); + btnEdit->setEnabled(rowSelected); + btnRemove->setEnabled(rowSelected); +} + +void MenuConfig::add() +{ + AddItem add(topLevelWidget()); + if (add.exec()){ + const int row = lstMenu->rowCount(); + lstMenu->setRowCount(row+1); + + QTableWidgetItem *item = new QTableWidgetItem(add.edtItem->text()); + lstMenu->setItem(row, 0, item); + + item = new QTableWidgetItem(add.edtPrg->text()); + lstMenu->setItem(row, 1, item); + + lstMenu->resizeColumnToContents(0); + } +} + +void MenuConfig::edit() +{ + const int row = lstMenu->currentRow(); + if (row < 0) + return; + AddItem add(topLevelWidget()); + add.edtItem->setText(lstMenu->item(row, 0)->text()); + add.edtPrg->setText(lstMenu->item(row, 1)->text()); + if (add.exec()){ + lstMenu->item(row, 0)->setText(add.edtItem->text()); + lstMenu->item(row, 1)->setText(add.edtPrg->text()); + lstMenu->resizeColumnToContents(0); + } +} + +void MenuConfig::remove() +{ + lstMenu->removeRow(lstMenu->currentRow()); +} + +void MenuConfig::apply(PropertyHubPtr data) +{ + //ActionUserData *data = (ActionUserData*)_data; + data->clearStringMap("Menu"); + data->setValue("NMenu", 0); + for (int row = 0; row < lstMenu->rowCount(); ++row){ + QString s = lstMenu->item(row, 0)->text() + ";" + lstMenu->item(row, 1)->text(); + data->setValue("NMenu", data->value("NMenu").toUInt() + 1); + data->setStringMapValue("Menu", data->value("NMenu").toUInt(), s); + } +} + diff --git a/plugins/action/menucfg.h b/plugins/action/menucfg.h new file mode 100644 index 0000000..0e1cb50 --- /dev/null +++ b/plugins/action/menucfg.h @@ -0,0 +1,44 @@ +/*************************************************************************** + menucfg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _MENUCFG_H +#define _MENUCFG_H + +#include "ui_menucfgbase.h" +#include "propertyhub.h" + +using namespace SIM; +struct ActionUserData; //RemoveMe? + +class MenuConfig : public QWidget, public Ui::MenuConfigBase +{ + Q_OBJECT +public: + MenuConfig(QWidget *parent, PropertyHubPtr data); + virtual ~MenuConfig(); +public Q_SLOTS: + void apply(PropertyHubPtr); + void itemSelectionChanged(); + void add(); + void edit(); + void remove(); +protected: + PropertyHubPtr m_data; +}; + +#endif + diff --git a/plugins/action/menucfgbase.ui b/plugins/action/menucfgbase.ui new file mode 100644 index 0000000..534ee29 --- /dev/null +++ b/plugins/action/menucfgbase.ui @@ -0,0 +1,109 @@ + + + MenuConfigBase + + + + 0 + 0 + 338 + 219 + + + + Form1 + + + + 6 + + + 11 + + + + + QAbstractItemView::SelectRows + + + false + + + false + + + true + + + false + + + false + + + true + + + + Item + + + + + Program + + + + + + + + 6 + + + 0 + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + &Add + + + + + + + &Edit + + + + + + + &Delete + + + + + + + + + + diff --git a/plugins/action/resource.h b/plugins/action/resource.h new file mode 100644 index 0000000..6a6e650 --- /dev/null +++ b/plugins/action/resource.h @@ -0,0 +1,18 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by action.rc +// +#define LANG_NEUTRAL 0 +#define SUBLANG_NEUTRAL 0 +#define IDI_ICON1 1 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 103 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/autoaway/CMakeLists.txt b/plugins/autoaway/CMakeLists.txt new file mode 100644 index 0000000..f30e6a3 --- /dev/null +++ b/plugins/autoaway/CMakeLists.txt @@ -0,0 +1,70 @@ +IF(BUILD_DROPPED) +IF(NOT WIN32 AND NOT APPLE) + INCLUDE(CheckFunctionExists) + INCLUDE(FindX11) + INCLUDE(CheckLibraryExists) + #SET(CMAKE_REQUIRED_LIBRARIES "X11 Xext m") + CHECK_LIBRARY_EXISTS("Xext" "XScreenSaverRegister" "${X11_LIBRARY_DIR}" XSS_IN_XEXT) + IF(XSS_IN_XEXT) + SET(XSS_LIB "Xext") + ELSE(XSS_IN_XEXT) + CHECK_LIBRARY_EXISTS("Xss" "XScreenSaverRegister" "${X11_LIBRARY_DIR}" XSS_IN_XSS) + IF(XSS_IN_XSS) + SET(XSS_LIB "Xss") + ENDIF(XSS_IN_XSS) + ENDIF(XSS_IN_XEXT) + IF(XSS_LIB) + CHECK_INCLUDE_FILES("X11/extensions/scrnsaver.h" HAVE_X11_EXTENSIONS_SCRNSAVER) + ENDIF(XSS_LIB) + IF(HAVE_X11_EXTENSIONS_SCRNSAVER) + SET(COMPILE_PLUGIN TRUE) + ELSE(HAVE_X11_EXTENSIONS_SCRNSAVER) + IF( X11_Xscreensaver_FOUND ) + SET(COMPILE_PLUGIN TRUE) + ENDIF( X11_Xscreensaver_FOUND ) + ENDIF(HAVE_X11_EXTENSIONS_SCRNSAVER) +ELSE(NOT WIN32 AND NOT APPLE) + SET(COMPILE_PLUGIN TRUE) +ENDIF(NOT WIN32 AND NOT APPLE) + +IF(COMPILE_PLUGIN) + #################### + # autoaway library # + #################### + SET(autoaway_SRCS + autoaway.cpp + autoawaycfg.cpp + ) + + SET(autoaway_HDRS + autoaway.h + autoawaycfg.h + ) + + SET(autoaway_UICS + autoawaycfgbase.ui + ) + + SET(autoaway_LIBS + _core + ) + + IF(WIN32) + SET(autoaway_SRCS + ${autoaway_SRCS} + idleui.cpp + ) + SET(autoaway_HDRS + ${autoaway_HDRS} + idleui.h + ) + ENDIF(WIN32) + + LINK_DIRECTORIES(${X11_LIBRARY_DIR}) + INCLUDE_DIRECTORIES(${X11_INCLUDE_DIR}) + SIM_ADD_PLUGIN(autoaway) + TARGET_LINK_LIBRARIES(autoaway ${XSS_LIB}) +ELSE(COMPILE_PLUGIN) + MESSAGE(STATUS "XScreenSaver library not found, autoaway plugin disabled") +ENDIF(COMPILE_PLUGIN) +ENDIF(BUILD_DROPPED) diff --git a/plugins/autoaway/autoaway.cpp b/plugins/autoaway/autoaway.cpp new file mode 100644 index 0000000..c759969 --- /dev/null +++ b/plugins/autoaway/autoaway.cpp @@ -0,0 +1,390 @@ +/*************************************************************************** + autoaway.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + *************************************************************************** + +Detect idle time for MAC: +Copyright (C) 2003 Tarkvara Design Inc. + +*/ + +// This is required to use Xlibint (which isn't very clean itself) +#define QT_CLEAN_NAMESPACE + +#include "simapi.h" + +#include "log.h" +#include "autoaway.h" +#include "autoawaycfg.h" +#include "core.h" + +#include "contacts/client.h" + +#ifdef WIN32 +#define _WIN32_WINNT 0x0500 +#include + +#include + +#include "idleui.h" + +static BOOL (WINAPI * _GetLastInputInfo)(PLASTINPUTINFO); + +#elif defined(HAVE_CARBON_CARBON_H) && !defined(HAVE_X) +#include +#elif defined(__OS2__) +#define INCL_WIN +#include +#include "sysglit.h" +#else +#include +#include +#include +#include +#include +#endif + +#include +#include +#include +#include + +using namespace SIM; + +const unsigned AUTOAWAY_TIME = 10000; + +Plugin *createAutoAwayPlugin(unsigned base, bool, Buffer *config) +{ + Plugin *plugin = new AutoAwayPlugin(base, config); + return plugin; +} + +static PluginInfo info = + { + I18N_NOOP("AutoAway"), + I18N_NOOP("Plugin provides set away and N/A status after some idle time"), + VERSION, + createAutoAwayPlugin, + PLUGIN_DEFAULT + }; + +EXPORT_PROC PluginInfo* GetPluginInfo() +{ + return &info; +} + +#if defined(HAVE_CARBON_CARBON_H) && !defined(HAVE_X) + +static unsigned mSecondsIdle = 0; +static EventLoopTimerRef mTimerRef; + +static OSStatus LoadFrameworkBundle(CFStringRef framework, CFBundleRef *bundlePtr) { + OSStatus err; + FSRef frameworksFolderRef; + CFURLRef baseURL; + CFURLRef bundleURL; + + if ( bundlePtr == nil ) return( -1 ); + + *bundlePtr = nil; + + baseURL = nil; + bundleURL = nil; + + err = FSFindFolder(kOnAppropriateDisk, kFrameworksFolderType, true, &frameworksFolderRef); + if (err == noErr) { + baseURL = CFURLCreateFromFSRef(kCFAllocatorSystemDefault, &frameworksFolderRef); + if (baseURL == nil) { + err = coreFoundationUnknownErr; + } + } + if (err == noErr) { + bundleURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault, baseURL, framework, false); + if (bundleURL == nil) { + err = coreFoundationUnknownErr; + } + } + if (err == noErr) { + *bundlePtr = CFBundleCreate(kCFAllocatorSystemDefault, bundleURL); + if (*bundlePtr == nil) { + err = coreFoundationUnknownErr; + } + } + if (err == noErr) { + if ( ! CFBundleLoadExecutable( *bundlePtr ) ) { + err = coreFoundationUnknownErr; + } + } + + // Clean up. + if (err != noErr && *bundlePtr != nil) { + CFRelease(*bundlePtr); + *bundlePtr = nil; + } + if (bundleURL != nil) { + CFRelease(bundleURL); + } + if (baseURL != nil) { + CFRelease(baseURL); + } + return err; +} + +pascal void IdleTimerAction(EventLoopTimerRef, EventLoopIdleTimerMessage inState, void* inUserData) +{ + switch (inState) { + case kEventLoopIdleTimerStarted: + case kEventLoopIdleTimerStopped: + // Get invoked with this constant at the start of the idle period, + // or whenever user activity cancels the idle. + mSecondsIdle = 0; + break; + case kEventLoopIdleTimerIdling: + // Called every time the timer fires (i.e. every second). + mSecondsIdle++; + break; + } +} + +typedef OSStatus (*InstallEventLoopIdleTimerPtr)(EventLoopRef inEventLoop, + EventTimerInterval inFireDelay, + EventTimerInterval inInterval, + EventLoopIdleTimerUPP inTimerProc, + void * inTimerData, + EventLoopTimerRef * outTimer); + +#endif + +static DataDef autoAwayData[] = + { + { "AwayTime", DATA_ULONG, 1, DATA(3) }, + { "EnableAway", DATA_BOOL, 1, DATA(1) }, + { "NATime", DATA_ULONG, 1, DATA(10)}, + { "EnableNA", DATA_BOOL, 1, DATA(1) }, + { "OffTime", DATA_ULONG, 1, DATA(10)}, + { "EnableOff", DATA_BOOL, 1, 0 }, + { "DisableAlert", DATA_BOOL, 1, DATA(1) }, + { "RealManualStatus", DATA_ULONG, 1, DATA(STATUS_UNKNOWN) }, + { NULL, DATA_UNKNOWN, 0, 0 } + }; + +AutoAwayPlugin::AutoAwayPlugin(unsigned base, Buffer *config) + : Plugin(base), EventReceiver(HighPriority) +{ + load_data(autoAwayData, &data, config); +#ifdef WIN32 + (DWORD&)_GetLastInputInfo = (DWORD)QLibrary::resolve("user32.dll", "GetLastInputInfo"); +#elif defined(HAVE_CARBON_CARBON_H) && !defined(HAVE_X) +/* ToDo: + CFBundleRef carbonBundle; + if (LoadFrameworkBundle( CFSTR("Carbon.framework"), &carbonBundle ) == noErr) { + InstallEventLoopIdleTimerPtr myInstallEventLoopIdleTimer = (InstallEventLoopIdleTimerPtr)CFBundleGetFunctionPointerForName(carbonBundle, CFSTR("InstallEventLoopIdleTimer")); + if (myInstallEventLoopIdleTimer){ + EventLoopIdleTimerUPP timerUPP = NewEventLoopIdleTimerUPP(Private::IdleTimerAction); + (*myInstallEventLoopIdleTimer)(GetMainEventLoop(), kEventDurationSecond, kEventDurationSecond, timerUPP, 0, &mTimerRef); + } + } +*/ +#endif + bAway = false; + bNA = false; + bOff = false; + m_timer = new QTimer(this); + connect(m_timer, SIGNAL(timeout()), this, SLOT(timeout())); + m_timer->start(AUTOAWAY_TIME); +} + +AutoAwayPlugin::~AutoAwayPlugin() +{ +#ifdef WIN32 + // nothing to do +#elif defined(HAVE_CARBON_CARBON_H) && !defined(HAVE_X) + RemoveEventLoopTimer(mTimerRef); +#elif defined(__OS2__) + // --- +#else + // We load static Xss in our autoaway.so's process space, but the bastard + // registers for shutdown in the XDisplay variable, so after autoaway.so + // unloads, its code will still be called (as part of the XCloseDisplay). + // As Xss offers no function to unregister itself, we'll have to be a little + // messy here: + Display* dpy = QX11Info::display(); + LockDisplay(dpy); + // Original code from Xlib's ClDisplay.c + _XExtension *ext, *prev_ext = NULL; + for (ext = dpy->ext_procs; ext; prev_ext = ext, ext = ext->next) + { + if (ext->name && (strcmp(ext->name, ScreenSaverName) == 0)) + { + if (ext->close_display) + (*ext->close_display)(dpy, &ext->codes); + if (prev_ext) + prev_ext->next = ext->next; + else + dpy->ext_procs = ext->next; + Xfree((char*)ext); + break; + } + } + UnlockDisplay(dpy); +#endif + free_data(autoAwayData, &data); +} + +QByteArray AutoAwayPlugin::getConfig() +{ + return save_data(autoAwayData, &data); +} + +QWidget *AutoAwayPlugin::createConfigWindow(QWidget *parent) +{ + return new AutoAwayConfig(parent, this); +} + +void AutoAwayPlugin::timeout() +{ + CorePlugin *core = GET_CorePlugin(); + unsigned long newStatus = core->getManualStatus(); + unsigned long oldStatus =getRealManualStatus(); + unsigned idle_time = getIdleTime() / 60; + if (oldStatus != STATUS_UNKNOWN && !bAway && !bNA && !bOff){ + // If fake ManualStatus were saved in config by chace, we should replace it by real value... + newStatus = oldStatus; + oldStatus = STATUS_UNKNOWN; + } + if ((bAway && (idle_time < getAwayTime())) || + (bNA && (idle_time < getNATime())) || + (bOff && (idle_time < getOffTime()))){ + bAway = false; + bNA = false; + bOff = false; + newStatus = oldStatus; + oldStatus = STATUS_UNKNOWN; + }else if (!bAway && !bNA && !bOff && getEnableAway() && (idle_time >= getAwayTime())){ + unsigned long status = core->getManualStatus(); + if ((status == STATUS_AWAY) || (status == STATUS_NA) || (status == STATUS_OFFLINE)) + return; + oldStatus = status; + newStatus = STATUS_AWAY; + bAway = true; + }else if (!bNA && !bOff && getEnableNA() && (idle_time >= getNATime())){ + unsigned long status = core->getManualStatus(); + if ((status == STATUS_NA) || (status == STATUS_OFFLINE)) + return; + if (!bAway) + oldStatus = status; + bNA = true; + newStatus = STATUS_NA; + }else if (!bOff && getEnableOff() && (idle_time >= getOffTime())){ + unsigned long status = core->getManualStatus(); + if (status == STATUS_OFFLINE) + return; + if (!bNA) + oldStatus = status; + bOff = true; + newStatus = STATUS_OFFLINE; + } + if (newStatus == core->getManualStatus()) + return; + for (unsigned i = 0; i < getContacts()->nClients(); i++){ + Client *client = getContacts()->getClient(i); + if (!client->getCommonStatus()) + continue; + client->setStatus(newStatus, true); + } + if (core->getManualStatus() == newStatus) + return; + core->setValue("StatusTime", (unsigned int)time(NULL)); //data.StatusTime.asULong() = time(NULL); + //core->data.ManualStatus.asULong() = newStatus; + core->setValue("ManualStatus", (unsigned int)newStatus); + setRealManualStatus(oldStatus); + EventClientStatus().process(); +} + +bool AutoAwayPlugin::processEvent(Event *e) +{ + switch (e->type()) { + case eEventPlaySound: { + if (getDisableAlert() && (bAway || bNA || bOff)) + return true; + break; + } + case eEventContact: { + EventContact *ec = static_cast(e); + if(ec->action() != EventContact::eOnline) + break; + unsigned long commonStatus = STATUS_UNKNOWN; + for (unsigned i = 0; i < getContacts()->nClients(); i++){ + Client *client = getContacts()->getClient(i); + if (!client->getCommonStatus()) + continue; + commonStatus = client->getManualStatus(); + break; + } + if ((commonStatus == STATUS_ONLINE) || (commonStatus == STATUS_OFFLINE)) + return false; + if (getDisableAlert() && (bAway || bNA || bOff)) + return true; + break; + } + default: + break; + } + return false; +} + +unsigned AutoAwayPlugin::getIdleTime() +{ +#ifdef WIN32 + if (_GetLastInputInfo){ + LASTINPUTINFO lii; + ZeroMemory(&lii,sizeof(lii)); + lii.cbSize=sizeof(lii); + _GetLastInputInfo(&lii); + return (GetTickCount()-lii.dwTime) / 1000; + } + return IdleUIGetLastInputTime(); +#elif defined(HAVE_CARBON_CARBON_H) && !defined(HAVE_X) + return mSecondsIdle; +#elif defined(__OS2__) + ULONG lastInp = WinGetLastInputTime(); + if ( lastInp == 0 ) { + return 0; + } + return (WinGetCurrentTime(WinQueryAnchorBlock(HWND_DESKTOP)) - lastInp) / 1000; +#else + static XScreenSaverInfo *mit_info = NULL; + if (mit_info == NULL) { + int event_base, error_base; + /* + if(XScreenSaverQueryExtension(QX11Info::display(), &event_base, &error_base)) { + mit_info = XScreenSaverAllocInfo (); + } + */ + } + if (mit_info == NULL){ + log(L_WARN, "No XScreenSaver extension found on current XServer, disabling auto-away."); + m_timer->stop(); + return 0; + } + if (!XScreenSaverQueryInfo(QX11Info::display(), QX11Info::appRootWindow(), mit_info)) { + log(L_WARN, "XScreenSaverQueryInfo failed, disabling auto-away."); + m_timer->stop(); + return 0; + } + return (mit_info->idle / 1000); +#endif +} + diff --git a/plugins/autoaway/autoaway.h b/plugins/autoaway/autoaway.h new file mode 100644 index 0000000..8be0a1a --- /dev/null +++ b/plugins/autoaway/autoaway.h @@ -0,0 +1,70 @@ +/*************************************************************************** + autoaway.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _AUTOAWAY_H +#define _AUTOAWAY_H + +#include + +#include "cfg.h" +#include "event.h" +#include "plugins.h" + +class QTimer; + +struct AutoAwayData +{ + SIM::Data AwayTime; + SIM::Data EnableAway; + SIM::Data NATime; + SIM::Data EnableNA; + SIM::Data OffTime; + SIM::Data EnableOff; + SIM::Data DisableAlert; + SIM::Data RealManualStatus; +}; + +class AutoAwayPlugin : public QObject, public SIM::Plugin, public SIM::EventReceiver +{ + Q_OBJECT +public: + AutoAwayPlugin(unsigned, Buffer*); + ~AutoAwayPlugin(); + PROP_ULONG(AwayTime); + PROP_BOOL(EnableAway); + PROP_ULONG(NATime); + PROP_BOOL(EnableNA); + PROP_ULONG(OffTime); + PROP_BOOL(EnableOff); + PROP_BOOL(DisableAlert); + PROP_ULONG(RealManualStatus); +protected slots: + void timeout(); +protected: + virtual bool processEvent(SIM::Event*); + virtual QByteArray getConfig(); + virtual QWidget *createConfigWindow(QWidget *parent); + unsigned getIdleTime(); + bool bAway; + bool bNA; + bool bOff; + QTimer *m_timer; + AutoAwayData data; +}; + +#endif + diff --git a/plugins/autoaway/autoaway.rc b/plugins/autoaway/autoaway.rc new file mode 100644 index 0000000..333bf83 --- /dev/null +++ b/plugins/autoaway/autoaway.rc @@ -0,0 +1,97 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,9,6,0 + PRODUCTVERSION 0,9,6,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Vladimir Shutoff\0" + VALUE "FileDescription", "Autoaway plugin\0" + VALUE "FileVersion", "0, 9, 6, 0\0" + VALUE "InternalName", "autoaway\0" + VALUE "LegalCopyright", "Copyright © 2002-2003\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "autoaway.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "SIM\0" + VALUE "ProductVersion", "0, 9, 6, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/autoaway/autoaway.vcproj b/plugins/autoaway/autoaway.vcproj new file mode 100644 index 0000000..cacf605 --- /dev/null +++ b/plugins/autoaway/autoaway.vcproj @@ -0,0 +1,418 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/autoaway/autoawaycfg.cpp b/plugins/autoaway/autoawaycfg.cpp new file mode 100644 index 0000000..c8a40d8 --- /dev/null +++ b/plugins/autoaway/autoawaycfg.cpp @@ -0,0 +1,72 @@ +/*************************************************************************** + autoawaycfg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "autoawaycfg.h" +#include "autoaway.h" + +#include +#include + +AutoAwayConfig::AutoAwayConfig(QWidget *parent, AutoAwayPlugin *plugin) : QWidget(parent) + //: AutoAwayConfigBase(parent) +{ + setupUi(this); + m_plugin = plugin; + chkAway->setChecked(m_plugin->getEnableAway()); + chkNA->setChecked(m_plugin->getEnableNA()); + chkOff->setChecked(m_plugin->getEnableOff()); + spnAway->setValue(m_plugin->getAwayTime()); + spnNA->setValue(m_plugin->getNATime()); + spnOff->setValue(m_plugin->getOffTime()); + chkAlert->setChecked(m_plugin->getDisableAlert()); + connect(chkAway, SIGNAL(toggled(bool)), this, SLOT(toggledAway(bool))); + connect(chkNA, SIGNAL(toggled(bool)), this, SLOT(toggledNA(bool))); + connect(chkOff, SIGNAL(toggled(bool)), this, SLOT(toggledOff(bool))); + toggledAway(chkAway->isChecked()); + toggledNA(chkNA->isChecked()); + toggledOff(chkOff->isChecked()); +} + +void AutoAwayConfig::toggledAway(bool bState) +{ + spnAway->setEnabled(bState); +} + +void AutoAwayConfig::toggledNA(bool bState) +{ + spnNA->setEnabled(bState); +} + +void AutoAwayConfig::toggledOff(bool bState) +{ + spnOff->setEnabled(bState); +} + +void AutoAwayConfig::apply() +{ + m_plugin->setDisableAlert(chkAlert->isChecked()); + m_plugin->setEnableAway(chkAway->isChecked()); + m_plugin->setEnableNA(chkNA->isChecked()); + m_plugin->setEnableOff(chkOff->isChecked()); + if (m_plugin->getEnableAway()) + m_plugin->setAwayTime(spnAway->text().toULong()); + if (m_plugin->getEnableNA()) + m_plugin->setNATime(spnNA->text().toULong()); + if (m_plugin->getEnableOff()) + m_plugin->setOffTime(spnOff->text().toULong()); +} + diff --git a/plugins/autoaway/autoawaycfg.h b/plugins/autoaway/autoawaycfg.h new file mode 100644 index 0000000..5b37dd3 --- /dev/null +++ b/plugins/autoaway/autoawaycfg.h @@ -0,0 +1,40 @@ +/*************************************************************************** + autoawaycfg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _AUTOAWAYCFG_H +#define _AUTOAWAYCFG_H + +#include "ui_autoawaycfgbase.h" + +class AutoAwayPlugin; + +class AutoAwayConfig : public QWidget, public Ui::AutoAwayConfigBase +{ + Q_OBJECT +public: + AutoAwayConfig(QWidget *parent, AutoAwayPlugin*); +public slots: + void apply(); + void toggledAway(bool); + void toggledNA(bool); + void toggledOff(bool); +protected: + AutoAwayPlugin *m_plugin; +}; + +#endif + diff --git a/plugins/autoaway/autoawaycfgbase.ui b/plugins/autoaway/autoawaycfgbase.ui new file mode 100644 index 0000000..95ab7e8 --- /dev/null +++ b/plugins/autoaway/autoawaycfgbase.ui @@ -0,0 +1,141 @@ + + + AutoAwayConfigBase + + + + 0 + 0 + 484 + 243 + + + + Form1 + + + + + + Set "Away" status after + + + + + + + 1 + + + + + + + minutes not using computer + + + false + + + + + + + Set "N/A" status after + + + + + + + 1 + + + + + + + minutes of "Away" + + + false + + + + + + + Set "Offline" status after + + + + + + + 1 + + + + + + + minutes of "N/A" + + + false + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 10 + 10 + + + + + + + + Disable online alert in "Away", "N/A", "DND" and "Occupied" List + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 95 + + + + + + + + chkAway + spnAway + chkNA + spnNA + chkOff + spnOff + chkAlert + + + + diff --git a/plugins/autoaway/configure.in.in b/plugins/autoaway/configure.in.in new file mode 100644 index 0000000..2b643a3 --- /dev/null +++ b/plugins/autoaway/configure.in.in @@ -0,0 +1,24 @@ +if test "x$kde_use_qt_win" = "xno"; then + compile_plugin="no" + XSS_LIBS="no" + save_CPPFLAGS="$CPPFLAGS" + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $all_libraries" + CPPFLAGS="$CPPFLAGS $X_INCLUDES" + AC_CHECK_LIB(Xext, XScreenSaverRegister,[XSS_LIBS=""],[], [-lX11 -lXext -lm]) + AC_CHECK_LIB(Xss, XScreenSaverRegister,[XSS_LIBS="-lXss"],[],[-lX11 -lXext -lm]) + if test \! "$XSS_LIBS" = "no"; then + KDE_CHECK_HEADER(X11/extensions/scrnsaver.h,[compile_plugin="yes"],[]) + else + XSS_LIBS="" + AC_CHECK_HEADER(Carbon/Carbon.h,[compile_plugin="yes"]) + fi + AC_SUBST(XSS_LIBS) + if test "x$compile_plugin" = "xno"; then + AC_MSG_WARN([ScreenSaver extension not found. AutoAway plugin is disabled]) + fi + AM_CONDITIONAL(ENABLE_AUTOAWAY, test "x$compile_plugin" = "xyes") +else + AM_CONDITIONAL(ENABLE_AUTOAWAY, true) +fi + diff --git a/plugins/autoaway/idleui.cpp b/plugins/autoaway/idleui.cpp new file mode 100644 index 0000000..4945c23 --- /dev/null +++ b/plugins/autoaway/idleui.cpp @@ -0,0 +1,177 @@ +//////////////////////////////////////////////////////////////// +// 2000 Microsoft Systems Journal. +// If this program works, it was written by Paul DiLascia. +// If not, I don't know who wrote it. +// This program compiles with Visual C++ 6.0 on Windows 98 +// +// See IdleUI.h +// +#ifdef WIN32 +#include +#include +#include +#include + +//////////////// +// The following global data is SHARED among all instances of the DLL +// (processes); i.e., these are system-wide globals. +// +#pragma data_seg (".IdleUI") // you must define as SHARED in .def + +HHOOK g_keyboardHook = NULL; // one instance for all processes +HHOOK g_mouseHook = NULL; // one instance for all processes +DWORD g_lastInputTick = 0; // tick time of last input event + +/** + Last mouse position. +*/ +POINT g_lastMousePos; + +#pragma data_seg () + +/** + Flag indicating whether the DLL's owning process is the loading DLL. +*/ +bool g_isHandleOwner = false; + +// +// Public interface +// + +////////////////// +// Initialize DLL: install kbd/mouse hooks. +// +BOOL IdleUIInit() +{ + return TRUE; +} + +////////////////// +// Terminate DLL: remove hooks. +// +void IdleUITerm() +{ +} + +///////////////// +// Get tick count of last keyboard or mouse event +// +DWORD IdleUIGetLastInputTime() +{ + return g_lastInputTick; +} + +// +// Internals +// + +///////////////// +// Keyboard hook: record tick count +// +LRESULT CALLBACK keyboardHookCallback(int code, WPARAM wParam, LPARAM lParam) +{ + if (code == HC_ACTION) + { + g_lastInputTick = GetTickCount(); + } + return ::CallNextHookEx(g_keyboardHook, code, wParam, lParam); +} + +///////////////// +// Mouse hook: record tick count +// +LRESULT CALLBACK mouseHookCallback(int code, WPARAM wParam, LPARAM lParam) +{ + if (code == HC_ACTION) + { + // Update timestamp if event indicates mouse action + bool change = false; + if (wParam == WM_MOUSEMOVE && lParam != 0) + { + PMOUSEHOOKSTRUCT mhs = (PMOUSEHOOKSTRUCT) lParam; + if (mhs->pt.x != g_lastMousePos.x || + mhs->pt.y != g_lastMousePos.y) + { + change = true; + g_lastMousePos = mhs->pt; + } + } + else + { + change = true; + } + if (change) + { + g_lastInputTick = GetTickCount(); + } + } + return ::CallNextHookEx(g_mouseHook, code, wParam, lParam); +} + +void initialize(HINSTANCE module) +{ + if (g_keyboardHook == 0) + { + g_keyboardHook = SetWindowsHookEx(WH_KEYBOARD, keyboardHookCallback, module, 0); + g_mouseHook = SetWindowsHookEx(WH_MOUSE, mouseHookCallback, module, 0); + g_lastInputTick = GetTickCount(); + g_isHandleOwner = true; + } + assert(g_keyboardHook); + assert(g_mouseHook); +} + +void shutdown() +{ + // Only handle-owning process may unhook + if (g_isHandleOwner) + { + if (g_keyboardHook != 0) + { + UnhookWindowsHookEx(g_keyboardHook); + g_keyboardHook = 0; + } + if (g_mouseHook != 0) + { + UnhookWindowsHookEx(g_mouseHook); + g_mouseHook = 0; + } + } +} + +// +// DLL entry point +// +static bool bHaveGetLastInputInfo = false; +BOOL WINAPI DllMain(HINSTANCE module, DWORD reason, LPVOID reserved) +{ + if(bHaveGetLastInputInfo) + return TRUE; + if(QLibrary::resolve("user32.dll", "GetLastInputInfo")) { + bHaveGetLastInputInfo = true; + return TRUE; + } + reserved=0; + switch (reason) + { + case DLL_PROCESS_ATTACH: + { + initialize(module); + break; + } + case DLL_PROCESS_DETACH: + { + shutdown(); + break; + } + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + { + // Ignore + break; + } + } + return TRUE; +} +#endif + diff --git a/plugins/autoaway/idleui.def b/plugins/autoaway/idleui.def new file mode 100644 index 0000000..6669763 --- /dev/null +++ b/plugins/autoaway/idleui.def @@ -0,0 +1,6 @@ +LIBRARY "IdleUI" +SECTIONS .IdleUI READ WRITE SHARED + +EXPORTS +IdleUIGetLastInputTime + diff --git a/plugins/autoaway/idleui.h b/plugins/autoaway/idleui.h new file mode 100644 index 0000000..954eb25 --- /dev/null +++ b/plugins/autoaway/idleui.h @@ -0,0 +1,10 @@ +#ifndef IDLEUI_H +#define IDLEUI_H +#pragma once +#include + +BOOL IdleUIInit(); +void IdleUITerm(); +DWORD IdleUIGetLastInputTime(); + +#endif diff --git a/plugins/autoaway/idleui.rc b/plugins/autoaway/idleui.rc new file mode 100644 index 0000000..e1c593b --- /dev/null +++ b/plugins/autoaway/idleui.rc @@ -0,0 +1,97 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,0 + PRODUCTVERSION 1,0,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Vladimir Shutoff\0" + VALUE "FileDescription", "Idle UI\0" + VALUE "FileVersion", "0, 9, 6, 0\0" + VALUE "InternalName", "idleui\0" + VALUE "LegalCopyright", "Copyright © 2002-2003\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "idleui.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "SIM\0" + VALUE "ProductVersion", "0, 9, 6, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/autoaway/idleui.vcproj b/plugins/autoaway/idleui.vcproj new file mode 100644 index 0000000..2cfab77 --- /dev/null +++ b/plugins/autoaway/idleui.vcproj @@ -0,0 +1,265 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/background/CMakeLists.txt b/plugins/background/CMakeLists.txt new file mode 100644 index 0000000..139ebd7 --- /dev/null +++ b/plugins/background/CMakeLists.txt @@ -0,0 +1,23 @@ +###################### +# background library # +###################### +IF(BUILD_DROPPED) +SET(background_SRCS + background.cpp + bkgndcfg.cpp +) + +SET(background_HDRS + background.h + bkgndcfg.h +) + +SET(background_UICS + bkgndcfgbase.ui +) + +REMOVE_DEFINITIONS(-DQT3_SUPPORT) +REMOVE_DEFINITIONS(-DQT_3SUPPORT_LIB) +REMOVE_DEFINITIONS(-DQT3_SUPPORT_WARNINGS) +SIM_ADD_PLUGIN(background) +ENDIF(BUILD_DROPPED) diff --git a/plugins/background/background.cpp b/plugins/background/background.cpp new file mode 100644 index 0000000..7f88b49 --- /dev/null +++ b/plugins/background/background.cpp @@ -0,0 +1,177 @@ +/*************************************************************************** + background.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "misc.h" + +#include "background.h" +#include "bkgndcfg.h" +#include "log.h" + +#include "profile.h" +#include "profilemanager.h" + +#include +#include +#include +#include + +using namespace SIM; + +Plugin *createBackgroundPlugin(unsigned base, bool, Buffer *config) +{ + Plugin *plugin = new BackgroundPlugin(base, config); + return plugin; +} + +static PluginInfo info = + { + I18N_NOOP("Background"), + I18N_NOOP("Plugin provides background pictures for user list"), + VERSION, + createBackgroundPlugin, + PLUGIN_NOLOAD_DEFAULT + }; + +EXPORT_PROC PluginInfo* GetPluginInfo() +{ + return &info; +} + +BackgroundPlugin::BackgroundPlugin(unsigned base, Buffer *config) + : QObject(), Plugin(base) +{ + m_propertyHub = SIM::PropertyHub::create("background"); + redraw(); +} + +BackgroundPlugin::~BackgroundPlugin() +{ + +} + +QByteArray BackgroundPlugin::getConfig() +{ + return QByteArray(); //Fixme +} + +QWidget *BackgroundPlugin::createConfigWindow(QWidget *parent) +{ + return new BkgndCfg(parent, this); +} + +bool BackgroundPlugin::processEvent(Event *e) +{ + if (e->type() == eEventPaintView){ + EventPaintView *ev = static_cast(e); + EventPaintView::PaintView *pv = ev->paintView();; + if (!bgImage.isNull()){ + unsigned w = bgImage.width(); + unsigned h = bgImage.height(); + int x = pv->pos.x(); + int y = pv->pos.y(); + bool bTiled = false; + unsigned pos = value("Position").toUInt(); + switch(pos){ + case ContactLeft: + h = pv->height; + bTiled = true; + break; + case ContactScale: + h = pv->height; + w = pv->win->width(); + bTiled = true; + break; + case WindowTop: + break; + case WindowBottom: + y += (bgImage.height() - pv->win->height()); + break; + case WindowCenter: + y += (bgImage.height() - pv->win->height()) / 2; + break; + case WindowScale: + w = pv->win->width(); + h = pv->win->height(); + break; + } + const QPixmap &bg = makeBackground(w, h); + if (bTiled){ + for (int py = 0; py < pv->size.height(); py += bg.height()){ + pv->p->drawPixmap(QPoint(0, py), bgScale, QRect(x, 0, w, h)); + } + }else{ + pv->p->drawPixmap(QPoint(0, 0), bgScale, QRect(x, y, pv->size.width(), pv->size.height())); + pv->isStatic = true; + } + } + pv->margin = pv->isGroup ? value("MarginGroup").toUInt() : value("MarginContact").toUInt(); + } + else if(e->type() == eEventPluginLoadConfig) + { + PropertyHubPtr hub = ProfileManager::instance()->getPropertyHub("_core"); + if(!hub.isNull()) + setPropertyHub(hub); + redraw(); + } + return false; +} + +void BackgroundPlugin::redraw() +{ + bgImage = QImage(); + bgScale = QPixmap(); + if (value("Background").toString().isEmpty()) + return; + bgImage = QImage(value("Background").toString()); + EventRepaintView e; + e.process(); +} + +QPixmap &BackgroundPlugin::makeBackground(int w, int h) +{ + if (bgImage.isNull()) + return bgScale; + if ((bgScale.width() != w) || (bgScale.height() != h)){ + if ((bgImage.width() == w) && (bgImage.height() == h)){ + bgScale = QPixmap::fromImage(bgImage); + }else{ + QImage img = bgImage.scaled( w, h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ); + bgScale = QPixmap::fromImage( img ); + } + } + return bgScale; +} + +void BackgroundPlugin::setPropertyHub(SIM::PropertyHubPtr hub) +{ + m_propertyHub = hub; +} + +SIM::PropertyHubPtr BackgroundPlugin::propertyHub() +{ + return m_propertyHub; +} + +QVariant BackgroundPlugin::value(const QString& key) +{ + return m_propertyHub->value(key); +} + +void BackgroundPlugin::setValue(const QString& key, const QVariant& v) +{ + m_propertyHub->setValue(key, v); +} \ No newline at end of file diff --git a/plugins/background/background.h b/plugins/background/background.h new file mode 100644 index 0000000..6c29eac --- /dev/null +++ b/plugins/background/background.h @@ -0,0 +1,63 @@ +/*************************************************************************** + background.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _BACKGROUND_H +#define _BACKGROUND_H + +#include "cfg.h" +#include "event.h" +#include "plugins.h" +#include "propertyhub.h" + +#include +#include +#include + +const unsigned ContactLeft = 0; +const unsigned ContactScale = 1; +const unsigned WindowTop = 2; +const unsigned WindowBottom = 3; +const unsigned WindowCenter = 4; +const unsigned WindowScale = 5; + +class BackgroundPlugin : public QObject, public SIM::Plugin, public SIM::EventReceiver +{ +public: + BackgroundPlugin(unsigned, Buffer *name); + virtual ~BackgroundPlugin(); + void setPropertyHub(SIM::PropertyHubPtr hub); + SIM::PropertyHubPtr propertyHub(); + QVariant value(const QString& key); + void setValue(const QString& key, const QVariant& v); + +protected: + virtual bool processEvent(SIM::Event *e); + virtual QByteArray getConfig(); + virtual QWidget *createConfigWindow(QWidget *parent); + + QImage bgImage; + QPixmap bgScale; + QPixmap &makeBackground(int w, int h); + void redraw(); + friend class BkgndCfg; + +private: + SIM::PropertyHubPtr m_propertyHub; +}; + +#endif + diff --git a/plugins/background/background.rc b/plugins/background/background.rc new file mode 100644 index 0000000..60b3d00 --- /dev/null +++ b/plugins/background/background.rc @@ -0,0 +1,97 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,9,6,0 + PRODUCTVERSION 0,9,6,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Vladimir Shutoff\0" + VALUE "FileDescription", "Background plugin\0" + VALUE "FileVersion", "0, 9, 6, 0\0" + VALUE "InternalName", "background\0" + VALUE "LegalCopyright", "Copyright © 2002-2003\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "background.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "SIM\0" + VALUE "ProductVersion", "0, 9, 6, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/background/background.vcproj b/plugins/background/background.vcproj new file mode 100644 index 0000000..87858ec --- /dev/null +++ b/plugins/background/background.vcproj @@ -0,0 +1,369 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/background/bkgndcfg.cpp b/plugins/background/bkgndcfg.cpp new file mode 100644 index 0000000..b124733 --- /dev/null +++ b/plugins/background/bkgndcfg.cpp @@ -0,0 +1,100 @@ +/*************************************************************************** + bkgndcfg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "simapi.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "misc.h" +#include "simgui/linklabel.h" +#include "simgui/editfile.h" +#include "simgui/preview.h" + +#include "bkgndcfg.h" +#include "background.h" + +#ifndef USE_KDE + +static FilePreview *createPreview(QWidget *parent) +{ + return new PictPreview(parent); +} + +#endif + +BkgndCfg::BkgndCfg(QWidget *parent, BackgroundPlugin *plugin) : QWidget(parent) + //: BkgndCfgBase(parent) +{ + setupUi(this); + m_plugin = plugin; + edtPicture->setText(plugin->value("Background").toString()); + edtPicture->setStartDir(SIM::app_file("pict/")); + edtPicture->setTitle(i18n("Select background picture")); + QList formats = QImageReader::supportedImageFormats(); + QString format; + QString fmt; + foreach (fmt,formats) + { + if(format.length()>0) + format += " "; + fmt = fmt.toLower(); + format += "*." + fmt; + if (fmt == "jpeg") + format += " *.jpg"; + } +#ifdef USE_KDE + edtPicture->setFilter(i18n("%1|Graphics") .arg(format)); +#else + edtPicture->setFilter(i18n("Graphics(%1)") .arg(format)); + edtPicture->setFilePreview(createPreview); +#endif + cmbPosition->insertItem(INT_MAX,i18n("Contact - left")); + cmbPosition->insertItem(INT_MAX,i18n("Contact - scale")); + cmbPosition->insertItem(INT_MAX,i18n("Window - left top")); + cmbPosition->insertItem(INT_MAX,i18n("Window - left bottom")); + cmbPosition->insertItem(INT_MAX,i18n("Window - left center")); + cmbPosition->insertItem(INT_MAX,i18n("Window - scale")); + cmbPosition->setCurrentIndex(plugin->value("Position").toUInt()); + spnContact->setValue(plugin->value("MarginContact").toUInt()); + spnGroup->setValue(plugin->value("MarginGroup").toUInt()); + lblLink->setText(i18n("Get more skins")); + lblLink->setUrl("http://addons.miranda-im.org/index.php?action=display&id=34"); +} + +void BkgndCfg::apply() +{ + if (cmbPosition->currentIndex() >= 0) + m_plugin->setValue("Position", cmbPosition->currentIndex()); + m_plugin->setValue("Background", edtPicture->text()); + m_plugin->setValue("MarginContact", (uint)spnContact->text().toULong()); + m_plugin->setValue("MarginGroup", (uint)spnGroup->text().toULong()); + m_plugin->redraw(); +} + +/* +#ifndef NO_MOC_INCLUDES +#include "bkgndcfg.moc" +#endif +*/ + diff --git a/plugins/background/bkgndcfg.h b/plugins/background/bkgndcfg.h new file mode 100644 index 0000000..99c04c6 --- /dev/null +++ b/plugins/background/bkgndcfg.h @@ -0,0 +1,37 @@ +/*************************************************************************** + bkgndcfg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _BKGNDCFG_H +#define _BKGNDCFG_H + +#include "ui_bkgndcfgbase.h" + +class BackgroundPlugin; + +class BkgndCfg : public QWidget, public Ui::BkgndCfgBase +{ + Q_OBJECT +public: + BkgndCfg(QWidget *parent, BackgroundPlugin *plugin); +public slots: + void apply(); +protected: + BackgroundPlugin *m_plugin; +}; + +#endif + diff --git a/plugins/background/bkgndcfgbase.ui b/plugins/background/bkgndcfgbase.ui new file mode 100644 index 0000000..2b0f16f --- /dev/null +++ b/plugins/background/bkgndcfgbase.ui @@ -0,0 +1,257 @@ + + + + + BkgndCfgBase + + + + 0 + 0 + 419 + 187 + + + + Form1 + + + + 11 + + + 6 + + + + + 0 + + + 6 + + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Horizontal + + + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Vertical + + + + + + + Group margin: + + + Qt::AlignVCenter|Qt::AlignRight + + + false + + + + + + + Contact margin: + + + Qt::AlignVCenter|Qt::AlignRight + + + false + + + + + + + + + + Main window background: + + + Qt::AlignVCenter|Qt::AlignLeft + + + false + + + + + + + 0 + + + 6 + + + + + 20 + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Horizontal + + + + + + + + + 0 + + + 6 + + + + + 20 + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Horizontal + + + + + + + + + Place: + + + Qt::AlignVCenter|Qt::AlignRight + + + false + + + + + + + + + + + QWidget + QWidget +
QWidget
+ + -1 + -1 + + 0 + + 5 + 5 + + image0 + + text + +
+ + LinkLabel + QWidget +
simgui/linklabel.h
+ + -1 + -1 + + 0 + + 1 + 1 + + image1 + + text + +
+ + EditFile + QWidget +
simgui/editfile.h
+ + -1 + -1 + + 0 + + 5 + 5 + + image1 +
+
+ + + 789c6dd2c10ac2300c00d07bbf2234b7229d1be245fc04c5a3201e4615f430059d0711ff5ddb2e6bb236ec90eed134cb5a19d8ef36602af5ecdbfeeac05dda0798d3abebde87e3faa374d3807fa0d633a52d38d8de6f679fe33fc776e196f53cd010188256a3600a292882096246517815ca99884606e18044a3a40d91824820924265a7923a2e8bcd05f33db1173e002913175f2a6be6d3294871a2d95fa00e8a94ee017b69d339d90df1e77c57ea072ede6758 + + + 789c6dd2c10ac2300c00d07bbf2234b7229d1ddec44f503c0ae2a154410f53d0ed20e2bf6bdb656dd6861dd23d9a66591b0587fd1654235ebded6f0edcd53e419d87ae7b1f4f9b8f906d0bfe012317426a70b07bdc2f3ec77f8ed6b89559061a0343d06a124cc105596482585094bc0ae599b04646c9018926491b2205e140c485cace25755c175d0a967b622ff900b8cc9c7d29af594ea722d589167f813aa852ba07d94b9dce296e883fe7bb163f23896753 + + +
diff --git a/plugins/dock/CMakeLists.txt b/plugins/dock/CMakeLists.txt new file mode 100644 index 0000000..ac00192 --- /dev/null +++ b/plugins/dock/CMakeLists.txt @@ -0,0 +1,22 @@ +################ +# dock library # +################ +IF(BUILD_DROPPED) +SET(dock_SRCS + dock.cpp + dockcfg.cpp + dockwnd.cpp +) + +SET(dock_HDRS + dock.h + dockcfg.h + dockwnd.h +) + +SET(dock_UICS + dockcfgbase.ui +) + +SIM_ADD_PLUGIN(dock) +ENDIF(BUILD_DROPPED) diff --git a/plugins/dock/dock.cpp b/plugins/dock/dock.cpp new file mode 100644 index 0000000..f9bc9e0 --- /dev/null +++ b/plugins/dock/dock.cpp @@ -0,0 +1,394 @@ +/*************************************************************************** + dock.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "dock.h" +#include "dockcfg.h" +#include "dockwnd.h" +#include "mainwin.h" +#include "misc.h" +#include "core_consts.h" +#include "cmddef.h" +#include "core.h" + +#include "profile.h" +#include "profilemanager.h" + +#include +#include +#include +#include + +using namespace SIM; + +Plugin *createDockPlugin(unsigned base, bool, Buffer *config) +{ + return new DockPlugin(base, config); +} + +static PluginInfo info = + { + I18N_NOOP("System tray"), + I18N_NOOP("Plugin provides dock main window in system tray"), + VERSION, + createDockPlugin, + PLUGIN_DEFAULT + }; + +EXPORT_PROC PluginInfo* GetPluginInfo() +{ + return &info; +} + +DockPlugin::DockPlugin(unsigned base, Buffer *config) + : QObject(), Plugin(base) + , EventReceiver() + , m_dock(NULL) + , m_popup(NULL) +{ + m_propertyHub = SIM::PropertyHub::create("dock"); + DockMenu = registerType(); + CmdTitle = registerType(); + CmdToggle = registerType(); + CmdCustomize = registerType(); + + EventMenu(DockMenu, EventMenu::eAdd).process(); + + Command cmd; + cmd->id = CmdTitle; + cmd->text = I18N_NOOP("Sim-IM"); + cmd->icon = "SIM"; + cmd->menu_id = DockMenu; + cmd->menu_grp = 0x1000; + cmd->flags = COMMAND_TITLE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdCustomize; + cmd->text = I18N_NOOP("Customize menu"); + cmd->icon = "configure"; + cmd->menu_id = DockMenu; + cmd->menu_grp = 0x10000; + cmd->accel = QString::null; + cmd->flags = COMMAND_DEFAULT; + EventCommandCreate(cmd).process(); + + EventMenuGetDef eMenu(MenuMain); + eMenu.process(); + CommandsDef *def = eMenu.defs(); + if (def){ + CommandsList list(*def, true); + CommandDef *s; + while ((s = ++list) != NULL){ + if (s->id == 0) + continue; + cmd = *s; + if (!(cmd->flags & COMMAND_IMPORTANT)) + cmd->menu_grp = 0; + cmd->bar_id = 0; + cmd->menu_id = DockMenu; + EventCommandCreate(cmd).process(); + } + } + + cmd->id = CmdToggle; + cmd->text = I18N_NOOP("Toggle main window"); + cmd->icon = QString::null; + cmd->menu_id = MenuMain; + cmd->menu_grp = 0; + cmd->accel = "Ctrl+Shift+A"; + cmd->flags = COMMAND_CHECK_STATE | COMMAND_GLOBAL_ACCEL | COMMAND_IMPORTANT; + EventCommandCreate(cmd).process(); + + init(); + + QTimer *timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(timer())); + timer->start(2000); +} + +DockPlugin::~DockPlugin() +{ + EventCommandRemove(CmdToggle).process(); + EventMenu(DockMenu, EventMenu::eRemove).process(); + delete m_dock; +} + +void DockPlugin::init() +{ + if (m_dock) + return; + m_main = getMainWindow(); + if (!m_main) + return; + m_main->installEventFilter(this); + m_dock = new DockWnd(this, "inactive", I18N_NOOP("Inactive")); + connect(m_dock, SIGNAL(showPopup(QPoint)), this, SLOT(showPopup(QPoint))); + connect(m_dock, SIGNAL(toggleWin()), this, SLOT(toggleWin())); + connect(m_dock, SIGNAL(doubleClicked()), this, SLOT(doubleClicked())); + m_bQuit = false; + QApplication::syncX(); +} + +bool DockPlugin::eventFilter(QObject *o, QEvent *e) +{ + if (o == m_popup) + { + if (e->type() == QEvent::Hide) + { + m_popup->removeEventFilter(this); + m_popup = NULL; + } + }else{ + switch (e->type()) + { + case QEvent::Close: + if (!m_bQuit) + { + QWidget *main = static_cast(o); + setValue("ShowMain", false); + //setShowMain(false); + main->hide(); + e->ignore(); + return true; + } + break; + case QEvent::WindowDeactivate: + m_inactiveTime = QDateTime::currentDateTime(); + break; + case QEvent::WindowActivate: + m_inactiveTime = QDateTime(); + break; + default: + break; + } + } + return QObject::eventFilter(o, e); +} + +bool DockPlugin::isMainShow() +{ + QWidget *main = getMainWindow(); + if (main && main->isVisible()) + return true; + return false; +} + +bool DockPlugin::processEvent(Event *e) +{ + switch (e->type()) + { + case eEventInit: + init(); + break; + case eEventQuit: + if (m_dock){ + delete m_dock; + m_dock = NULL; + } + break; + case eEventRaiseWindow: + { + EventRaiseWindow *w = static_cast(e); + if (w->widget() == getMainWindow()){ + if (!m_dock) + init(); + if (!value("ShowMain").toBool()) + return true; + } + break; + } + case eEventCommandCreate: + { + EventCommandCreate *ecc = static_cast(e); + CommandDef *def = ecc->cmd(); + if (def->menu_id == MenuMain) + { + CommandDef d = *def; + if (def->flags & COMMAND_IMPORTANT) + { + if (d.menu_grp == 0) + d.menu_grp = 0x1001; + } + else + d.menu_grp = 0; + d.menu_id = DockMenu; + d.bar_id = 0; + EventCommandCreate(&d).process(); + } + break; + } + case eEventCheckCommandState: + { + EventCheckCommandState *ecs = static_cast(e); + CommandDef *def = ecs->cmd(); + if (def->id == CmdToggle) + { + def->flags &= ~COMMAND_CHECKED; + def->text = isMainShow() ? + I18N_NOOP("Hide main window") : + I18N_NOOP("Show main window"); + return true; + } + break; + } + case eEventCommandExec: + { + EventCommandExec *ece = static_cast(e); + CommandDef *def = ece->cmd(); + if (def->id == CmdToggle) + { + QWidget *main = getMainWindow(); + if(!main) + return false; + if (isMainShow()) + { + setValue("ShowMain", false); + main->hide(); + } + else + { + m_inactiveTime = QDateTime(); + setValue("ShowMain", true); + raiseWindow(main, value("Desktop").toUInt()); + } + return true; + } + if (def->id == CmdCustomize){ + EventMenu(DockMenu, EventMenu::eCustomize).process(); + return true; + } + if (def->id == CmdQuit) + m_bQuit = true; + break; + } + case eEventPluginLoadConfig: + { + PropertyHubPtr hub = ProfileManager::instance()->getPropertyHub("dock"); + if(!hub.isNull()) + setPropertyHub(hub); + break; + } + default: + break; + } + return false; +} + +QByteArray DockPlugin::getConfig() +{ + return QByteArray(); //Fixme +} + +QMenu *DockPlugin::createMenu() +{ + Command cmd; + cmd->popup_id = DockMenu; + EventMenuGet e(cmd); + e.process(); + return e.menu(); +} + +void DockPlugin::showPopup(QPoint p) +{ + if (m_popup) + return; + m_popup = createMenu(); + if (m_popup){ + m_popup->installEventFilter(this); + m_popup->popup(p); + } +} + +void DockPlugin::toggleWin() +{ + if (m_popup) + return; + + Command cmd; + cmd->id = CmdToggle; + cmd->menu_id = DockMenu; + cmd->menu_grp = 0x1000; + cmd->flags = COMMAND_CHECK_STATE; + + EventCommandExec(cmd).process(); +} + +void DockPlugin::doubleClicked() +{ + if (m_popup) + return; + + CorePlugin *core = GET_CorePlugin(); + if ( 0 == core->unread.size() ) + return; + + Command cmd; + cmd->id = CmdUnread; + cmd->menu_id = DockMenu; + cmd->menu_grp = 0x1000; + cmd->flags = COMMAND_CHECK_STATE; + + EventCommandExec(cmd).process(); +} + +QWidget *DockPlugin::getMainWindow() +{ + CorePlugin *core = GET_CorePlugin(); + return core->getMainWindow(); +} + +QWidget *DockPlugin::createConfigWindow(QWidget *parent) +{ + return new DockCfg(parent, this); +} + +void DockPlugin::timer() +{ + if (!isMainShow()) // already hidden + return; + if (!value("AutoHide").toBool() || (m_inactiveTime.isNull())) // no autohide + return; + m_main = getMainWindow(); + m_main->installEventFilter(this); + + if (QDateTime::currentDateTime() > m_inactiveTime.addSecs(value("AutoHideInterval").toUInt())){ + if (m_main) + { + setValue("ShowMain", false); + m_main->hide(); + } + } +} + +void DockPlugin::setPropertyHub(SIM::PropertyHubPtr hub) +{ + m_propertyHub = hub; +} + +SIM::PropertyHubPtr DockPlugin::propertyHub() +{ + return m_propertyHub; +} + +QVariant DockPlugin::value(const QString& key) +{ + return m_propertyHub->value(key); +} + +void DockPlugin::setValue(const QString& key, const QVariant& v) +{ + m_propertyHub->setValue(key, v); +} diff --git a/plugins/dock/dock.h b/plugins/dock/dock.h new file mode 100644 index 0000000..cd88941 --- /dev/null +++ b/plugins/dock/dock.h @@ -0,0 +1,77 @@ +/*************************************************************************** + dock.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _DOCK_H +#define _DOCK_H + +#include "cfg.h" +#include "event.h" +#include "plugins.h" +#include "propertyhub.h" + +#include +#include + +class DockWnd; +class QMenu; + +class DockPlugin : public QObject, public SIM::Plugin, public SIM::EventReceiver +{ + Q_OBJECT +public: + DockPlugin(unsigned, Buffer*); + virtual ~DockPlugin(); + + QMenu *createMenu(); + +protected slots: + void showPopup(QPoint); + void toggleWin(); + void doubleClicked(); + void timer(); +protected: + virtual bool processEvent(SIM::Event *e); + virtual QWidget *createConfigWindow(QWidget *parent); + virtual QByteArray getConfig(); + virtual bool eventFilter(QObject*, QEvent*); + QWidget *getMainWindow(); + bool isMainShow(); + void init(); + + DockWnd *m_dock; + QWidget* m_main; + QMenu *m_popup; + unsigned long DockMenu; + unsigned long CmdTitle; + unsigned long CmdToggle; + unsigned long CmdCustomize; + bool m_bQuit; + QDateTime m_inactiveTime; + friend class DockCfg; + friend class DockWnd; + + void setPropertyHub(SIM::PropertyHubPtr hub); + SIM::PropertyHubPtr propertyHub(); + QVariant value(const QString& key); + void setValue(const QString& key, const QVariant& v); + +private: + SIM::PropertyHubPtr m_propertyHub; +}; + +#endif + diff --git a/plugins/dock/dock.rc b/plugins/dock/dock.rc new file mode 100644 index 0000000..58c8941 --- /dev/null +++ b/plugins/dock/dock.rc @@ -0,0 +1,97 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,9,6,0 + PRODUCTVERSION 0,9,6,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Vladimir Shutoff\0" + VALUE "FileDescription", "Systray plugin\0" + VALUE "FileVersion", "0, 9, 6, 0\0" + VALUE "InternalName", "dock\0" + VALUE "LegalCopyright", "Copyright © 2002-2003\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "dock.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "SIM\0" + VALUE "ProductVersion", "0, 9, 6, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/dock/dock.vcproj b/plugins/dock/dock.vcproj new file mode 100644 index 0000000..062f1f3 --- /dev/null +++ b/plugins/dock/dock.vcproj @@ -0,0 +1,477 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/dock/dockcfg.cpp b/plugins/dock/dockcfg.cpp new file mode 100644 index 0000000..58e636d --- /dev/null +++ b/plugins/dock/dockcfg.cpp @@ -0,0 +1,68 @@ +/*************************************************************************** + dockcfg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "simapi.h" + +#include "dockcfg.h" +#include "dock.h" + +#include +#include +#include +#include +#ifdef USE_KDE +#include +#endif + +DockCfg::DockCfg(QWidget *parent, DockPlugin *plugin) : QWidget(parent) +{ + setupUi(this); + m_plugin = plugin; + chkAutoHide->setChecked(plugin->value("AutoHide").toBool()); + unsigned interval = plugin->value("AutoHideInterval").toUInt(); + spnAutoHide->setValue(interval); + connect(chkAutoHide, SIGNAL(toggled(bool)), this, SLOT(autoHideToggled(bool))); + connect(btnCustomize, SIGNAL(clicked()), this, SLOT(customize())); + autoHideToggled(plugin->value("AutoHide").toBool()); +#ifdef USE_KDE + spn_desk->setMaxValue(KWin::numberOfDesktops()); + spn_desk->setValue(m_plugin->value("Desktop").toUInt()); +#else + spn_desk->hide(); + TextLabel1_2->hide(); +#endif +} + +void DockCfg::apply() +{ + m_plugin->setValue("AutoHide", chkAutoHide->isChecked()); + m_plugin->setValue("AutoHideInterval", (uint)spnAutoHide->text().toULong()); +#ifdef USE_KDE + m_plugin->setValue("Desktop", spn_desk->text().toULong()); +#endif +} + +void DockCfg::autoHideToggled(bool bAutoHide) +{ + spnAutoHide->setEnabled(bAutoHide); +} + +void DockCfg::customize() +{ + SIM::EventMenu(m_plugin->DockMenu, SIM::EventMenu::eCustomize).process(); +} + diff --git a/plugins/dock/dockcfg.h b/plugins/dock/dockcfg.h new file mode 100644 index 0000000..d3e6373 --- /dev/null +++ b/plugins/dock/dockcfg.h @@ -0,0 +1,39 @@ +/*************************************************************************** + dockcfg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _DOCKCFG_H +#define _DOCKCFG_H + +#include "ui_dockcfgbase.h" + +class DockPlugin; + +class DockCfg : public QWidget, public Ui::DockCfgBase +{ + Q_OBJECT +public: + DockCfg(QWidget *w, DockPlugin *plugin); +public slots: + void apply(); + void autoHideToggled(bool); + void customize(); +protected: + DockPlugin *m_plugin; +}; + +#endif + diff --git a/plugins/dock/dockcfgbase.ui b/plugins/dock/dockcfgbase.ui new file mode 100644 index 0000000..071924a --- /dev/null +++ b/plugins/dock/dockcfgbase.ui @@ -0,0 +1,177 @@ + + DockCfgBase + + + + 0 + 0 + 313 + 138 + + + + Form1 + + + + 11 + + + 6 + + + + + 0 + + + 6 + + + + + Hide main window after + + + + + + + 999 + + + + + + + seconds inactive + + + false + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + + 0 + + + 6 + + + + + Show Mainwin on desktop + + + false + + + + + + + current + + + 999 + + + 0 + + + 0 + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + + 0 + + + 6 + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + &Customize dock menu + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + diff --git a/plugins/dock/dockwnd.cpp b/plugins/dock/dockwnd.cpp new file mode 100644 index 0000000..fa77cdb --- /dev/null +++ b/plugins/dock/dockwnd.cpp @@ -0,0 +1,383 @@ +/*************************************************************************** + dockwnd.cpp - description + ------------------- + begin : Sun Mar 10 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "simapi.h" + +#include "icons.h" +#include "log.h" +#include "dockwnd.h" +#include "dock.h" +#include "core.h" +#include "contacts/contact.h" +#include "contacts/client.h" + +#include +#include +#include +#include + +using namespace SIM; + +void DockWnd::trayAction(QSystemTrayIcon::ActivationReason reason) +{ + log( L_DEBUG, "Tray activation reason: %d", (int)reason ); + switch (reason){ + case QSystemTrayIcon::Context: + showPopup(); + return; + case QSystemTrayIcon::DoubleClick: + bNoToggle = true; + QTimer::singleShot(0, this, SLOT(dbl_click())); + return; + case QSystemTrayIcon::Trigger: +#ifdef Q_OS_MAC + showPopup(); +#else + if (bNoToggle) + bNoToggle = false; + else + emit toggleWin(); +#endif + return; + default: + return; + } +} + +void DockWnd::messageClicked() { + if (m_queue.isEmpty()) + return; + unsigned id = m_queue.front().id; + SIM::Client *client = m_queue.front().client; + m_queue.erase(m_queue.begin()); + if (!m_queue.empty()) + showBalloon(); + Command cmd; + cmd->id = id; + cmd->param = client; + EventCommandExec(cmd).process(); +} + +void DockWnd::showPopup() +{ + m_menu = m_plugin->createMenu(); +#ifdef Q_OS_MAC + m_TrayIcon.setContextMenu( m_menu ); +#else + m_menu->exec( QCursor::pos() ); +#endif +} + +DockWnd::DockWnd(DockPlugin *plugin, const char *icon, const char *text) + : QWidget(NULL, Qt::Window + | Qt::FramelessWindowHint + | Qt::WindowStaysOnTopHint) + , EventReceiver(LowPriority) + , m_state(icon) + , m_plugin(plugin) +{ + setObjectName("dock"); + setMouseTracking(true); + bNoToggle = false; + bBlink = false; + blinkTimer = new QTimer(this); + connect(blinkTimer, SIGNAL(timeout()), this, SLOT(blink())); + + m_bBalloon = QSystemTrayIcon::supportsMessages(); + setIcon(icon); + QWidget::hide(); + connect( + &m_TrayIcon, + SIGNAL(activated(QSystemTrayIcon::ActivationReason)), + SLOT(trayAction(QSystemTrayIcon::ActivationReason)) + ); + connect( + &m_TrayIcon, + SIGNAL(messageClicked()), + SLOT(messageClicked()) + ); + m_TrayIcon.show(); + setTip(text); + reset(); +} + +DockWnd::~DockWnd() +{ + quit(); +} + +void DockWnd::quit() +{ + m_TrayIcon.hide(); +} + +void DockWnd::dbl_click() +{ + emit doubleClicked(); +} + +bool DockWnd::processEvent(Event *e) +{ + switch (e->type()){ + case eEventMessageReceived: + case eEventMessageRead: + case eEventMessageDeleted: + reset(); + break; + case eEventSetMainIcon: { + EventSetMainIcon *smi = static_cast(e); + m_state = smi->icon(); + if (bBlink) + break; + setIcon(m_state); + break; + } + case eEventSetMainText: { + EventSetMainText *smt = static_cast(e); + setTip(smt->text()); + break; + } + case eEventIconChanged: + setIcon((bBlink && !m_unread.isEmpty()) ? m_unread : m_state); + break; + case eEventLanguageChanged: + setTip(m_tip); + break; + case eEventQuit: + quit(); + break; + case eEventShowNotification:{ + if (!m_bBalloon) + return false; + EventShowNotification *ee = static_cast(e); + const EventNotification::ClientNotificationData &data = ee->data(); + if (data.id == 0) + return false; + foreach(BalloonItem item, m_queue ) { + if (item.id == data.id) + return true; + } + QString arg = data.args; + + BalloonItem item; + item.id = data.id; + item.client = data.client; + item.flags = (data.flags & EventNotification::ClientNotificationData::E_INFO) ? EventNotification::ClientNotificationData::E_INFO : EventNotification::ClientNotificationData::E_INFO; + item.text = i18n(data.text); + if (item.text.indexOf("%1") >= 0) + item.text = item.text.arg(arg); + if (!m_queue.empty()){ + m_queue.push_back(item); + return true; + } + item.title = "SIM"; + if (getContacts()->nClients() > 1){ + for (unsigned i = 0; i < getContacts()->nClients(); i++){ + if (getContacts()->getClient(i) == data.client){ + item.title = getContacts()->getClient(i)->name(); + int n = item.title.indexOf("."); + if (n > 0) + item.title = item.title.left(n) + " " + item.title.mid(n + 1); + } + } + } + m_queue.push_back(item); + if (showBalloon()) + return true; + return false; + } + default: + break; + } + return false; +} + +bool DockWnd::showBalloon() +{ + if (m_queue.empty()) + return false; + BalloonItem &item = m_queue.front(); + + m_TrayIcon.showMessage( + item.title, + item.text, + item.flags & EventNotification::ClientNotificationData::E_INFO ? QSystemTrayIcon::Information : QSystemTrayIcon::Critical, + 20000 + ); + + return true; +} + +void DockWnd::paintEvent( QPaintEvent* ) +{ + QPainter p(this); + p.drawPixmap((width() - drawIcon.width())/2, (height() - drawIcon.height())/2, drawIcon); +} + +void DockWnd::setIcon(const QString &icon) +{ + if(m_curIcon == icon) + return; + m_curIcon = icon; + drawIcon = Pict(icon); + QWidget::setWindowIcon(drawIcon); + m_TrayIcon.setIcon(drawIcon); +} + +void DockWnd::setTip(const QString &text) +{ + m_tip = text; + QString tip = m_unreadText; + if (tip.isEmpty()){ + tip = i18n(text); + tip = tip.remove('&'); + } + if(tip == m_curTipText) + return; + m_curTipText = tip; + m_TrayIcon.setToolTip(m_curTipText); +} + +void DockWnd::mouseEvent( QMouseEvent *e) +{ + switch(e->button()){ + case Qt::LeftButton: + if (bNoToggle) + bNoToggle = false; + else + emit toggleWin(); + break; + case Qt::RightButton: + emit showPopup(e->globalPos()); + break; + case Qt::MidButton: + emit doubleClicked(); + break; + default: + break; + } +} + +void DockWnd::mousePressEvent( QMouseEvent *e) +{ + QWidget::mousePressEvent(e); +} + +void DockWnd::mouseReleaseEvent( QMouseEvent *e) +{ + QWidget::mouseReleaseEvent(e); + mouseEvent(e); +} + +void DockWnd::mouseMoveEvent( QMouseEvent *e) +{ + QWidget::mouseMoveEvent(e); +} + +void DockWnd::mouseDoubleClickEvent( QMouseEvent*) +{ + bNoToggle = true; + emit doubleClicked(); +} + +void DockWnd::enterEvent( QEvent* ) +{ +} + +void DockWnd::blink() +{ + if (m_unread.isEmpty()){ + bBlink = false; + blinkTimer->stop(); + setIcon(m_state); + return; + } + bBlink = !bBlink; + setIcon(bBlink ? m_unread : m_state); +} + +struct msgIndex +{ + unsigned contact; + unsigned type; +}; + +bool operator < (const msgIndex &a, const msgIndex &b) +{ + if (a.contact < b.contact) + return true; + if (a.contact > b.contact) + return false; + return a.type < b.type; +} + +typedef QMap MAP_COUNT; + +void DockWnd::reset() +{ + m_unread = QString::null; + QString oldUnreadText = m_unreadText; + m_unreadText = QString::null; + MAP_COUNT count; + MAP_COUNT::iterator itc; + CorePlugin *core = GET_CorePlugin(); + for (std::list::iterator it = core->unread.begin(); it != core->unread.end(); ++it){ + if (m_unread.isEmpty()){ + CommandDef *def =core->messageTypes.find(it->type); + if (def) + m_unread = def->icon; + } + msgIndex m; + m.contact = it->contact; + m.type = it->type; + itc = count.find(m); + if (itc == count.end()){ + count.insert(m, 1); + }else{ + itc.value()++; + } + } + if (!count.empty()){ + for (itc = count.begin(); itc != count.end(); ++itc){ + CommandDef *def = core->messageTypes.find(itc.key().type); + if (def == NULL) + continue; + MessageDef *mdef = (MessageDef*)(def->param); + QString msg = i18n(mdef->singular, mdef->plural, itc.value()); + + Contact *contact = getContacts()->contact(itc.key().contact); + if (contact == NULL) + continue; + msg = i18n("%1 from %2") + .arg(msg) + .arg(contact->getName()); + if (m_unreadText.length() + 2 + msg.length() >= 64){ + m_unreadText += "..."; + break; + } + + if (!m_unreadText.isEmpty()) + m_unreadText += "\n"; + m_unreadText += msg; + } + } + if (!m_unread.isEmpty() && !blinkTimer->isActive()) + blinkTimer->start(1500); + if (m_unreadText != oldUnreadText) + setTip(m_tip); +} + diff --git a/plugins/dock/dockwnd.h b/plugins/dock/dockwnd.h new file mode 100644 index 0000000..8f248ea --- /dev/null +++ b/plugins/dock/dockwnd.h @@ -0,0 +1,90 @@ +/*************************************************************************** + dockwnd.h - description + ------------------- + begin : Sun Mar 10 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _DOCKWND_H +#define _DOCKWND_H + +#include +#include +#include +#include + +#include "event.h" + +class WharfIcon; +class DockPlugin; + +struct BalloonItem +{ + QString text; + QString title; + unsigned id; + unsigned flags; + SIM::Client *client; +}; + +class DockWnd : public QWidget, public SIM::EventReceiver +{ + Q_OBJECT +public: + DockWnd(DockPlugin *plugin, const char *icon, const char *text); + ~DockWnd(); + void setIcon(const QString &icon); + void setTip(const QString &text); + void mouseEvent( QMouseEvent *e); + virtual void mouseDoubleClickEvent( QMouseEvent *e); +signals: + void showPopup(QPoint); + void toggleWin(); + void doubleClicked(); +protected slots: + void blink(); + void dbl_click(); + void showPopup(); + void trayAction(QSystemTrayIcon::ActivationReason reason); + void messageClicked(); +protected: + virtual bool processEvent(SIM::Event *e); + void reset(); + bool bNoToggle; + QString m_tip; + QString m_curTipText; + QString m_curIcon; + QString m_state; + QString m_unread; + QString m_unreadText; + QPixmap drawIcon; + virtual void enterEvent( QEvent *e); + virtual void paintEvent( QPaintEvent *e); + virtual void mousePressEvent( QMouseEvent *e); + virtual void mouseReleaseEvent( QMouseEvent *e); + virtual void mouseMoveEvent( QMouseEvent *e); + void quit(); + bool bBlink; + QTimer *blinkTimer; + + bool m_bBalloon; + QList m_queue; + bool showBalloon(); + + DockPlugin *m_plugin; + QSystemTrayIcon m_TrayIcon; + QMenu *m_menu; +}; + +#endif + diff --git a/plugins/filter/CMakeLists.txt b/plugins/filter/CMakeLists.txt new file mode 100644 index 0000000..09723fe --- /dev/null +++ b/plugins/filter/CMakeLists.txt @@ -0,0 +1,23 @@ +################## +# filter library # +################## +IF(BUILD_DROPPED) +SET(filter_SRCS + filter.cpp + filtercfg.cpp + ignorelist.cpp +) + +SET(filter_HDRS + filter.h + filtercfg.h + ignorelist.h +) + +SET(filter_UICS + filtercfgbase.ui + ignorelistbase.ui +) + +SIM_ADD_PLUGIN(filter) +ENDIF(BUILD_DROPPED) diff --git a/plugins/filter/filter.cpp b/plugins/filter/filter.cpp new file mode 100644 index 0000000..553fc0f --- /dev/null +++ b/plugins/filter/filter.cpp @@ -0,0 +1,429 @@ +/*************************************************************************** + filter.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include + +#include "simgui/ballonmsg.h" +#include "unquot.h" +#include "msgedit.h" +#include "msgview.h" +#include "userwnd.h" + +#include "profile.h" +#include "profilemanager.h" + +#include "filter.h" +#include "filtercfg.h" +#include "contacts/contact.h" + +using namespace SIM; + +Plugin *createFilterPlugin(unsigned base, bool, Buffer *cfg) +{ + return new FilterPlugin(base, cfg); +} + +static PluginInfo info = + { + I18N_NOOP("Filter"), + I18N_NOOP("Plugin provides message filter"), + VERSION, + createFilterPlugin, + PLUGIN_DEFAULT + }; + +EXPORT_PROC PluginInfo* GetPluginInfo() +{ + return &info; +} + +static DataDef filterUserData[] = + { + { "SpamList", DATA_UTF, 1, 0 }, + { NULL, DATA_UNKNOWN, 0, 0 } + }; + +static FilterPlugin *filterPlugin = NULL; + +static QWidget *getFilterConfig(QWidget *parent, PropertyHubPtr data) +{ + return new FilterConfig(parent, data, filterPlugin, false); +} + +FilterPlugin::FilterPlugin(unsigned base, Buffer *cfg) + : QObject(), Plugin(base) + , EventReceiver(HighPriority - 1) +{ + filterPlugin = this; + + m_propertyHub = SIM::PropertyHub::create("filter"); + //load_data(filterData, &data, cfg); + user_data_id = getContacts()->registerUserData(info.title, filterUserData); + + CmdIgnoreList = registerType(); + CmdIgnore = registerType(); + CmdIgnoreText = registerType(); + + Command cmd; + cmd->id = CmdIgnoreList; + cmd->text = I18N_NOOP("Ignore list"); + cmd->menu_id = MenuContactGroup; + cmd->menu_grp = 0x8080; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdIgnore; + cmd->text = I18N_NOOP("Ignore user"); + cmd->icon = "ignorelist"; + cmd->menu_id = 0; + cmd->menu_grp = 0; + cmd->bar_id = ToolBarContainer; + cmd->bar_grp = 0x7001; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdIgnoreText; + cmd->text = I18N_NOOP("Ignore this phrase"); + cmd->icon = QString::null; + cmd->menu_id = MenuTextEdit; + cmd->menu_grp = 0x7000; + cmd->bar_id = 0; + cmd->bar_grp = 0; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->menu_id = MenuMsgView; + EventCommandCreate(cmd).process(); + + cmd->id = user_data_id; + cmd->text = I18N_NOOP("&Filter"); + cmd->icon = "filter"; + cmd->menu_id = 0; + cmd->menu_grp = 0; + cmd->param = (void*)getFilterConfig; + EventAddPreferences(cmd).process(); +} + +FilterPlugin::~FilterPlugin() +{ + EventCommandRemove(CmdIgnoreList).process(); + EventRemovePreferences(user_data_id).process(); + getContacts()->unregisterUserData(user_data_id); +} + +QByteArray FilterPlugin::getConfig() +{ + return QByteArray(); +} + +bool FilterPlugin::processEvent(Event *e) +{ + switch (e->type()) { + case eEventContact: { + EventContact *ec = static_cast(e); + if(ec->action() != EventContact::eChanged) + break; + Contact *contact = ec->contact(); + if (contact->getGroup()){ + Command cmd; + cmd->id = CmdIgnore; + cmd->flags = BTN_HIDE; + cmd->param = (void*)(contact->id()); + EventCommandShow(cmd).process(); + } + break; + } + case eEventPluginLoadConfig: + { + setPropertyHub( ProfileManager::instance()->getPropertyHub("filter") ); + break; + } + case eEventMessageReceived: { + EventMessage *em = static_cast(e); + Message *msg = em->msg(); + if (!msg || (msg->type() == MessageStatus)) + return false; + Contact *contact = getContacts()->contact(msg->contact()); + PropertyHubPtr data = contact->getUserData("filter"); + // check if we accept only from users on the list + if (((contact == NULL) || contact->getFlags() & CONTACT_TEMPORARY) && + ((value("FromList").toBool() && + msg->type() != MessageAuthRequest && + msg->type() != MessageAuthGranted && + msg->type() != MessageAuthRefused) || + (value("AuthFromList").toBool() && msg->type() <= MessageContacts))) { + delete msg; + delete contact; + return msg; + } + if (!contact) + return false; + // check if the user is a ignored user + if (contact->getIgnore()){ + delete msg; + return true; + } + + // get filter-data + if (data && !data->value("SpamList").toString().isEmpty() && (!contact || (contact->getFlags() & CONTACT_TEMPORARY) )) { + if (checkSpam(msg->getPlainText(), data->value("SpamList").toString())){ + delete msg; + return true; + } + } + break; + } + case eEventCheckCommandState: { + EventCheckCommandState *ecs = static_cast(e); + CommandDef *cmd = ecs->cmd(); + if (cmd->id == CmdIgnore){ + cmd->flags &= ~BTN_HIDE; + Contact *contact = getContacts()->contact((unsigned long)(cmd->param)); + if (contact && contact->getGroup()) + cmd->flags |= BTN_HIDE; + return true; + } + if (cmd->id == CmdIgnoreText){ + cmd->flags &= ~COMMAND_CHECKED; + if (cmd->menu_id == MenuMsgView){ + MsgViewBase *edit = (MsgViewBase*)(cmd->param); + if (edit->textCursor().hasSelection()) + return true; + } else + /*if (cmd->menu_id == MenuTextEdit){ + TextEdit *edit = ((MsgEdit*)(cmd->param))->m_edit; + if (edit->textCursor().hasSelection()) + return true; + }*/ //Fixme Block (crashing on rightclick in msgedit from container) + return false; + } + if (cmd->menu_id == MenuContactGroup){ + if (cmd->id == CmdIgnoreList){ + Contact *contact = getContacts()->contact((unsigned long)(cmd->param)); + if (contact == NULL) + return false; + cmd->flags &= COMMAND_CHECKED; + if (contact->getIgnore()) + cmd->flags |= COMMAND_CHECKED; + return true; + } + } + break; + } + case eEventCommandExec: { + EventCommandExec *ece = static_cast(e); + CommandDef *cmd = ece->cmd(); + if (cmd->id == CmdIgnore){ + Contact *contact = getContacts()->contact((unsigned long)(cmd->param)); + if (contact){ + QString text = i18n("Add %1 to ignore list?") .arg(contact->getName()); + Command cmd; + cmd->id = CmdIgnore; + cmd->param = (void*)(contact->id()); + EventCommandWidget eWidget(cmd); + eWidget.process(); + QWidget *w = eWidget.widget(); + BalloonMsg::ask((void*)(contact->id()), text, w, SLOT(addToIgnore(void*)), NULL, NULL, this); + } + return true; + } + if (cmd->id == CmdIgnoreText){ + QString text; + unsigned id = 0; + if (cmd->menu_id == MenuMsgView){ + MsgViewBase *view = (MsgViewBase*)(cmd->param); + if (view->textCursor().hasSelection()){ + text = view->textCursor().selectedText(); + text = unquoteText(text); + id = view->m_id; + } + }else if (cmd->menu_id == MenuTextEdit){ + MsgEdit *medit = (MsgEdit*)(cmd->param); + TextEdit *edit = medit->m_edit; + if (edit->textCursor().hasSelection()){ + text = edit->textCursor().selectedText(); + text = unquoteText(text); + id = medit->m_userWnd->id(); + } + } + + Contact *contact = getContacts()->contact(id); + PropertyHubPtr data = contact->getUserData("filter"); + + QString s = data->value("SpamList").toString(); + while (!text.isEmpty()){ + QString line = getToken(text, '\n'); + line = line.remove('\r'); + if (line.isEmpty()) + continue; + bool bSpace = false; + for (int i = 0; i < (int)(line.length()); i++) + if (line[i] == ' '){ + bSpace = true; + break; + } + if (bSpace) + line = '\"' + line + '\"'; + if (!s.isEmpty()) + s += ' '; + s += line; + } + data->setValue("SpamList", s); + return false; + } + if (cmd->menu_id == MenuContactGroup) + { + if (cmd->id == CmdIgnoreList) + { + Contact *contact = getContacts()->contact((unsigned long)(cmd->param)); + if (!contact) + return false; + contact->setIgnore((cmd->flags & COMMAND_CHECKED) == 0); + EventContact(contact, EventContact::eChanged).process(); + return true; + } + } + break; + } + default: + break; + } + return false; +} + +QWidget *FilterPlugin::createConfigWindow(QWidget *parent) +{ + PropertyHubPtr data = getContacts()->getUserData("filter"); + return new FilterConfig(parent, data, this, true); +} + +static bool match(const QString &text, const QString &pat) +{ + int i; + for (i = 0; (i < (int)(text.length())) && (i < (int)(pat.length())); i++){ + QChar c = pat[i]; + if (c == '?') + continue; + if (c == '*'){ + int n; + for (n = i; n < (int)(pat.length()); n++) + if (pat[n] != '*') + break; + QString p = pat.mid(n); + if (p.isEmpty()) + return true; + for (n = i; n < (int)(text.length()); n++){ + QString t = text.mid(n); + if (match(text, p)) + return true; + } + return false; + } + if (text[i] != c) + return false; + } + return (i == (int)(text.length())) && (i == (int)(pat.length())); +} + +bool FilterPlugin::checkSpam(const QString &text, const QString &_filter) +{ + QString filter = _filter; + QStringList wordsText; + getWords(text, wordsText, false); + bool bQuota = false; + while (!filter.isEmpty()){ + QString filterPart = getToken(filter, '\"'); + QStringList wordsFilter; + getWords(filterPart, wordsFilter, true); + if (wordsFilter.count()){ + if (bQuota){ + for (QStringList::Iterator it = wordsText.begin(); it != wordsText.end(); ++it){ + if (!match(*it, wordsFilter[0])) + continue; + QStringList::Iterator it1 = it; + QStringList::Iterator itFilter = wordsFilter.begin(); + for (; (it1 != wordsText.end()) && (itFilter != wordsFilter.end()); ++it1, ++itFilter){ + if (!match(*it1, *itFilter)) + break; + } + if (itFilter == wordsFilter.end()) + return true; + } + }else{ + for (QStringList::Iterator it = wordsText.begin(); it != wordsText.end(); ++it){ + for (QStringList::Iterator itFilter = wordsFilter.begin(); itFilter != wordsFilter.end(); ++itFilter){ + if (match(*it, *itFilter)) + return true; + } + } + } + } + bQuota = !bQuota; + } + return false; +} + +void FilterPlugin::getWords(const QString &text, QStringList &words, bool bPattern) +{ + QString word; + for (int i = 0; i < (int)(text.length()); i++){ + QChar c = text[i]; + if (c.isLetterOrNumber()){ + word += c; + continue; + } + if (bPattern && ((c == '?') || (c == '*'))){ + word += c; + continue; + } + if (word.isEmpty()) + continue; + words.append(word); + word = QString::null; + } + if (!word.isEmpty()) + words.append(word); +} + +void FilterPlugin::addToIgnore(void *p) +{ + Contact *contact = getContacts()->contact((unsigned long)p); + if (contact && !contact->getIgnore()){ + contact->setIgnore(true); + EventContact(contact, EventContact::eChanged).process(); + } +} + +void FilterPlugin::setPropertyHub(SIM::PropertyHubPtr hub) +{ + m_propertyHub = hub; +} + +SIM::PropertyHubPtr FilterPlugin::propertyHub() +{ + return m_propertyHub; +} + +QVariant FilterPlugin::value(const QString& key) +{ + return m_propertyHub->value(key); +} + +void FilterPlugin::setValue(const QString& key, const QVariant& v) +{ + m_propertyHub->setValue(key, v); +} diff --git a/plugins/filter/filter.h b/plugins/filter/filter.h new file mode 100644 index 0000000..6426610 --- /dev/null +++ b/plugins/filter/filter.h @@ -0,0 +1,68 @@ +/*************************************************************************** + filter.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _FILTER_H +#define _FILTER_H + +#include + +#include "cfg.h" +#include "event.h" +#include "plugins.h" +#include "propertyhub.h" + +class QWidget; + +struct FilterUserData +{ + SIM::Data SpamList; +}; + +class QStringList; + +class FilterPlugin : public QObject, public SIM::Plugin, public SIM::EventReceiver +{ + Q_OBJECT +public: + FilterPlugin(unsigned, Buffer *cfg); + virtual ~FilterPlugin(); + void setPropertyHub(SIM::PropertyHubPtr hub); + SIM::PropertyHubPtr propertyHub(); + QVariant value(const QString& key); + void setValue(const QString& key, const QVariant& v); + +protected slots: + void addToIgnore(void*); + +protected: + unsigned long user_data_id; + unsigned long CmdIgnoreList; + unsigned long CmdIgnore; + unsigned long CmdIgnoreText; + virtual bool processEvent(SIM::Event *e); + virtual QWidget *createConfigWindow(QWidget *parent); + virtual QByteArray getConfig(); + bool checkSpam(const QString &text, const QString &filter); + void getWords(const QString &text, QStringList &words, bool bPattern); + +private: + SIM::PropertyHubPtr m_propertyHub; + +}; + +#endif + diff --git a/plugins/filter/filter.rc b/plugins/filter/filter.rc new file mode 100644 index 0000000..51f8e63 --- /dev/null +++ b/plugins/filter/filter.rc @@ -0,0 +1,97 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,9,6,0 + PRODUCTVERSION 0,9,6,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Vladimir Shutoff\0" + VALUE "FileDescription", "Filter plugin\0" + VALUE "FileVersion", "0, 9, 6, 0\0" + VALUE "InternalName", "filter\0" + VALUE "LegalCopyright", "Copyright © 2002-2003\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "filter.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "SIM\0" + VALUE "ProductVersion", "0, 9, 6, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/filter/filter.vcproj b/plugins/filter/filter.vcproj new file mode 100644 index 0000000..de509d3 --- /dev/null +++ b/plugins/filter/filter.vcproj @@ -0,0 +1,500 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/filter/filtercfg.cpp b/plugins/filter/filtercfg.cpp new file mode 100644 index 0000000..3f4d819 --- /dev/null +++ b/plugins/filter/filtercfg.cpp @@ -0,0 +1,75 @@ +/*************************************************************************** + filtercfg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "misc.h" + +#include "filtercfg.h" +#include "filter.h" +#include "ignorelist.h" + +#include +#include +#include + +FilterConfig::FilterConfig(QWidget *parent, PropertyHubPtr data, FilterPlugin *plugin, bool bMain) + : QWidget(parent) + , m_data(data) + , m_plugin(plugin) + , m_ignore(NULL) +{ + setupUi(this); + if(bMain) + { + chkFromList->setChecked(m_plugin->value("FromList").toBool()); + chkAuthFromList->setChecked(m_plugin->value("AuthFromList").toBool()); + for (QObject *p = parent; p != NULL; p = p->parent()){ + QTabWidget *tab = qobject_cast(p); + if (!tab) + continue; + m_ignore = new IgnoreList(tab); + tab->addTab(m_ignore, i18n("Ignore list")); + break; + } + } + else + { + chkFromList->hide(); + chkAuthFromList->hide(); + lblFilter->hide(); + } + edtFilter->setPlainText(data->value("SpamList").toString()); +} + +FilterConfig::~FilterConfig() +{ +// do not delete - it gets deleted when QTabWidget (=parent) goes away +// delete m_ignore; +} + +void FilterConfig::apply() +{ + m_plugin->setValue("FromList", chkFromList->isChecked()); + m_plugin->setValue("AuthFromList", chkAuthFromList->isChecked()); + apply(m_data); +} + +void FilterConfig::apply(PropertyHubPtr data) +{ + //FilterUserData *data = (FilterUserData*)_data; + data->setValue("SpamList", edtFilter->toPlainText()); +} + diff --git a/plugins/filter/filtercfg.h b/plugins/filter/filtercfg.h new file mode 100644 index 0000000..bf49725 --- /dev/null +++ b/plugins/filter/filtercfg.h @@ -0,0 +1,46 @@ +/*************************************************************************** + filtercfg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _FILTERCFG_H +#define _FILTERCFG_H + +#include "ui_filtercfgbase.h" +#include "propertyhub.h" + +using namespace SIM; + +struct FilterUserData; +class FilterPlugin; +class IgnoreList; + +class FilterConfig : public QWidget, public Ui::FilterConfigBase +{ + Q_OBJECT +public: + FilterConfig(QWidget *parent, PropertyHubPtr data, FilterPlugin *plugin, bool bMain); + ~FilterConfig(); +public slots: + void apply(); + void apply(PropertyHubPtr); +protected: + PropertyHubPtr m_data; + FilterPlugin *m_plugin; + IgnoreList *m_ignore; +}; + +#endif + diff --git a/plugins/filter/filtercfgbase.ui b/plugins/filter/filtercfgbase.ui new file mode 100644 index 0000000..ba5b19b --- /dev/null +++ b/plugins/filter/filtercfgbase.ui @@ -0,0 +1,74 @@ + + + FilterConfigBase + + + + 0 + 0 + 392 + 253 + + + + Form1 + + + + 6 + + + 11 + + + + + &Receive message only from contacts from list + + + + + + + &Receive authorization and system messages only from contacts from list + + + + + + + Reject messages from unknown users contains this words or phrases: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + true + + + + + + + + + + Words are divided by any separators (space, comma, i.e.) +A phrase can be specified using quotation marks +Words can contain wildcards: +* - any amount of symbols (or is empty) +? - any symbol + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + true + + + + + + + + diff --git a/plugins/filter/ignorelist.cpp b/plugins/filter/ignorelist.cpp new file mode 100644 index 0000000..0fb8a95 --- /dev/null +++ b/plugins/filter/ignorelist.cpp @@ -0,0 +1,238 @@ +/*************************************************************************** + ignorelist.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "icons.h" +#include "log.h" +#include "misc.h" + +#include "ignorelist.h" +#include "contacts/contact.h" + +#include + +using namespace SIM; + +unsigned CmdListUnignore = 0x130001; + +IgnoreList::IgnoreList(QWidget *parent) : QWidget(parent) +{ + setupUi(this); + Command cmd; + cmd->id = CmdListUnignore; + cmd->text = I18N_NOOP("Unignore"); + cmd->icon = QString::null; + cmd->accel = QString::null; + cmd->bar_id = 0; + cmd->menu_id = MenuListView; + cmd->menu_grp = 0x1000; + cmd->flags = COMMAND_DEFAULT; + EventCommandCreate(cmd).process(); + + lstIgnore->addColumn(i18n("Contact")); + lstIgnore->addColumn(i18n("Name")); + lstIgnore->addColumn(i18n("EMail")); + connect(lstIgnore, SIGNAL(deleteItem(ListViewItem*)), this, SLOT(deleteItem(ListViewItem*))); + connect(lstIgnore, SIGNAL(dragStart()), this, SLOT(dragStart())); + connect(lstIgnore, SIGNAL(dragEnter(QMimeSource*)), this, SLOT(dragEnter(QMimeSource*))); + connect(lstIgnore, SIGNAL(drop(QMimeSource*)), this, SLOT(drop(QMimeSource*))); + Contact *contact; + ContactList::ContactIterator it; + while ((contact = ++it) != NULL){ + if (!contact->getIgnore()) + continue; + ListViewItem *item = new ListViewItem(lstIgnore); + updateItem(item, contact); + } +} + +bool IgnoreList::processEvent(Event *e) +{ + switch (e->type()){ + case eEventContact: { + EventContact *ec = static_cast(e); + Contact *contact = ec->contact(); + switch(ec->action()) { + case EventContact::eDeleted: { + removeItem(findItem(contact)); + break; + } + case EventContact::eCreated: { + ListViewItem *item = findItem(contact); + if (contact->getIgnore()){ + if (item == NULL) + item = new ListViewItem(lstIgnore); + updateItem(item, contact); + }else{ + removeItem(item); + } + break; + } + case EventContact::eChanged: { + if(contact->getIgnore()) { + ListViewItem *item = findItem(contact); + if(!item) { + if (item == NULL) + item = new ListViewItem(lstIgnore); + updateItem(item, contact); + } + } else { + ListViewItem *item = findItem(contact); + removeItem(item); + } + break; + } + default: + break; + } + break; + } + case eEventCommandExec: { + EventCommandExec *ece = static_cast(e); + CommandDef *cmd = ece->cmd(); + if ((cmd->id == CmdListUnignore) && (cmd->menu_id == MenuListView)){ + ListViewItem *item = (ListViewItem*)(cmd->param); + if (item->listView() == lstIgnore){ + unignoreItem(item); + return true; + } + } + break; + } + default: + break; + } + return false; +} + +void IgnoreList::updateItem(ListViewItem *item, Contact *contact) +{ + QString name = contact->getName(); + QString firstName = contact->getFirstName(); + QString lastName = contact->getLastName(); + firstName = getToken(firstName, '/'); + lastName = getToken(lastName, '/'); + if (!lastName.isEmpty()){ + if (!firstName.isEmpty()) + firstName += ' '; + firstName += lastName; + } + QString mail; + QString mails = contact->getEMails(); + while (mails.length()){ + QString mailItem = getToken(mails, ';'); + if (mail.length()) + mail += ','; + mail += getToken(mailItem, '/'); + } + unsigned style; + QString statusIcon; + contact->contactInfo(style, statusIcon); + item->setText(0, name); + item->setText(1, firstName); + item->setText(2, mail); + item->setText(3, QString::number(contact->id())); + item->setPixmap(0, Pict(statusIcon)); +} + +ListViewItem *IgnoreList::findItem(Contact *contact) +{ + for(int c = 0; c < lstIgnore->topLevelItemCount(); c++) + { + ListViewItem *item = static_cast(lstIgnore->topLevelItem(c)); + if (item->text(3).toUInt() == contact->id()) + return item; + } + return NULL; +} + +void IgnoreList::unignoreItem(ListViewItem *item) +{ + Contact *contact = getContacts()->contact(item->text(3).toUInt()); + if (contact) { + contact->setIgnore(false); + EventContact(contact, EventContact::eChanged).process(); + } +} + +void IgnoreList::deleteItem(ListViewItem *item) +{ + Contact *contact = getContacts()->contact(item->text(3).toUInt()); + if (contact) { + EventContact(contact,EventContact::eDeleted).process(); + } +} + +void IgnoreList::dragStart() +{ + ListViewItem *item = lstIgnore->currentItem(); + if (item == NULL) + return; +// Contact *contact = getContacts()->contact(item->text(3).toUInt()); +// if (contact) +// lstIgnore->startDrag(new ContactDragObject(lstIgnore, contact)); +} + +void IgnoreList::dragEnter(QMimeSource *s) +{ +// if (ContactDragObject::canDecode(s)){ +// Contact *contact = ContactDragObject::decode(s); +// if (contact){ +// if (!contact->getIgnore()){ +// log(L_DEBUG, "Set true"); +// lstIgnore->acceptDrop(true); +// return; +// } +// } +// } +// log(L_DEBUG, "Set false"); +// lstIgnore->acceptDrop(false); +} + +void IgnoreList::drop(QMimeSource *s) +{ + if (ContactDragObject::canDecode(s)){ + Contact *contact = ContactDragObject::decode(s); + if (contact){ + if (!contact->getIgnore()){ + contact->setIgnore(true); + EventContact(contact, EventContact::eChanged).process(); + return; + } + } + } +} + +void IgnoreList::removeItem(ListViewItem *item) +{ + if (item == NULL) + return; + /* + ListViewItem *nextItem = NULL; + if (item == lstIgnore->currentItem()){ + nextItem = item->nextSibling(); + if (nextItem == NULL){ + for (nextItem = lstIgnore->firstChild(); nextItem; nextItem = nextItem->nextSibling()) + if (nextItem->nextSibling() == item) + break; + } + } + */ + delete item; + //if (nextItem) + // lstIgnore->setCurrentItem(nextItem); +} + diff --git a/plugins/filter/ignorelist.h b/plugins/filter/ignorelist.h new file mode 100644 index 0000000..04a7216 --- /dev/null +++ b/plugins/filter/ignorelist.h @@ -0,0 +1,46 @@ +/*************************************************************************** + ignorelist.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _IGNORELIST_H +#define _IGNORELIST_H + +#include "ui_ignorelistbase.h" + +#include "event.h" + +class ListViewItem; + +class IgnoreList : public QWidget, public Ui::IgnoreListBase, public SIM::EventReceiver +{ + Q_OBJECT +public: + IgnoreList(QWidget *parent); +protected slots: + void deleteItem(ListViewItem*); + void dragStart(); + void dragEnter(QMimeSource*); + void drop(QMimeSource*); +protected: + virtual bool processEvent(SIM::Event *e); + void removeItem(ListViewItem*); + void updateItem(ListViewItem*, SIM::Contact*); + void unignoreItem(ListViewItem*); + ListViewItem *findItem(SIM::Contact*); +}; + +#endif + diff --git a/plugins/filter/ignorelistbase.ui b/plugins/filter/ignorelistbase.ui new file mode 100644 index 0000000..434fbb5 --- /dev/null +++ b/plugins/filter/ignorelistbase.ui @@ -0,0 +1,73 @@ + + + + + IgnoreListBase + + + + 0 + 0 + 373 + 223 + + + + Form2 + + + + 11 + + + 6 + + + + + + + + + QWidget + QWidget +
QWidget
+ + -1 + -1 + + 0 + + 5 + 5 + + image0 + + text + +
+ + ListView + QWidget +
simgui/listview.h
+ + -1 + -1 + + 0 + + 7 + 7 + + image1 +
+
+ + + 789c6dd2c10ac2300c00d07bbf2234b7229d1be245fc04c5a3201e4615f430059d0711ff5ddb2e6bb236ec90eed134cb5a19d8ef36602af5ecdbfeeac05dda0798d3abebde87e3faa374d3807fa0d633a52d38d8de6f679fe33fc776e196f53cd010188256a3600a292882096246517815ca99884606e18044a3a40d91824820924265a7923a2e8bcd05f33db1173e002913175f2a6be6d3294871a2d95fa00e8a94ee017b69d339d90df1e77c57ea072ede6758 + + + 789c6dd2c10ac2300c00d07bbf2234b7229d1ddec44f503c0ae2a154410f53d0ed20e2bf6bdb656dd6861dd23d9a66591b0587fd1654235ebded6f0edcd53e419d87ae7b1f4f9b8f906d0bfe012317426a70b07bdc2f3ec77f8ed6b89559061a0343d06a124cc105596482585094bc0ae599b04646c9018926491b2205e140c485cace25755c175d0a967b622ff900b8cc9c7d29af594ea722d589167f813aa852ba07d94b9dce296e883fe7bb163f23896753 + + +
diff --git a/plugins/flash/flash_win32.zip b/plugins/flash/flash_win32.zip new file mode 100644 index 0000000..21a80b9 Binary files /dev/null and b/plugins/flash/flash_win32.zip differ diff --git a/plugins/flash/flash_win32/FlashWnd.cpp b/plugins/flash/flash_win32/FlashWnd.cpp new file mode 100644 index 0000000..ed243fe --- /dev/null +++ b/plugins/flash/flash_win32/FlashWnd.cpp @@ -0,0 +1,156 @@ +/****************************************************************** +*** +*** +*** FREE WINDOWLESS FLASH CONTROL +*** +*** by Makarov Igor +*** +*** for questions and remarks mailto: mak_july@list.ru +*** +*** +*******************************************************************/ +// FlashWnd.cpp: implementation of the COleContainerWnd class. +// +////////////////////////////////////////////////////////////////////// + +//for help and reference see: http://www.codeproject.com/KB/COM/flashcontrol.aspx + + +#include "stdafx.h" +#include "FlashWnd.h" + +CFlashWnd::CFlashWnd() +{ + m_lVersion = 0; +} +CFlashWnd::~CFlashWnd() +{ +} + +//DShockwaveFlashEvents +HRESULT STDMETHODCALLTYPE CFlashWnd::OnReadyStateChange(long newState) +{ + return S_OK; +} +HRESULT STDMETHODCALLTYPE CFlashWnd::OnProgress(long percentDone) +{ + return S_OK; +} +HRESULT STDMETHODCALLTYPE CFlashWnd::FSCommand(_bstr_t command, _bstr_t args) +{ + return S_OK; +} + +void CFlashWnd::OnErrorClassNotReg() +{ + //some notification code here +} +BOOL CFlashWnd::OnBeforeShowingContent() +{ + m_lVersion = m_lpControl->FlashVersion(); + if ((m_lVersion & 0x00FF0000) == 0x00080000) + m_bFixTransparency = TRUE; + else + m_bFixTransparency = FALSE; + HRESULT hr; + hr = m_lpControl->QueryInterface(IID_IConnectionPointContainer, (void**)&m_lpConCont); + if (FAILED(hr)) + return FALSE; + hr = m_lpConCont->FindConnectionPoint(ShockwaveFlashObjects::DIID__IShockwaveFlashEvents, &m_lpConPoint); + if (FAILED(hr)) + return FALSE; + hr = m_lpConPoint->Advise((ShockwaveFlashObjects::_IShockwaveFlashEvents *)this, &m_dwConPointID); + if (FAILED(hr)) + return FALSE; + + if (m_bTransparent) + m_lpControl->PutWMode(L"transparent"); + m_lpControl->PutScale(L"showAll"); + m_lpControl->PutBackgroundColor(0x00000000); + m_lpControl->PutEmbedMovie(FALSE); + return TRUE; +} +BOOL CFlashWnd::OnAfterShowingContent() +{ + HRESULT hr; + m_lpControl->PutEmbedMovie(TRUE); + hr = m_lpControl->LoadMovie(0, L"http://www.djdean.de/dean_bot.swf"); +// hr = m_lpControl->LoadMovie(0, L"c:\\mailru.swf"); + if (FAILED(hr)) + return FALSE; + hr = m_lpControl->Play(); + if (FAILED(hr)) + return FALSE; + return TRUE; +} + +//IUnknown + +HRESULT STDMETHODCALLTYPE CFlashWnd::QueryInterface(REFIID riid, void ** ppvObject) +{ + HRESULT hr = COleContainerWnd::QueryInterface(riid, ppvObject); + if (hr != E_NOINTERFACE) + return hr; + if (IsEqualGUID(riid, ShockwaveFlashObjects::DIID__IShockwaveFlashEvents)) + *ppvObject = (void*)dynamic_cast(this); + else + { + *ppvObject = 0; + return E_NOINTERFACE; + } + if (!(*ppvObject)) + return E_NOINTERFACE; //if dynamic_cast returned 0 + m_iRef++; + return S_OK; +} + +ULONG STDMETHODCALLTYPE CFlashWnd::AddRef() +{ + m_iRef++; + return m_iRef; +} + +ULONG STDMETHODCALLTYPE CFlashWnd::Release() +{ + m_iRef--; + return m_iRef; +} + +//IDispatch +HRESULT STDMETHODCALLTYPE CFlashWnd::GetTypeInfoCount(UINT __RPC_FAR *pctinfo) +{ + NOTIMPLEMENTED; +} +HRESULT STDMETHODCALLTYPE CFlashWnd::GetTypeInfo( + /* [in] */ UINT iTInfo, + /* [in] */ LCID lcid, + /* [out] */ ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo) +{ + NOTIMPLEMENTED; +} +HRESULT STDMETHODCALLTYPE CFlashWnd::GetIDsOfNames( + /* [in] */ REFIID riid, + /* [size_is][in] */ LPOLESTR __RPC_FAR *rgszNames, + /* [in] */ UINT cNames, + /* [in] */ LCID lcid, + /* [size_is][out] */ DISPID __RPC_FAR *rgDispId) +{ + NOTIMPLEMENTED; +} +HRESULT STDMETHODCALLTYPE CFlashWnd::Invoke( + /* [in] */ DISPID dispIdMember, + /* [in] */ REFIID riid, + /* [in] */ LCID lcid, + /* [in] */ WORD wFlags, + /* [out][in] */ DISPPARAMS __RPC_FAR *pDispParams, + /* [out] */ VARIANT __RPC_FAR *pVarResult, + /* [out] */ EXCEPINFO __RPC_FAR *pExcepInfo, + /* [out] */ UINT __RPC_FAR *puArgErr) +{ +/* switch (dispIdMember) + { + default: + return S_OK; + }*/ + return S_OK; +} diff --git a/plugins/flash/flash_win32/FlashWnd.h b/plugins/flash/flash_win32/FlashWnd.h new file mode 100644 index 0000000..ae079a5 --- /dev/null +++ b/plugins/flash/flash_win32/FlashWnd.h @@ -0,0 +1,1018 @@ +/****************************************************************** +*** +*** +*** FREE WINDOWLESS FLASH CONTROL +*** +*** by Makarov Igor +*** +*** for questions and remarks mailto: mak_july@list.ru +*** +*** +*******************************************************************/ +// FlashWnd.h: interface for the CFlashWnd class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_FLASHWND_H__D74EA89B_5D79_4D87_8BB9_4DB90A5FE8FC__INCLUDED_) +#define AFX_FLASHWND_H__D74EA89B_5D79_4D87_8BB9_4DB90A5FE8FC__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +//#import "c:\\winnt\\system32\\macromed\\flash\\flash.ocx" named_guids + +#import "c:\\WINNT\\system32\\macromed\\flash\\Flash10a.ocx" named_guids no_auto_exclude + +#define NOTIMPLEMENTED return E_NOTIMPL + +#define OLECONTAINER_DEF template +#define OLECONTAINER_DEF2 TObj + +#define OLECONTAINER_CONSTRUCT OLECONTAINER_DEF COleContainerWnd +#define OLECONTAINER(type) OLECONTAINER_DEF type COleContainerWnd + +#define OLE_IUNKNOWN_DECLARE \ + int m_iRef; \ + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void ** ppvObject); \ + ULONG STDMETHODCALLTYPE AddRef(); \ + ULONG STDMETHODCALLTYPE Release(); + + +OLECONTAINER_DEF class COleContainerWnd : +/*virtual*/ public IOleClientSite, +/*virtual*/ public IOleInPlaceSiteWindowless, +/*virtual*/ public IOleInPlaceFrame, +/*virtual*/ public IStorage + +{ +public: + GUID m_CLSID; + TObj *m_lpControl; + IOleObject *m_lpO; + IViewObjectEx *m_lpViewObject; + IViewObjectEx *m_lpViewObjectEx; + IOleInPlaceObject *m_lpInPlaceObj; + IOleInPlaceObjectWindowless *m_lpInPlaceObjWindowless; + IConnectionPointContainer *m_lpConCont; + IConnectionPoint *m_lpConPoint; + + HWND m_hWnd, m_hWndParent; + HINSTANCE m_hInst; + + BOOL m_bChild; + BOOL m_bTransparent; + BOOL m_bFixTransparency; + DWORD m_dwConPointID; + HDC m_hdcBack; + HBITMAP m_bmpBack; + RECT m_rcBounds; + BYTE *m_lpBitsOnly; + int m_iBPP; + HDC m_hdcBackW; + HBITMAP m_bmpBackW; + BYTE *m_lpBitsOnlyW; +public: + COleContainerWnd(); + virtual ~COleContainerWnd(); + static LRESULT CALLBACK WndProcStatic(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); + LRESULT WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); + HWND GetHWND() { assert(m_hWnd); return m_hWnd; } + HWND GetParentWindow() { assert(m_hWndParent); return m_hWndParent; } + HWND GetInstance() { assert(m_hInst); return m_hInst; } +public: + virtual BOOL Create(GUID clsid, DWORD dwExStyle, DWORD dwStyle, HWND hWndParent, HINSTANCE hInst); + virtual void Draw(HDC hdcDraw, const RECT *rcDraw, BOOL bErase); + //ole container events + virtual void OnErrorClassNotReg(); + virtual BOOL OnBeforeShowingContent(); + virtual BOOL OnAfterShowingContent(); +public: + //interface methods + + //IUnknown + int m_iRef; + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void ** ppvObject); + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + + //IOleClientSite + virtual HRESULT STDMETHODCALLTYPE SaveObject(); + virtual HRESULT STDMETHODCALLTYPE GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, IMoniker ** ppmk); + virtual HRESULT STDMETHODCALLTYPE GetContainer(LPOLECONTAINER FAR* ppContainer); + virtual HRESULT STDMETHODCALLTYPE ShowObject(); + virtual HRESULT STDMETHODCALLTYPE OnShowWindow(BOOL fShow); + virtual HRESULT STDMETHODCALLTYPE RequestNewObjectLayout(); + + //IOleInPlaceSite + virtual HRESULT STDMETHODCALLTYPE GetWindow(HWND FAR* lphwnd); + virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode); + virtual HRESULT STDMETHODCALLTYPE CanInPlaceActivate(); + virtual HRESULT STDMETHODCALLTYPE OnInPlaceActivate(); + virtual HRESULT STDMETHODCALLTYPE OnUIActivate(); + virtual HRESULT STDMETHODCALLTYPE GetWindowContext(LPOLEINPLACEFRAME FAR* lplpFrame,LPOLEINPLACEUIWINDOW FAR* lplpDoc,LPRECT lprcPosRect,LPRECT lprcClipRect,LPOLEINPLACEFRAMEINFO lpFrameInfo); + virtual HRESULT STDMETHODCALLTYPE Scroll(SIZE scrollExtent); + virtual HRESULT STDMETHODCALLTYPE OnUIDeactivate(BOOL fUndoable); + virtual HRESULT STDMETHODCALLTYPE OnInPlaceDeactivate(); + virtual HRESULT STDMETHODCALLTYPE DiscardUndoState(); + virtual HRESULT STDMETHODCALLTYPE DeactivateAndUndo(); + virtual HRESULT STDMETHODCALLTYPE OnPosRectChange(LPCRECT lprcPosRect); + + //IOleInPlaceSiteEx + virtual HRESULT STDMETHODCALLTYPE OnInPlaceActivateEx(BOOL __RPC_FAR *pfNoRedraw, DWORD dwFlags); + virtual HRESULT STDMETHODCALLTYPE OnInPlaceDeactivateEx(BOOL fNoRedraw); + virtual HRESULT STDMETHODCALLTYPE RequestUIActivate(void); + + //IOleInPlaceSiteWindowless + virtual HRESULT STDMETHODCALLTYPE CanWindowlessActivate( void); + virtual HRESULT STDMETHODCALLTYPE GetCapture( void); + virtual HRESULT STDMETHODCALLTYPE SetCapture( + /* [in] */ BOOL fCapture); + virtual HRESULT STDMETHODCALLTYPE GetFocus( void); + virtual HRESULT STDMETHODCALLTYPE SetFocus( + /* [in] */ BOOL fFocus); + virtual HRESULT STDMETHODCALLTYPE GetDC( + /* [in] */ LPCRECT pRect, + /* [in] */ DWORD grfFlags, + /* [out] */ HDC __RPC_FAR *phDC); + virtual HRESULT STDMETHODCALLTYPE ReleaseDC( + /* [in] */ HDC hDC); + virtual HRESULT STDMETHODCALLTYPE InvalidateRect( + /* [in] */ LPCRECT pRect, + /* [in] */ BOOL fErase); + virtual HRESULT STDMETHODCALLTYPE InvalidateRgn( + /* [in] */ HRGN hRGN, + /* [in] */ BOOL fErase); + virtual HRESULT STDMETHODCALLTYPE ScrollRect( + /* [in] */ INT dx, + /* [in] */ INT dy, + /* [in] */ LPCRECT pRectScroll, + /* [in] */ LPCRECT pRectClip); + virtual HRESULT STDMETHODCALLTYPE AdjustRect( + /* [out][in] */ LPRECT prc); + virtual HRESULT STDMETHODCALLTYPE OnDefWindowMessage( + /* [in] */ UINT msg, + /* [in] */ WPARAM wParam, + /* [in] */ LPARAM lParam, + /* [out] */ LRESULT __RPC_FAR *plResult); + + //IOleInPlaceFrame +// virtual HRESULT STDMETHODCALLTYPE GetWindow(HWND FAR* lphwnd); +// virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode); + virtual HRESULT STDMETHODCALLTYPE GetBorder(LPRECT lprectBorder); + virtual HRESULT STDMETHODCALLTYPE RequestBorderSpace(LPCBORDERWIDTHS pborderwidths); + virtual HRESULT STDMETHODCALLTYPE SetBorderSpace(LPCBORDERWIDTHS pborderwidths); + virtual HRESULT STDMETHODCALLTYPE SetActiveObject(IOleInPlaceActiveObject *pActiveObject, LPCOLESTR pszObjName); + virtual HRESULT STDMETHODCALLTYPE InsertMenus(HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths); + virtual HRESULT STDMETHODCALLTYPE SetMenu(HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject); + virtual HRESULT STDMETHODCALLTYPE RemoveMenus(HMENU hmenuShared); + virtual HRESULT STDMETHODCALLTYPE SetStatusText(LPCOLESTR pszStatusText); + virtual HRESULT STDMETHODCALLTYPE EnableModeless(BOOL fEnable); + virtual HRESULT STDMETHODCALLTYPE TranslateAccelerator(LPMSG lpmsg, WORD wID); + + //IStorage + virtual HRESULT STDMETHODCALLTYPE CreateStream(const WCHAR *pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStream **ppstm); + virtual HRESULT STDMETHODCALLTYPE OpenStream(const WCHAR * pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream **ppstm); + virtual HRESULT STDMETHODCALLTYPE CreateStorage(const WCHAR *pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStorage **ppstg); + virtual HRESULT STDMETHODCALLTYPE OpenStorage(const WCHAR * pwcsName, IStorage * pstgPriority, DWORD grfMode, SNB snbExclude, DWORD reserved, IStorage **ppstg); + virtual HRESULT STDMETHODCALLTYPE CopyTo(DWORD ciidExclude, IID const *rgiidExclude, SNB snbExclude,IStorage *pstgDest); + virtual HRESULT STDMETHODCALLTYPE MoveElementTo(const OLECHAR *pwcsName,IStorage * pstgDest, const OLECHAR *pwcsNewName, DWORD grfFlags); + virtual HRESULT STDMETHODCALLTYPE Commit(DWORD grfCommitFlags); + virtual HRESULT STDMETHODCALLTYPE Revert(); + virtual HRESULT STDMETHODCALLTYPE EnumElements(DWORD reserved1, void * reserved2, DWORD reserved3, IEnumSTATSTG ** ppenum); + virtual HRESULT STDMETHODCALLTYPE DestroyElement(const OLECHAR *pwcsName); + virtual HRESULT STDMETHODCALLTYPE RenameElement(const WCHAR *pwcsOldName, const WCHAR *pwcsNewName); + virtual HRESULT STDMETHODCALLTYPE SetElementTimes(const WCHAR *pwcsName, FILETIME const *pctime, FILETIME const *patime, FILETIME const *pmtime); + virtual HRESULT STDMETHODCALLTYPE SetClass(REFCLSID clsid); + virtual HRESULT STDMETHODCALLTYPE SetStateBits(DWORD grfStateBits, DWORD grfMask); + virtual HRESULT STDMETHODCALLTYPE Stat(STATSTG * pstatstg, DWORD grfStatFlag); + + //IDispatch + virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount( + /* [out] */ UINT __RPC_FAR *pctinfo); + virtual HRESULT STDMETHODCALLTYPE GetTypeInfo( + /* [in] */ UINT iTInfo, + /* [in] */ LCID lcid, + /* [out] */ ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo); + virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames( + /* [in] */ REFIID riid, + /* [size_is][in] */ LPOLESTR __RPC_FAR *rgszNames, + /* [in] */ UINT cNames, + /* [in] */ LCID lcid, + /* [size_is][out] */ DISPID __RPC_FAR *rgDispId); + virtual /* [local] */ HRESULT STDMETHODCALLTYPE Invoke( + /* [in] */ DISPID dispIdMember, + /* [in] */ REFIID riid, + /* [in] */ LCID lcid, + /* [in] */ WORD wFlags, + /* [out][in] */ DISPPARAMS __RPC_FAR *pDispParams, + /* [out] */ VARIANT __RPC_FAR *pVarResult, + /* [out] */ EXCEPINFO __RPC_FAR *pExcepInfo, + /* [out] */ UINT __RPC_FAR *puArgErr); +}; + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +OLECONTAINER_CONSTRUCT::COleContainerWnd() +{ + m_lpControl = NULL; + m_lpO = NULL; + m_lpViewObjectEx = NULL; + m_lpViewObject = NULL; + m_lpInPlaceObj = NULL; + m_lpInPlaceObjWindowless = NULL; + m_lpConCont = NULL; + m_lpConPoint = NULL; + + m_hdcBack = NULL; + m_bmpBack = NULL; + m_hdcBackW = NULL; + m_bmpBackW = NULL; + m_rcBounds.left = m_rcBounds.top = m_rcBounds.right = m_rcBounds.bottom = 0; + m_lpBitsOnly = NULL; + m_lpBitsOnlyW = NULL; + m_iBPP = 0; + + m_dwConPointID = 0; + m_bTransparent = FALSE; + m_bFixTransparency = FALSE; + m_iRef = 0; +} + +OLECONTAINER_CONSTRUCT::~COleContainerWnd() +{ + if (m_lpControl) + { + if (m_lpConPoint) + { + if (m_dwConPointID) + m_lpConPoint->Unadvise(m_dwConPointID); + m_lpConPoint->Release(); + } + if (m_lpConCont) + m_lpConCont->Release(); + m_lpO->Close(OLECLOSE_NOSAVE); + if (m_lpViewObjectEx) + m_lpViewObjectEx->Release(); + if (m_lpViewObject) + m_lpViewObject->Release(); + if (m_lpInPlaceObjWindowless) + m_lpInPlaceObjWindowless->Release(); + if (m_lpInPlaceObj) + m_lpInPlaceObj->Release(); + if (m_lpO) + m_lpO->Release(); + m_lpControl->Release(); + } + if (m_hdcBack) + ::DeleteDC(m_hdcBack); + if (m_bmpBack) + ::DeleteObject(m_bmpBack); + if (m_hdcBackW) + ::DeleteDC(m_hdcBackW); + if (m_bmpBackW) + ::DeleteObject(m_bmpBackW); +} +OLECONTAINER(BOOL)::Create(GUID clsid, DWORD dwExStyle, DWORD dwStyle, HWND hWndParent, HINSTANCE hInst) +{ + m_hWndParent = hWndParent; + m_hInst = hInst; + + m_CLSID = clsid; + m_bTransparent = dwExStyle & WS_EX_LAYERED; + m_bChild = dwStyle & WS_CHILD; + + WNDCLASSEX wcs = {0}; + wcs.cbSize = sizeof(WNDCLASSEX); + wcs.lpfnWndProc = COleContainerWnd::WndProcStatic; + wcs.hInstance = hInst; + wcs.lpszClassName = "MyOleControl"; + RegisterClassEx(&wcs); + + RECT r; + if (m_bChild) + ::GetClientRect(hWndParent, &r); + else + ::GetWindowRect(hWndParent, &r); + m_hWnd = CreateWindowEx(dwExStyle, + "MyOleControl", "MyOleControlWindow", + dwStyle, + r.left, r.top, r.right-r.left, r.bottom-r.top, hWndParent, NULL, hInst, (void *)this); + ::SetWindowPos(GetHWND(), HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); + HRESULT hr; + hr = OleCreate(m_CLSID, IID_IOleObject, OLERENDER_DRAW, + 0, (IOleClientSite *)this, (IStorage *)this, (void **)&m_lpO); + if (FAILED(hr)) + { + if (hr == REGDB_E_CLASSNOTREG) + { + OnErrorClassNotReg(); + } + return FALSE; + } + hr = OleSetContainedObject(m_lpO, TRUE); + if (FAILED(hr)) + return FALSE; + hr = m_lpO->QueryInterface(__uuidof(TObj), (void **)&m_lpControl); + if (FAILED(hr)) + return FALSE; + hr = m_lpO->QueryInterface(IID_IViewObjectEx, (void **)&m_lpViewObjectEx); + if (FAILED(hr)) + { + m_lpViewObjectEx = NULL; + hr = m_lpO->QueryInterface(IID_IViewObject, (void **)&m_lpViewObject); + if (FAILED(hr)) + return FALSE; + } + if (m_bTransparent) + { + hr = m_lpO->QueryInterface(IID_IOleInPlaceObjectWindowless, (void **)&m_lpInPlaceObjWindowless); + if (FAILED(hr)) + { + hr = m_lpO->QueryInterface(IID_IOleInPlaceObject, (void **)&m_lpInPlaceObj); + if (FAILED(hr)) + return FALSE; + m_bTransparent = FALSE; + } + } + else + { + hr = m_lpO->QueryInterface(IID_IOleInPlaceObject, (void **)&m_lpInPlaceObj); + if (FAILED(hr)) + return FALSE; + } + if (!OnBeforeShowingContent()) + return FALSE; + hr = m_lpO->DoVerb(OLEIVERB_SHOW, NULL, (IOleClientSite *)this, 0, NULL, NULL); + if (FAILED(hr)) + return FALSE; + if (!OnAfterShowingContent()) + return FALSE; + return TRUE; +} + +//interface methods + +//IUnknown + +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::QueryInterface(REFIID riid, void ** ppvObject) +{ + if (IsEqualGUID(riid, IID_IUnknown)) + *ppvObject = (void*)(this); + else if (IsEqualGUID(riid, IID_IOleInPlaceSite)) + *ppvObject = (void*)dynamic_cast(this); + else if (IsEqualGUID(riid, IID_IOleInPlaceSiteEx)) + *ppvObject = (void*)dynamic_cast(this); + else if (IsEqualGUID(riid, IID_IOleInPlaceSiteWindowless)) + *ppvObject = (void*)dynamic_cast(this); + else if (IsEqualGUID(riid, IID_IOleInPlaceFrame)) + *ppvObject = (void*)dynamic_cast(this); + else if (IsEqualGUID(riid, IID_IStorage)) + *ppvObject = (void*)dynamic_cast(this); + else + { + *ppvObject = 0; + return E_NOINTERFACE; + } + if (!(*ppvObject)) + return E_NOINTERFACE; //if dynamic_cast returned 0 + m_iRef++; + return S_OK; +} + +OLECONTAINER(ULONG STDMETHODCALLTYPE)::AddRef() +{ + m_iRef++; + return m_iRef; +} + +OLECONTAINER(ULONG STDMETHODCALLTYPE)::Release() +{ + m_iRef--; + return m_iRef; +} + +//IOleClientSite + +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::SaveObject() { NOTIMPLEMENTED; } +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, IMoniker ** ppmk) { NOTIMPLEMENTED; } +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::GetContainer(LPOLECONTAINER FAR* ppContainer) +{ + *ppContainer = 0; + return E_NOINTERFACE; +} +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::ShowObject() +{ + return S_OK; +} +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::OnShowWindow(BOOL fShow) { NOTIMPLEMENTED; } +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::RequestNewObjectLayout() { NOTIMPLEMENTED; } + +//IOleInPlaceSite + +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::GetWindow(HWND FAR* lphwnd) +{ + *lphwnd = GetHWND(); + return S_OK; +} +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::ContextSensitiveHelp(BOOL fEnterMode) { NOTIMPLEMENTED; } +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::CanInPlaceActivate() +{ + return(S_OK); +} +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::OnInPlaceActivate() +{ + return(S_OK); +} +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::OnUIActivate() +{ + return(S_OK); +} +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::GetWindowContext(LPOLEINPLACEFRAME FAR* lplpFrame, LPOLEINPLACEUIWINDOW FAR* lplpDoc, LPRECT lprcPosRect, LPRECT lprcClipRect, LPOLEINPLACEFRAMEINFO lpFrameInfo) +{ + *lplpFrame = (LPOLEINPLACEFRAME)this; + + *lplpDoc = 0; + + lpFrameInfo->fMDIApp = FALSE; + lpFrameInfo->hwndFrame = GetHWND(); + lpFrameInfo->haccel = 0; + lpFrameInfo->cAccelEntries = 0; + + RECT r; + ::GetClientRect(GetHWND(), &r); + *lprcPosRect = r; + *lprcClipRect = r; + return(S_OK); +} +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::Scroll(SIZE scrollExtent) { NOTIMPLEMENTED; } +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::OnUIDeactivate(BOOL fUndoable) +{ + return(S_OK); +} +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::OnInPlaceDeactivate() +{ + return(S_OK); +} +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::DiscardUndoState() { NOTIMPLEMENTED; } +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::DeactivateAndUndo() { NOTIMPLEMENTED; } +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::OnPosRectChange(LPCRECT lprcPosRect) +{ + return(S_OK); +} + + +//IOleInPlaceSiteEx + +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::OnInPlaceActivateEx(BOOL __RPC_FAR *pfNoRedraw, DWORD dwFlags) +{ + if (pfNoRedraw) + *pfNoRedraw = FALSE; + return S_OK; +} +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::OnInPlaceDeactivateEx(BOOL fNoRedraw) +{ + return S_FALSE; +} +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::RequestUIActivate(void) +{ + return S_FALSE; +} + + +//IOleInPlaceSiteWindowless + +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::CanWindowlessActivate( void) +{ + return S_OK; +} +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::GetCapture( void) +{ + return S_FALSE; +} +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::SetCapture( + /* [in] */ BOOL fCapture) +{ + return S_FALSE; +} +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::GetFocus( void) +{ + return S_OK; +} +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::SetFocus( + /* [in] */ BOOL fFocus) +{ + return S_OK; +} +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::GetDC( + /* [in] */ LPCRECT pRect, + /* [in] */ DWORD grfFlags, + /* [out] */ HDC __RPC_FAR *phDC) +{ + return S_FALSE; +} +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::ReleaseDC( + /* [in] */ HDC hDC) +{ + return S_FALSE; +} +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::InvalidateRect( + /* [in] */ LPCRECT pRect, + /* [in] */ BOOL fErase) +{ + Draw(NULL, pRect, fErase); + return S_OK; +} +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::InvalidateRgn( + /* [in] */ HRGN hRGN, + /* [in] */ BOOL fErase) +{ + return S_OK; +} +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::ScrollRect( + /* [in] */ INT dx, + /* [in] */ INT dy, + /* [in] */ LPCRECT pRectScroll, + /* [in] */ LPCRECT pRectClip) +{ + NOTIMPLEMENTED; +} +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::AdjustRect( + /* [out][in] */ LPRECT prc) +{ + return S_FALSE; +} +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::OnDefWindowMessage( + /* [in] */ UINT msg, + /* [in] */ WPARAM wParam, + /* [in] */ LPARAM lParam, + /* [out] */ LRESULT __RPC_FAR *plResult) +{ + return S_FALSE; +} +OLECONTAINER(void)::Draw(HDC hdcDraw, const RECT *rcDraw, BOOL bErase) +{ + HWND hwnd = GetHWND(); + HRESULT hr; + RECT r; + + IOleObject *lpO = m_lpO; + IViewObject *lpV = m_lpViewObjectEx ? (IViewObject *)m_lpViewObjectEx : m_lpViewObject; + + if (!m_bTransparent) + { + RECT rTotal; + if (!::GetClientRect(hwnd, &rTotal)) + return; + if (lpV) + { + if (!hdcDraw) + { + hdcDraw = ::GetDC(hwnd); + hr = OleDraw(lpV, DVASPECT_CONTENT, hdcDraw, &rTotal); + ::ReleaseDC(hwnd, hdcDraw); + } + else + { + hr = OleDraw(lpV, DVASPECT_CONTENT, hdcDraw, &rTotal); + } + } + return; + } + + ::GetWindowRect(hwnd, &r); + if (!m_hdcBack || !EqualRect(&r, &m_rcBounds)) + { + if (m_hdcBack) + ::DeleteDC(m_hdcBack); + if (m_bmpBack) + ::DeleteObject(m_bmpBack); + if (m_hdcBackW) + ::DeleteDC(m_hdcBackW); + if (m_bmpBackW) + ::DeleteObject(m_bmpBackW); + m_rcBounds = r; + HDC hdc = ::GetDC(hwnd); + BITMAPINFOHEADER bih = {0}; + bih.biSize = sizeof(BITMAPINFOHEADER); + bih.biBitCount = 32; + bih.biCompression = BI_RGB; + bih.biPlanes = 1; + bih.biWidth = r.right - r.left; + bih.biHeight = -(r.bottom - r.top); + m_hdcBack = CreateCompatibleDC(hdc); + m_bmpBack = CreateDIBSection(hdc, (BITMAPINFO *)&bih, DIB_RGB_COLORS, (void **)&m_lpBitsOnly, NULL, 0x0); + SelectObject(m_hdcBack, m_bmpBack); + if (m_bFixTransparency) + { + m_hdcBackW = CreateCompatibleDC(hdc); + m_bmpBackW = CreateDIBSection(hdc, (BITMAPINFO *)&bih, DIB_RGB_COLORS, (void **)&m_lpBitsOnlyW, NULL, 0x0); + SelectObject(m_hdcBackW, m_bmpBackW); + } + ::ReleaseDC(hwnd, hdc); + if (m_iBPP == 0) + m_iBPP = GetDeviceCaps(m_hdcBack, BITSPIXEL); + } + POINT p = {r.left, r.top}; + POINT p2 = {0, 0}; + SIZE sz = {r.right-r.left, r.bottom-r.top}; + + if (lpO && lpV) + { + RECT rTotal; + ::GetClientRect(hwnd, &rTotal); + RECTL rcBounds = {rTotal.left, rTotal.top, rTotal.right, rTotal.bottom}; + BYTE *dst = m_lpBitsOnly, *dstW; + if (m_iBPP == 32) + { + if (!m_bFixTransparency) //if flash player version is other than 8, do usual painting + { + memset(m_lpBitsOnly, 0, sz.cx * sz.cy * 4); + hr = OleDraw(lpV, DVASPECT_TRANSPARENT, m_hdcBack, &rTotal); + } + else //if player version is 8, we need to fix flash player 8 control transparency bug + { + memset(m_lpBitsOnly, 0, sz.cx * sz.cy * 4); + memset(m_lpBitsOnlyW, 255, sz.cx * sz.cy * 4); + hr = OleDraw(lpV, DVASPECT_TRANSPARENT, m_hdcBack, &rTotal); + hr = OleDraw(lpV, DVASPECT_TRANSPARENT, m_hdcBackW, &rTotal); + dst = m_lpBitsOnly; + dstW = m_lpBitsOnlyW; + BYTE r, g, b, a, rw, gw, bw, aw, alpha_r, alpha_g, alpha_b, alpha; + for (int y = 0; y < sz.cy; y++) + { + for (int x = 0; x < sz.cx; x++) + { + //the idea is that we draw the same data onto black and white DC's + //and then calculate per pixel alpha based on difference, produced by alpha blending + r = *dst++; + g = *dst++; + b = *dst++; + a = *dst++; + rw = *dstW++; + gw = *dstW++; + bw = *dstW++; + aw = *dstW++; + alpha_r = rw-r; + alpha_g = gw-g; + alpha_b = bw-b; + //division by 3 is for accuracy and can be replaced by + //alpha = alpha_g; for example + alpha = (alpha_r + alpha_g + alpha_b) / 3; + *(dst - 1) = 255 - alpha; + //this algorithm should be optimized for MMX to achieve best performance + } + } + } + } + else //in 8/16/24 bit screen depth UpdateLayeredWindow produces wrong results - we use underlaying DC to paint to + { + HWND hwndParent = ::GetParent(hwnd); + HDC hdcParent = ::GetWindowDC(hwndParent); + BOOL bRet = BitBlt(m_hdcBack, 0, 0, rTotal.right, rTotal.bottom, hdcParent, 0, 0, SRCCOPY); + ::ReleaseDC(hwndParent, hdcParent); + hr = OleDraw(lpV, DVASPECT_TRANSPARENT, m_hdcBack, &rTotal); + dst = m_lpBitsOnly; + } + } + + BLENDFUNCTION bf; + bf.BlendOp = AC_SRC_OVER; + bf.AlphaFormat = AC_SRC_ALPHA; + bf.BlendFlags = 0; + bf.SourceConstantAlpha = 255; + BOOL bRet = UpdateLayeredWindow(hwnd, NULL, &p, &sz, m_hdcBack, &p2, 0, &bf, m_iBPP == 32 ? ULW_ALPHA : ULW_OPAQUE); +} + + +//IStorage + +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::CreateStream(const WCHAR *pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStream **ppstm) +{ + NOTIMPLEMENTED; +} + +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::OpenStream(const WCHAR * pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream **ppstm) +{ + NOTIMPLEMENTED; +} + +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::CreateStorage(const WCHAR *pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStorage **ppstg) +{ + NOTIMPLEMENTED; +} + +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::OpenStorage(const WCHAR * pwcsName, IStorage * pstgPriority, DWORD grfMode, SNB snbExclude, DWORD reserved, IStorage **ppstg) +{ + NOTIMPLEMENTED; +} + +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::CopyTo(DWORD ciidExclude, IID const *rgiidExclude, SNB snbExclude,IStorage *pstgDest) +{ + NOTIMPLEMENTED; +} + +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::MoveElementTo(const OLECHAR *pwcsName,IStorage * pstgDest, const OLECHAR *pwcsNewName, DWORD grfFlags) +{ + NOTIMPLEMENTED; +} + +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::Commit(DWORD grfCommitFlags) +{ + NOTIMPLEMENTED; +} + +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::Revert() +{ + NOTIMPLEMENTED; +} + +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::EnumElements(DWORD reserved1, void * reserved2, DWORD reserved3, IEnumSTATSTG ** ppenum) +{ + NOTIMPLEMENTED; +} + +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::DestroyElement(const OLECHAR *pwcsName) +{ + NOTIMPLEMENTED; +} + +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::RenameElement(const WCHAR *pwcsOldName, const WCHAR *pwcsNewName) +{ + NOTIMPLEMENTED; +} + +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::SetElementTimes(const WCHAR *pwcsName, FILETIME const *pctime, FILETIME const *patime, FILETIME const *pmtime) +{ + NOTIMPLEMENTED; +} + +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::SetClass(REFCLSID clsid) +{ + return(S_OK); +} + +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::SetStateBits(DWORD grfStateBits, DWORD grfMask) +{ + NOTIMPLEMENTED; +} + +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::Stat(STATSTG * pstatstg, DWORD grfStatFlag) +{ + NOTIMPLEMENTED; +} + + +//IOleInPlaceFrame + +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::GetBorder(LPRECT lprectBorder) +{ + NOTIMPLEMENTED; +} + +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::RequestBorderSpace(LPCBORDERWIDTHS pborderwidths) +{ + NOTIMPLEMENTED; +} + +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::SetBorderSpace(LPCBORDERWIDTHS pborderwidths) +{ + NOTIMPLEMENTED; +} + +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::SetActiveObject(IOleInPlaceActiveObject *pActiveObject, LPCOLESTR pszObjName) +{ + return(S_OK); +} + +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::InsertMenus(HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths) +{ + NOTIMPLEMENTED; +} + +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::SetMenu(HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject) +{ + return(S_OK); +} + +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::RemoveMenus(HMENU hmenuShared) +{ + NOTIMPLEMENTED; +} + +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::SetStatusText(LPCOLESTR pszStatusText) +{ + return(S_OK); +} + +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::EnableModeless(BOOL fEnable) +{ + return(S_OK); +} + +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::TranslateAccelerator(LPMSG lpmsg, WORD wID) +{ + NOTIMPLEMENTED; +} + + +//IDispatch +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::GetTypeInfoCount(UINT __RPC_FAR *pctinfo) +{ + NOTIMPLEMENTED; +} +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::GetTypeInfo( + /* [in] */ UINT iTInfo, + /* [in] */ LCID lcid, + /* [out] */ ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo) +{ + NOTIMPLEMENTED; +} +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::GetIDsOfNames( + /* [in] */ REFIID riid, + /* [size_is][in] */ LPOLESTR __RPC_FAR *rgszNames, + /* [in] */ UINT cNames, + /* [in] */ LCID lcid, + /* [size_is][out] */ DISPID __RPC_FAR *rgDispId) +{ + NOTIMPLEMENTED; +} +OLECONTAINER(HRESULT STDMETHODCALLTYPE)::Invoke( + /* [in] */ DISPID dispIdMember, + /* [in] */ REFIID riid, + /* [in] */ LCID lcid, + /* [in] */ WORD wFlags, + /* [out][in] */ DISPPARAMS __RPC_FAR *pDispParams, + /* [out] */ VARIANT __RPC_FAR *pVarResult, + /* [out] */ EXCEPINFO __RPC_FAR *pExcepInfo, + /* [out] */ UINT __RPC_FAR *puArgErr) +{ +/* switch (dispIdMember) + { + default: + return S_OK; + }*/ + return S_OK; +} + +OLECONTAINER(void)::OnErrorClassNotReg() +{ +} +OLECONTAINER(BOOL)::OnBeforeShowingContent() +{ + return TRUE; +} +OLECONTAINER(BOOL)::OnAfterShowingContent() +{ + return TRUE; +} + +OLECONTAINER(LRESULT CALLBACK)::WndProcStatic(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + if (uMsg == WM_CREATE) + { + LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam; + SetWindowLong(hWnd, GWL_USERDATA, (long)lpcs->lpCreateParams); + return 0; + } + COleContainerWnd *lpWnd = (COleContainerWnd *)GetWindowLong(hWnd, GWL_USERDATA); + if (lpWnd) + return lpWnd->WndProc(hWnd, uMsg, wParam, lParam); + else + return DefWindowProc(hWnd, uMsg, wParam, lParam); +} +OLECONTAINER(LRESULT)::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_CREATE: + { + LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam; + SetWindowLong(hWnd, GWL_USERDATA, (long)lpcs->lpCreateParams); + return 0; + } + break; + case WM_PAINT: + { + if (!m_bTransparent) + { + PAINTSTRUCT ps; + HDC hdc = ::BeginPaint(GetHWND(), &ps); + Draw(hdc, &ps.rcPaint, ps.fErase); + ::EndPaint(GetHWND(), &ps); + return 0; + } + } + break; + case WM_NCHITTEST: + { + int x = LOWORD(lParam), y = HIWORD(lParam); + if (m_lpO && m_lpViewObjectEx) + { + IViewObjectEx *lpV = m_lpViewObjectEx; + POINT p = {x, y}; + DWORD dwRes; + RECT rTotal; + GetWindowRect(GetHWND(), &rTotal); + HRESULT hr = lpV->QueryHitPoint(DVASPECT_CONTENT, &rTotal, p, 1, &dwRes); + if (hr == S_OK) + { + if (dwRes == HITRESULT_OUTSIDE) + return HTTRANSPARENT; + else + return HTCLIENT; + } + } + } + break; + case WM_SIZE: + { + HRESULT hr; + RECT rPos; + GetClientRect(GetHWND(), &rPos); + RECT rClip = rPos; + if (m_lpInPlaceObjWindowless) + hr = m_lpInPlaceObjWindowless->SetObjectRects(&rPos, &rClip); + else if (m_lpInPlaceObj) + hr = m_lpInPlaceObj->SetObjectRects(&rPos, &rClip); + return 0; + } + break; + } + if (m_lpInPlaceObjWindowless) + { + if (uMsg == WM_MOUSEMOVE || uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONUP || uMsg == WM_LBUTTONDBLCLK + || uMsg == WM_RBUTTONDOWN || uMsg == WM_RBUTTONUP || uMsg == WM_RBUTTONDBLCLK + || uMsg == WM_MBUTTONDOWN || uMsg == WM_MBUTTONUP || uMsg == WM_MBUTTONDBLCLK + || uMsg == WM_MOUSEWHEEL + || uMsg == WM_KEYDOWN || uMsg == WM_KEYUP || uMsg == WM_CHAR + || uMsg == WM_SETCURSOR + ) + { + HRESULT hr; + LRESULT res; + hr = m_lpInPlaceObjWindowless->OnWindowMessage(uMsg, wParam, lParam, &res); + if (hr == S_OK) + return res; + } + } + return DefWindowProc(hWnd, uMsg, wParam, lParam); +} + + +class CFlashWnd : + public COleContainerWnd, + public ShockwaveFlashObjects::_IShockwaveFlashEvents + +{ +public: + long m_lVersion; +public: + CFlashWnd(); + virtual ~CFlashWnd(); + + virtual void OnErrorClassNotReg(); + virtual BOOL OnBeforeShowingContent(); + virtual BOOL OnAfterShowingContent(); +public: + //IUnknown + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void ** ppvObject); + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + + //IDispatch + virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount( + /* [out] */ UINT __RPC_FAR *pctinfo); + virtual HRESULT STDMETHODCALLTYPE GetTypeInfo( + /* [in] */ UINT iTInfo, + /* [in] */ LCID lcid, + /* [out] */ ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo); + virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames( + /* [in] */ REFIID riid, + /* [size_is][in] */ LPOLESTR __RPC_FAR *rgszNames, + /* [in] */ UINT cNames, + /* [in] */ LCID lcid, + /* [size_is][out] */ DISPID __RPC_FAR *rgDispId); + virtual /* [local] */ HRESULT STDMETHODCALLTYPE Invoke( + /* [in] */ DISPID dispIdMember, + /* [in] */ REFIID riid, + /* [in] */ LCID lcid, + /* [in] */ WORD wFlags, + /* [out][in] */ DISPPARAMS __RPC_FAR *pDispParams, + /* [out] */ VARIANT __RPC_FAR *pVarResult, + /* [out] */ EXCEPINFO __RPC_FAR *pExcepInfo, + /* [out] */ UINT __RPC_FAR *puArgErr); + + //DShockwaveFlashEvents + HRESULT STDMETHODCALLTYPE OnReadyStateChange ( + long newState ); + HRESULT STDMETHODCALLTYPE OnProgress ( + long percentDone ); + HRESULT STDMETHODCALLTYPE FSCommand ( + _bstr_t command, + _bstr_t args ); +}; + +#endif // !defined(AFX_FLASHWND_H__D74EA89B_5D79_4D87_8BB9_4DB90A5FE8FC__INCLUDED_) diff --git a/plugins/flash/flash_win32/StdAfx.cpp b/plugins/flash/flash_win32/StdAfx.cpp new file mode 100644 index 0000000..0ddc873 --- /dev/null +++ b/plugins/flash/flash_win32/StdAfx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// flash.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/plugins/flash/flash_win32/StdAfx.h b/plugins/flash/flash_win32/StdAfx.h new file mode 100644 index 0000000..d86347d --- /dev/null +++ b/plugins/flash/flash_win32/StdAfx.h @@ -0,0 +1,47 @@ +/****************************************************************** +*** +*** +*** FREE WINDOWLESS FLASH CONTROL +*** +*** by Makarov Igor +*** +*** for questions and remarks mailto: mak_july@list.ru +*** +*** +*******************************************************************/ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#if !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_) +#define AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +//#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers + +#define WINVER 0x0500 +#define _WIN32_WINDOWS 0x0500 +#define _WIN32_WINNT 0x0500 + +// Windows Header Files: +#include + +// C RunTime Header Files +#include +#include +#include +#include +#include + +// Local Header Files + +// TODO: reference additional headers your program requires here + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_) diff --git a/plugins/flash/flash_win32/flash.cpp b/plugins/flash/flash_win32/flash.cpp new file mode 100644 index 0000000..47b7bf5 --- /dev/null +++ b/plugins/flash/flash_win32/flash.cpp @@ -0,0 +1,246 @@ +/****************************************************************** +*** +*** +*** FREE WINDOWLESS FLASH CONTROL +*** +*** by Makarov Igor +*** +*** for questions and remarks mailto: mak_july@list.ru +*** +*** +*******************************************************************/ +// flash.cpp : Defines the entry point for the application. +// + +#include "stdafx.h" +#include "resource.h" +#include "FlashWnd.h" + +#define MAX_LOADSTRING 100 + +// Global Variables: +HINSTANCE hInst; // current instance +TCHAR szTitle[MAX_LOADSTRING]; // The title bar text +TCHAR szWindowClass[MAX_LOADSTRING]; // The title bar text + +// Foward declarations of functions included in this code module: +ATOM MyRegisterClass(HINSTANCE hInstance); +BOOL InitInstance(HINSTANCE, int); +LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); +LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM); + +HWND g_hWnd = NULL; +HINSTANCE g_hInst = NULL; +CFlashWnd *g_flashWnd = NULL; + + +int APIENTRY WinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPSTR lpCmdLine, + int nCmdShow) +{ + // TODO: Place code here. + MSG msg; + HACCEL hAccelTable; + + // Initialize global strings + LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); + LoadString(hInstance, IDC_FLASH, szWindowClass, MAX_LOADSTRING); + MyRegisterClass(hInstance); + + // Perform application initialization: + if (!InitInstance (hInstance, nCmdShow)) + { + return FALSE; + } + + g_hInst = hInst; + + hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_FLASH); + + OleInitialize(NULL); + + g_flashWnd = new CFlashWnd; + +//create windowless control + g_flashWnd->Create(ShockwaveFlashObjects::CLSID_ShockwaveFlash, + WS_EX_LAYERED, WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS, + g_hWnd, g_hInst); + +//to create a windowed control uncomment this +// g_flashWnd->Create(ShockwaveFlashObjects::CLSID_ShockwaveFlash, +// 0, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS, +// g_hWnd, g_hInst); + + // Main message loop: + while (GetMessage(&msg, NULL, 0, 0)) + { + if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + delete g_flashWnd; + + OleUninitialize(); + + return msg.wParam; +} + + + +// +// FUNCTION: MyRegisterClass() +// +// PURPOSE: Registers the window class. +// +// COMMENTS: +// +// This function and its usage is only necessary if you want this code +// to be compatible with Win32 systems prior to the 'RegisterClassEx' +// function that was added to Windows 95. It is important to call this function +// so that the application will get 'well formed' small icons associated +// with it. +// +ATOM MyRegisterClass(HINSTANCE hInstance) +{ + WNDCLASSEX wcex; + + wcex.cbSize = sizeof(WNDCLASSEX); + + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpfnWndProc = (WNDPROC)WndProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = hInstance; + wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_FLASH); + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wcex.lpszMenuName = (LPCSTR)IDC_FLASH; + wcex.lpszClassName = szWindowClass; + wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL); + + return RegisterClassEx(&wcex); +} + +// +// FUNCTION: InitInstance(HANDLE, int) +// +// PURPOSE: Saves instance handle and creates main window +// +// COMMENTS: +// +// In this function, we save the instance handle in a global variable and +// create and display the main program window. +// +BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) +{ + HWND hWnd; + + hInst = hInstance; // Store instance handle in our global variable + + hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, + CW_USEDEFAULT, CW_USEDEFAULT, 300, 200, NULL, NULL, hInstance, NULL); + + if (!hWnd) + { + return FALSE; + } + + ShowWindow(hWnd, nCmdShow); + UpdateWindow(hWnd); + + g_hWnd = hWnd; + + return TRUE; +} + +// +// FUNCTION: WndProc(HWND, unsigned, WORD, LONG) +// +// PURPOSE: Processes messages for the main window. +// +// WM_COMMAND - process the application menu +// WM_PAINT - Paint the main window +// WM_DESTROY - post a quit message and return +// +// +LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + int wmId, wmEvent; + PAINTSTRUCT ps; + HDC hdc; + TCHAR szHello[MAX_LOADSTRING]; + LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING); + + switch (message) + { + case WM_COMMAND: + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + // Parse the menu selections: + switch (wmId) + { + case IDM_ABOUT: + DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About); + break; + case IDM_EXIT: + DestroyWindow(hWnd); + break; + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + break; + case WM_PAINT: + hdc = BeginPaint(hWnd, &ps); + // TODO: Add any drawing code here... + RECT rt; + GetClientRect(hWnd, &rt); + DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + EndPaint(hWnd, &ps); + break; + case WM_DESTROY: + PostQuitMessage(0); + break; + case WM_MOVE: + { + RECT r; + GetWindowRect(hWnd, &r); + if (g_flashWnd) + SetWindowPos(g_flashWnd->GetHWND(), NULL, r.left, r.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER); + } + break; + case WM_SIZE: + { + RECT r; + GetWindowRect(hWnd, &r); + if (g_flashWnd) + SetWindowPos(g_flashWnd->GetHWND(), NULL, 0, 0, (r.right-r.left), (r.bottom-r.top), SWP_NOMOVE | SWP_NOZORDER); + } + break; + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + return 0; +} + +// Mesage handler for about box. +LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_INITDIALOG: + return TRUE; + + case WM_COMMAND: + if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) + { + EndDialog(hDlg, LOWORD(wParam)); + return TRUE; + } + break; + } + return FALSE; +} diff --git a/plugins/flash/flash_win32/flash.h b/plugins/flash/flash_win32/flash.h new file mode 100644 index 0000000..161c424 --- /dev/null +++ b/plugins/flash/flash_win32/flash.h @@ -0,0 +1,23 @@ +/****************************************************************** +*** +*** +*** FREE WINDOWLESS FLASH CONTROL +*** +*** by Makarov Igor +*** +*** for questions and remarks mailto: mak_july@list.ru +*** +*** +*******************************************************************/ + +#if !defined(AFX_FLASH_H__03637834_4B49_478B_98FD_E7B146E19D99__INCLUDED_) +#define AFX_FLASH_H__03637834_4B49_478B_98FD_E7B146E19D99__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "resource.h" + + +#endif // !defined(AFX_FLASH_H__03637834_4B49_478B_98FD_E7B146E19D99__INCLUDED_) diff --git a/plugins/flash/flash_win32/flash.ico b/plugins/flash/flash_win32/flash.ico new file mode 100644 index 0000000..3868835 Binary files /dev/null and b/plugins/flash/flash_win32/flash.ico differ diff --git a/plugins/flash/flash_win32/flash.rc b/plugins/flash/flash_win32/flash.rc new file mode 100644 index 0000000..c1da62e --- /dev/null +++ b/plugins/flash/flash_win32/flash.rc @@ -0,0 +1,135 @@ +//Microsoft Visual C++ generated resource script. +// + +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#define APSTUDIO_HIDDEN_SYMBOLS +#include "windows.h" +#undef APSTUDIO_HIDDEN_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE 9, 1 +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. + +IDI_FLASH ICON DISCARDABLE "flash.ICO" +IDI_SMALL ICON DISCARDABLE "SMALL.ICO" + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDC_FLASH MENU DISCARDABLE +BEGIN + POPUP "&File" + BEGIN + MENUITEM "E&xit", IDM_EXIT + END + POPUP "&Help" + BEGIN + MENUITEM "&About ...", IDM_ABOUT + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +IDC_FLASH ACCELERATORS MOVEABLE PURE +BEGIN + "?", IDM_ABOUT, ASCII, ALT + "/", IDM_ABOUT, ASCII, ALT +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUTBOX DIALOG DISCARDABLE 22, 17, 230, 75 +STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU +CAPTION "About" +FONT 8, "System" +BEGIN + ICON IDI_FLASH,IDC_MYICON,14,9,16,16 + LTEXT "flash Version 1.0",IDC_STATIC,49,10,119,8,SS_NOPREFIX + LTEXT "Copyright (C) 2006",IDC_STATIC,49,20,119,8 + DEFPUSHBUTTON "OK",IDOK,195,6,30,11,WS_GROUP +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""windows.h""\r\n" + "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""resource.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + IDC_FLASH "FLASH" + IDS_APP_TITLE "flash" + IDS_HELLO "Hello World!" +END + +#endif +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/flash/flash_win32/flash.sln b/plugins/flash/flash_win32/flash.sln new file mode 100644 index 0000000..1bc809b --- /dev/null +++ b/plugins/flash/flash_win32/flash.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "flash", "flash.vcproj", "{2561D961-FBDC-4DC5-9F47-F9300CC74D03}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2561D961-FBDC-4DC5-9F47-F9300CC74D03}.Debug|Win32.ActiveCfg = Debug|Win32 + {2561D961-FBDC-4DC5-9F47-F9300CC74D03}.Debug|Win32.Build.0 = Debug|Win32 + {2561D961-FBDC-4DC5-9F47-F9300CC74D03}.Release|Win32.ActiveCfg = Release|Win32 + {2561D961-FBDC-4DC5-9F47-F9300CC74D03}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/flash/flash_win32/flash.vcproj b/plugins/flash/flash_win32/flash.vcproj new file mode 100644 index 0000000..f4f33d5 --- /dev/null +++ b/plugins/flash/flash_win32/flash.vcproj @@ -0,0 +1,335 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/flash/flash_win32/resource.h b/plugins/flash/flash_win32/resource.h new file mode 100644 index 0000000..87afef1 --- /dev/null +++ b/plugins/flash/flash_win32/resource.h @@ -0,0 +1,27 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by FLASH.RC +// +#define IDR_MAINFRAME 128 +#define IDD_FLASH_DIALOG 102 +#define IDD_ABOUTBOX 103 +#define IDS_APP_TITLE 103 +#define IDM_ABOUT 104 +#define IDM_EXIT 105 +#define IDS_HELLO 106 +#define IDI_FLASH 107 +#define IDI_SMALL 108 +#define IDC_FLASH 109 +#define IDC_MYICON 2 +#define IDC_STATIC -1 +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS + +#define _APS_NEXT_RESOURCE_VALUE 129 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 110 +#endif +#endif diff --git a/plugins/flash/flash_win32/small.ico b/plugins/flash/flash_win32/small.ico new file mode 100644 index 0000000..8f94d9a Binary files /dev/null and b/plugins/flash/flash_win32/small.ico differ diff --git a/plugins/floaty/CMakeLists.txt b/plugins/floaty/CMakeLists.txt new file mode 100644 index 0000000..853b660 --- /dev/null +++ b/plugins/floaty/CMakeLists.txt @@ -0,0 +1,23 @@ +################## +# floaty library # +################## +IF(BUILD_DROPPED) +SET(floaty_SRCS + floaty.cpp + floatywnd.cpp +) + +SET(floaty_HDRS + floaty.h + floatywnd.h +) + +SET(floaty_LIBS + _core +) + +REMOVE_DEFINITIONS(-DQT3_SUPPORT) +REMOVE_DEFINITIONS(-DQT_3SUPPORT_LIB) +REMOVE_DEFINITIONS(-DQT3_SUPPORT_WARNINGS) +SIM_ADD_PLUGIN(floaty) +ENDIF(BUILD_DROPPED) diff --git a/plugins/floaty/floaty.cpp b/plugins/floaty/floaty.cpp new file mode 100644 index 0000000..33c6084 --- /dev/null +++ b/plugins/floaty/floaty.cpp @@ -0,0 +1,250 @@ +/*************************************************************************** + floaty.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "floaty.h" +#include "floatywnd.h" + +#include "core.h" + +#include "contacts/contact.h" + +#include +#include +#include +#include +#include + +using namespace SIM; + +const unsigned BLINK_TIMEOUT = 500; +const unsigned BLINK_COUNT = 8; + +Plugin *createFloatyPlugin(unsigned base, bool, Buffer*) +{ + FloatyPlugin *plugin = new FloatyPlugin(base); + return plugin; +} + +static PluginInfo info = + { + I18N_NOOP("Floaty"), + I18N_NOOP("Plugin provides floating windows for contacts"), + VERSION, + createFloatyPlugin, + PLUGIN_DEFAULT + }; + +EXPORT_PROC PluginInfo* GetPluginInfo() +{ + return &info; +} + +static DataDef floatyUserData[] = + { + { "FloatyPosition", DATA_LONG, 2, DATA((unsigned long)-1>>1)}, // 0x7FFFFFFF - maximum value of sigend long + { NULL, DATA_UNKNOWN, 0, 0 } + }; + +FloatyPlugin::FloatyPlugin(unsigned base) + : Plugin(base) +{ + CmdFloaty = registerType(); + user_data_id = getContacts()->registerUserData(info.title, floatyUserData); + + m_bBlink = false; + unreadTimer = new QTimer(this); + connect(unreadTimer, SIGNAL(timeout()), this, SLOT(unreadBlink())); + + Command cmd; + cmd->id = CmdFloaty; + cmd->text = I18N_NOOP("Floating on"); + cmd->icon = "floating"; + cmd->menu_id = MenuContact; + cmd->menu_grp = 0xB000; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); +} + +FloatyPlugin::~FloatyPlugin() +{ + qDeleteAll(m_floaties); + EventCommandRemove(CmdFloaty).process(); + getContacts()->unregisterUserData(user_data_id); +} + +bool FloatyPlugin::processEvent(Event *e) +{ + switch (e->type()){ + case eEventInit:{ + Contact *contact; + ContactList::ContactIterator it; + while ((contact = ++it) != NULL){ + SIM::PropertyHubPtr data = contact->getUserData("floaty", false); + if (!data) + continue; + FloatyWnd *wnd = new FloatyWnd(this, contact->id()); + m_floaties.insert(contact->id(), wnd); + ((QWidget*)wnd)->move(data->value("X").toInt(), data->value("Y").toInt()); + wnd->show(); + } + break; + } + case eEventCheckCommandState:{ + EventCheckCommandState *ecs = static_cast(e); + CommandDef *cmd = ecs->cmd(); + if (cmd->id == CmdFloaty){ + Contact *contact = getContacts()->contact((unsigned long)(cmd->param)); + if (contact){ + SIM::PropertyHubPtr data = contact->getUserData("floaty", false); + if (data) + { + cmd->text = I18N_NOOP("Floating off"); + cmd->flags |= COMMAND_CHECKED; + }else{ + cmd->text = I18N_NOOP("Floating on"); + cmd->flags &= ~COMMAND_CHECKED; + } + } + return true; + } + break; + } + case eEventCommandExec:{ + EventCommandExec *ece = static_cast(e); + CommandDef *cmd = ece->cmd(); + if (cmd->id == CmdFloaty){ + Contact *contact = getContacts()->contact((unsigned long)(cmd->param)); + if (contact){ + SIM::PropertyHubPtr data = contact->getUserData("floaty", false); + if (data) + { + FloatyWnd *wnd = m_floaties.take(contact->id()); + delete wnd; + } + else + { + data = contact->getUserData("floaty", true); + QRect r = QApplication::desktop()->availableGeometry(); + data->setValue("X", r.x()); + data->setValue("Y", r.y()); + FloatyWnd *wnd = new FloatyWnd(this, (unsigned long)(cmd->param)); + m_floaties.insert((unsigned long)(cmd->param), wnd); + ((QWidget*)wnd)->move(r.x(), r.y()); + wnd->show(); + } + } + return true; + } + break; + } + case eEventMessageDeleted: + case eEventMessageRead: + case eEventMessageReceived:{ + EventMessage *em = static_cast(e); + Message *msg = em->msg(); + FloatyWnd *wnd = m_floaties.value(msg->contact()); + if (wnd){ + wnd->init(); + wnd->repaint(); + } + break; + } + case eEventContactClient: { + EventContactClient *ecc = static_cast(e); + Contact *contact = ecc->contact(); + if(!contact) + break; + FloatyWnd *wnd = m_floaties.value(contact->id()); + if (wnd){ + wnd->init(); + wnd->repaint(); + } + break; + } + case eEventContact: { + EventContact *ec = static_cast(e); + Contact *contact = ec->contact(); + FloatyWnd *wnd = m_floaties.value(contact->id()); + if(!wnd) + break; + switch(ec->action()) { + case EventContact::eDeleted: + delete wnd; + break; + case EventContact::eStatus: + case EventContact::eChanged: + wnd->init(); + wnd->repaint(); + break; + case EventContact::eOnline: + wnd->startBlink(); + break; + default: + break; + } + break; + } + case eEventRepaintView:{ + QHashIterator it(m_floaties); + while(it.hasNext()) + { + FloatyWnd *wnd = it.next().value(); + wnd->init(); + wnd->repaint(); + } + break; + } + default: + break; + } + return false; +} + +void FloatyPlugin::showPopup() +{ + EventMenuProcess eMenu(MenuContact, (void*)popupId); + eMenu.process(); + QMenu *popup = eMenu.menu(); + if(popup) + popup->popup(popupPos); +} + +void FloatyPlugin::startBlink() +{ + if (unreadTimer->isActive()) + return; + m_bBlink = true; + unreadTimer->start(800); +} + +void FloatyPlugin::unreadBlink() +{ + m_bBlink = !m_bBlink; + QHashIterator it(m_floaties); + while(it.hasNext()) + { + FloatyWnd *wnd = it.next().value(); + wnd->repaint(); + } +} + +void FloatyWnd::startBlink() +{ + m_blink = BLINK_COUNT * 2 + 1; + blinkTimer->start(BLINK_TIMEOUT); + repaint(); +} diff --git a/plugins/floaty/floaty.h b/plugins/floaty/floaty.h new file mode 100644 index 0000000..a526535 --- /dev/null +++ b/plugins/floaty/floaty.h @@ -0,0 +1,63 @@ +/*************************************************************************** + floaty.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _FLOATY_H +#define _FLOATY_H + +#include +#include +#include + +#include "cfg.h" +#include "event.h" +#include "plugins.h" + +class QTimer; + +struct FloatyUserData +{ + SIM::Data X; + SIM::Data Y; +}; + +class FloatyWnd; +class QTimer; + +class FloatyPlugin : public QObject, public SIM::Plugin, public SIM::EventReceiver +{ + Q_OBJECT +public: + FloatyPlugin(unsigned); + virtual ~FloatyPlugin(); + bool m_bBlink; + void startBlink(); +protected slots: + void showPopup(); + void unreadBlink(); +protected: + virtual bool processEvent(SIM::Event *e); + unsigned long CmdFloaty; + unsigned long user_data_id; + QPoint popupPos; + QTimer *unreadTimer; + unsigned long popupId; + QHash m_floaties; + friend class FloatyWnd; +}; + +#endif + diff --git a/plugins/floaty/floaty.rc b/plugins/floaty/floaty.rc new file mode 100644 index 0000000..116b990 --- /dev/null +++ b/plugins/floaty/floaty.rc @@ -0,0 +1,97 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,9,6,0 + PRODUCTVERSION 0,9,6,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Vladimir Shutoff\0" + VALUE "FileDescription", "Floaty plugin\0" + VALUE "FileVersion", "0, 9, 6, 0\0" + VALUE "InternalName", "floaty\0" + VALUE "LegalCopyright", "Copyright © 2002-2003\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "floaty.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "SIM\0" + VALUE "ProductVersion", "0, 9, 6, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/floaty/floaty.vcproj b/plugins/floaty/floaty.vcproj new file mode 100644 index 0000000..d549bc7 --- /dev/null +++ b/plugins/floaty/floaty.vcproj @@ -0,0 +1,374 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/floaty/floatywnd.cpp b/plugins/floaty/floatywnd.cpp new file mode 100644 index 0000000..c040773 --- /dev/null +++ b/plugins/floaty/floatywnd.cpp @@ -0,0 +1,560 @@ +/*************************************************************************** + floatywnd.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "simapi.h" +#include + +#include "floatywnd.h" +#include "floaty.h" +#include "contacts/contact.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef USE_KDE +#include +#endif + +#include "icons.h" +#include "simgui/linklabel.h" +#include "userview.h" +#include "core.h" + +using namespace std; +using namespace SIM; + +namespace { namespace aux { + +static QString +compose_floaty_name( unsigned long id ) +{ + return QString( "floaty-%1" ).arg( id ); +} + +}} + +FloatyWnd::FloatyWnd(FloatyPlugin *plugin, unsigned long id) + : QWidget(NULL, + Qt::Tool + | Qt::WindowStaysOnTopHint + | Qt::CustomizeWindowHint + | Qt::FramelessWindowHint + | Qt::Tool + | Qt::X11BypassWindowManagerHint + ) +{ + setAttribute(Qt::WA_MacAlwaysShowToolWindow); + setAttribute(Qt::WA_AlwaysShowToolTips); + setObjectName(aux::compose_floaty_name( id ) ); + m_plugin = plugin; + m_id = id; + m_blink = 0; + b_ignoreMouseClickRelease=false; + init(); + setAcceptDrops(true); +#ifdef USE_KDE + KWin::setState(winId(), NET::SkipTaskbar | NET::SkipPager); + KWin::setOnAllDesktops(winId(), true); +#endif + moveTimer = new QTimer(this); + connect(moveTimer, SIGNAL(timeout()), this, SLOT(startMove())); + blinkTimer = new QTimer(this); + connect(blinkTimer, SIGNAL(timeout()), this, SLOT(blink())); + setMouseTracking(true); +} + +FloatyWnd::~FloatyWnd() +{ + delete moveTimer; + delete blinkTimer; +} + +void FloatyWnd::init() +{ + m_style = 0; + m_icons.clear(); + m_unread = 0; + Contact *contact = getContacts()->contact(m_id); + if (contact == NULL) + return; + m_text = contact->getName(); + m_status = contact->contactInfo(m_style, m_statusIcon, &m_icons); + unsigned blink = m_blink; + m_blink = 1; + m_blink = blink; + QFontMetrics metr(font()); + QRect br = metr.boundingRect(m_text); + int h = br.height(); + int w = br.width() + 5; + const QPixmap &pict = Pict(m_statusIcon); + w += pict.width() + 2; + if (pict.height() > h) + h = pict.height(); + Q_FOREACH(const QString &icon, m_icons) { + const QPixmap &pict = Pict(icon); + w += pict.width() + 2; + if (pict.height() > h) + h = pict.height(); + } + w += 15; + h += 6; + resize(w, h); + CorePlugin *core = GET_CorePlugin(); + for (list::iterator it = core->unread.begin(); it != core->unread.end(); ++it){ + if (it->contact != m_id) + continue; + m_unread = it->type; + m_plugin->startBlink(); + break; + } +} + +void FloatyWnd::paintEvent(QPaintEvent*) +{ + int w = width() - 4; + int h = height() - 4; + + QPixmap pict(w, h); + QPainter p(&pict); + p.fillRect(QRect(0, 0, width(), height()), palette().brush(QPalette::Base)); + EventPaintView::PaintView pv; + pv.p = &p; + pv.pos = QPoint(2, 2); + pv.size = QSize(w, h); + pv.win = this; + pv.isStatic = false; + pv.height = h; + CorePlugin *core = GET_CorePlugin(); + if (core->value("UseSysColors").toBool()){ + p.setPen(palette().color(QPalette::Text)); + }else{ + p.setPen(QColor(core->value("ColorOnline").toUInt())); + } + EventPaintView e(&pv); + e.process(); + + if (core->value("UseSysColors").toBool()){ + if (m_status != STATUS_ONLINE) + p.setPen(palette().color(QPalette::Disabled, QPalette::Text)); + }else{ + switch (m_status){ + case STATUS_ONLINE: + p.setPen(core->value("ColorOnline").toUInt()); + break; + case STATUS_AWAY: + p.setPen(core->value("ColorAway").toUInt()); + break; + case STATUS_NA: + p.setPen(core->value("ColorNA").toUInt()); + break; + case STATUS_DND: + p.setPen(core->value("ColorDND").toUInt()); + break; + default: + p.setPen(core->value("ColorOffline").toUInt()); + break; + } + } + + int x = 0; + QString statusIcon = m_statusIcon; + if (m_unread && m_plugin->m_bBlink){ + CommandDef *def = core->messageTypes.find(m_unread); + if (def) + statusIcon = def->icon; + } + + if (!statusIcon.isEmpty()){ + const QPixmap &pict = Pict(statusIcon); + x += 2; + p.drawPixmap(x, (h - pict.height()) / 2, pict); + x += pict.width() + 2; + } + QRect br; + setFont(&p); + p.drawText(x, 0, w, h, Qt::AlignLeft | Qt::AlignVCenter, m_text, &br); + x = br.right() + 5; + Q_FOREACH(const QString &icon, m_icons) { + const QPixmap &pict = Pict(icon); + x += 2; + p.drawPixmap(x, (h - pict.height()) / 2, pict); + x += pict.width(); + } + p.end(); + + p.begin(this); + p.drawPixmap(QPoint(2, 2), pict); + + p.setPen(palette().color(QPalette::Dark)); + p.drawLine(1, 1, width() - 2, 1); + p.drawLine(width() - 2, 1, width() - 2, height() - 2); + p.drawLine(width() - 2, height() - 2, 1, height() - 2); + p.drawLine(1, height() - 2, 1, 1); + + p.setPen(palette().color(QPalette::Shadow)); + p.drawLine(0, height() - 1, width() - 1, height() - 1); + p.drawLine(width() - 1, height() - 1, width() - 1, 1); + p.drawLine(width() - 3, 2, 2, 2); + p.drawLine(2, 2, 2, height() - 3); + + p.setPen(palette().color(QPalette::Light)); + p.drawLine(2, height() - 3, width() - 3, height() - 3); + p.drawLine(width() - 3, height() - 3, width() - 3, 2); + p.drawLine(width() - 1, 0, 0, 0); + p.drawLine(0, 0, 0, height() - 1); +} + +void FloatyWnd::setFont(QPainter *p) +{ + QFont f(font()); + CorePlugin *core = GET_CorePlugin(); + if (m_style & CONTACT_ITALIC){ + if (core->value("VisibleStyle").toUInt() & STYLE_ITALIC) + f.setItalic(true); + if (core->value("VisibleStyle").toUInt() & STYLE_UNDER) + f.setUnderline(true); + if (core->value("VisibleStyle").toUInt() & STYLE_STRIKE) + f.setStrikeOut(true); + } + if (m_style & CONTACT_UNDERLINE){ + if (core->value("AuthStyle").toUInt() & STYLE_ITALIC) + f.setItalic(true); + if (core->value("AuthStyle").toUInt() & STYLE_UNDER) + f.setUnderline(true); + if (core->value("AuthStyle").toUInt() & STYLE_STRIKE) + f.setStrikeOut(true); + } + if (m_style & CONTACT_STRIKEOUT){ + if (core->value("InvisibleStyle").toUInt() & STYLE_ITALIC) + f.setItalic(true); + if (core->value("InvisibleStyle").toUInt() & STYLE_UNDER) + f.setUnderline(true); + if (core->value("InvisibleStyle").toUInt() & STYLE_STRIKE) + f.setStrikeOut(true); + } + if (m_blink & 1){ + f.setBold(true); + }else{ + f.setBold(false); + } + p->setFont(f); +} + +void FloatyWnd::mousePressEvent(QMouseEvent *e) +{ + if (e->button() == Qt::LeftButton){ + initMousePos = e->pos(); + moveTimer->start(QApplication::startDragTime()); + } + if (e->button() == Qt::RightButton){ + m_plugin->popupPos = e->globalPos(); + m_plugin->popupId = m_id; + QTimer::singleShot(0, m_plugin, SLOT(showPopup())); + } +} + +void FloatyWnd::mouseReleaseEvent(QMouseEvent *e) +{ + moveTimer->stop(); + + if (!mousePos.isNull()){ + if (!b_ignoreMouseClickRelease) // we reached fetch positich + move(e->globalPos() - mousePos); + releaseMouse(); + Contact *contact = getContacts()->contact(m_id); + if (contact){ + SIM::PropertyHubPtr data = contact->getUserData("floaty", false); + if(!data.isNull()) + { + data->setValue("X", x()); + data->setValue("Y", y()); + } + } + mousePos = QPoint(); + } + else + { + CorePlugin *core = GET_CorePlugin(); + if ((e->pos() == initMousePos) && !core->value("UseDblClick").toBool()) + { + EventDefaultAction(m_id).process(); + } + } + initMousePos = QPoint(0, 0); +} + +void FloatyWnd::mouseMoveEvent(QMouseEvent *e) +{ + if ((e->buttons() & Qt::LeftButton) && !initMousePos.isNull() && + (QPoint(e->pos() - initMousePos).manhattanLength() > QApplication::startDragDistance())) + startMove(); + if (!mousePos.isNull()) + { + QWidgetList list = QApplication::topLevelWidgets(); + QWidget * w; + foreach(w,list) + { + if (w->inherits("FloatyWnd")) + { + FloatyWnd *refwnd = static_cast(w); + int dist = 4; + move(e->globalPos() - mousePos); + //Top left: + if (this->pos().x() + this->width() - refwnd->pos().x() <= dist && //== x Top left + this->pos().x() + this->width() - refwnd->pos().x() >= 0 && + this->pos().y() + this->height() - refwnd->pos().y() <= dist && + this->pos().y() + this->height() - refwnd->pos().y() >= 0) { + QWidget::move(refwnd->pos().x()-this->width(), //== x Top left + refwnd->pos().y()-this->height()); + b_ignoreMouseClickRelease=true; + cout << "TOP LEFT" << endl; + return; + } + + //Bottom left + if (this->pos().x() + this->width() - refwnd->pos().x() <= dist && + this->pos().x() + this->width() - refwnd->pos().x() >=0 && //== x Top left + this->pos().y() - refwnd->pos().y() - refwnd->height() <= dist && + this->pos().y() - refwnd->pos().y() - refwnd->height() >=0 ) { + QWidget::move(refwnd->pos().x()-this->width(), //== x Top left + refwnd->pos().y()+refwnd->height()); + b_ignoreMouseClickRelease=true; + cout << "BOTTOM LEFT" << endl; + return; + } + + //Top right + if (this->pos().x() + refwnd->width() - this->pos().x() <= dist && + this->pos().y() + this->height() - refwnd->pos().y() <= dist ) {//== y Top left + QWidget::move(refwnd->pos().x()+refwnd->width(), + refwnd->pos().y()-this->height()); //== y Top left + b_ignoreMouseClickRelease=true; + cout << "TOP RIGHT" << endl; + return; + } + + //Bottom right + if (this->pos().x() + refwnd->width() - this->pos().x() <= dist && + this->pos().x() + refwnd->width() - this->pos().x() >=0 && //== x Top right + this->pos().y() - refwnd->pos().y() - refwnd->height() <= dist && + this->pos().y() - refwnd->pos().y() - refwnd->height() >=0 ) { //== y Bottom left + QWidget::move(refwnd->pos().x()+refwnd->width(), //== x Top right + refwnd->pos().y()-refwnd->height()); //== y Bottom left + b_ignoreMouseClickRelease=true; + cout << "BOTTOM LEFT" << endl; + return; + } + //Top + if (this->pos().y()+this->height()-refwnd->pos().y() <= dist ) { + if (this->pos().x() == refwnd->pos().x()) {//add distance + QWidget::move(refwnd->pos().x(), //== x Top right + refwnd->pos().y()-this->height()); //== y Top left + b_ignoreMouseClickRelease=true; + cout << "TOP dock left" << endl; + return; + } + + if (this->pos().x() + this->width() == refwnd->pos().x() + refwnd->width()) {//add distance + QWidget::move(refwnd->pos().x() + refwnd->width() - this->width(), //== x Top right + refwnd->pos().y()-this->height()); //== y Top left + b_ignoreMouseClickRelease=true; + cout << "TOP dock right" << endl; + return; + } + } + + //Bottom + if (refwnd->pos().y()+refwnd->height()-this->pos().y() <= dist ) { + if (this->pos().x() == refwnd->pos().x()) { //add distance + QWidget::move(refwnd->pos().x(), //== x Top right + refwnd->pos().y()+refwnd->height()); //== y Bottem left + b_ignoreMouseClickRelease=true; + cout << "BOTTOM dock left" << endl; + return; + } + + if (this->pos().x() + this->width() == refwnd->pos().x() + refwnd->width()) {//add distance + QWidget::move(refwnd->pos().x() + refwnd->width() - this->width(), //== x Top right + refwnd->pos().y()+refwnd->height()); //== y Bottem left + b_ignoreMouseClickRelease=true; + cout << "BOTTOM dock right" << endl; + return; + } + } + + //Left + if (this->pos().x()+this->width()-refwnd->pos().x() <= dist && + this->pos().x()+this->width()-refwnd->pos().x() >= 0 + ) + if (this->pos().y() - refwnd->pos().y() < dist || + refwnd->pos().y() - this->pos().y() < dist ) { + QWidget::move(refwnd->pos().x() - this->width(), + refwnd->pos().y()); + b_ignoreMouseClickRelease=true; + cout << "LEFT" << endl; + return; + } + + + + //Right + if (refwnd->pos().x()+refwnd->width()-this->pos().x() <= dist && + refwnd->pos().x()+refwnd->width()-this->pos().x() >=0 + ) + if (this->pos().y() - refwnd->pos().y() < dist || + refwnd->pos().y() - this->pos().y() < dist ) { + QWidget::move(refwnd->pos().x() + refwnd->width(), + refwnd->pos().y()); + b_ignoreMouseClickRelease=true; + cout << "RIGHT" << endl; + return; + } + + //this->size(); + this->repaint(); + } + } + } +} + +void FloatyWnd::startMove() +{ + if (initMousePos.isNull()) + return; + moveTimer->stop(); + mousePos = initMousePos; + initMousePos = QPoint(0, 0); + grabMouse(); +} + +void FloatyWnd::move(QPoint point) +{ + QRect r = QApplication::desktop()->availableGeometry(); + QRect wr = frameGeometry(); + if(point.x() < r.x()) + point.setX(r.x()); + if(point.y() < r.y()) + point.setY(r.y()); + if(point.x()+wr.width() > r.x()+r.width()) + point.setX(r.x()+r.width()-wr.width()); + if(point.y()+wr.height() > r.y()+r.height()) + point.setY(r.y()+r.height()-wr.height()); + QWidget::move(point); +} + +void FloatyWnd::blink() +{ + if (m_blink){ + m_blink--; + }else{ + blinkTimer->stop(); + } + repaint(); +} + +void FloatyWnd::mouseDoubleClickEvent(QMouseEvent *) +{ + EventDefaultAction(m_id).process(); +} + +void FloatyWnd::dragEnterEvent(QDragEnterEvent *e) +{ + dragEvent(e, false); +} + +void FloatyWnd::dropEvent(QDropEvent *e) +{ + dragEvent(e, true); +} + +void FloatyWnd::dragEvent(QDropEvent *e, bool isDrop) +{ + Message *msg = NULL; + CommandDef *cmd; + CorePlugin *core = GET_CorePlugin(); + CommandsMapIterator it(core->messageTypes); + while ((cmd = ++it) != NULL){ + MessageDef *def = (MessageDef*)(cmd->param); + if (def && def->drag){ + msg = def->drag(e); + if (msg){ + unsigned type = cmd->id; + Command cmd; + cmd->id = type; + cmd->menu_id = MenuMessage; + cmd->param = (void*)m_id; + if (EventCheckCommandState(cmd).process()) + break; + } + } + } + if (msg){ + e->accept(); + if (isDrop){ + msg->setContact(m_id); + EventOpenMessage(msg).process(); + } + delete msg; + return; + } + if (!e->mimeData()->text().isEmpty()) { + e->accept(); + if (isDrop) { + Message *msg = new Message(MessageGeneric); + msg->setText(e->mimeData()->text()); + msg->setContact(m_id); + EventOpenMessage(msg).process(); + delete msg; + } + return; + } +} + +bool FloatyWnd::event( QEvent *event ) { + if( QEvent::ToolTip == event->type() ) { + do { + QHelpEvent *e = dynamic_cast( event ); + + Contact *contact = getContacts()->contact(m_id); + if (contact == NULL) + break; + + QString tip = contact->tipText(); + QRect tipRect(pos().x(), pos().y(), width(), height()); + QToolTip::showText( mapToGlobal( e->pos() ), tip, this, tipRect ); + + return true; + } while( false ); + + QToolTip::hideText(); + } + + return QWidget::event( event ); +} + +// vim: set expandtab: + diff --git a/plugins/floaty/floatywnd.h b/plugins/floaty/floatywnd.h new file mode 100644 index 0000000..7cacc2c --- /dev/null +++ b/plugins/floaty/floatywnd.h @@ -0,0 +1,77 @@ +/*************************************************************************** + floatywnd.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _FLOATYWND_H +#define _FLOATYWND_H + + +#include +#include +#include + +class FloatyPlugin; +class QTimer; +class QPainter; + +#ifdef MAKE_FLOATY_LIB +# define FLOATY_EXPORTS Q_DECL_EXPORT +#else +# define FLOATY_EXPORTS Q_DECL_IMPORT +#endif + +class FLOATY_EXPORTS FloatyWnd : public QWidget +{ + Q_OBJECT +public: + FloatyWnd(FloatyPlugin*, unsigned long id); + ~FloatyWnd(); + unsigned long id() { return m_id; } + void init(); + void startBlink(); +private slots: + void startMove(); + void blink(); +private: + void paintEvent(QPaintEvent*); + void mousePressEvent(QMouseEvent*); + void mouseReleaseEvent(QMouseEvent*); + void mouseMoveEvent(QMouseEvent*); + void mouseDoubleClickEvent(QMouseEvent*); + void dragEnterEvent(QDragEnterEvent*); + void dropEvent(QDropEvent*); + void dragEvent(QDropEvent *e, bool isDrop); + void setFont(QPainter *p); + void move(QPoint point); + virtual bool event( QEvent *event ); + QPoint mousePos; + QPoint initMousePos; + QString m_text; + QSet m_icons; + QString m_statusIcon; + unsigned long m_id; + unsigned m_style; + unsigned m_unread; + unsigned m_blink; + unsigned long m_status; + bool b_ignoreMouseClickRelease; + QTimer *blinkTimer; + QTimer *moveTimer; + FloatyPlugin *m_plugin; +}; + +#endif + diff --git a/plugins/forward/CMakeLists.txt b/plugins/forward/CMakeLists.txt new file mode 100644 index 0000000..78f1c3a --- /dev/null +++ b/plugins/forward/CMakeLists.txt @@ -0,0 +1,28 @@ +################### +# forward library # +################### +IF(BUILD_DROPPED) +SET(forward_SRCS + forward.cpp + forwardcfg.cpp +) + +SET(forward_HDRS + forward.h + forwardcfg.h +) + +SET(forward_UICS + forwardcfgbase.ui +) + +SET(forward_LIBS + _core +) + +REMOVE_DEFINITIONS(-DQT3_SUPPORT) +REMOVE_DEFINITIONS(-DQT_3SUPPORT_LIB) +REMOVE_DEFINITIONS(-DQT3_SUPPORT_WARNINGS) +SIM_ADD_PLUGIN(forward) +ENDIF(BUILD_DROPPED) + diff --git a/plugins/forward/forward.cpp b/plugins/forward/forward.cpp new file mode 100644 index 0000000..c22335f --- /dev/null +++ b/plugins/forward/forward.cpp @@ -0,0 +1,208 @@ +/*************************************************************************** + forward.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "forward.h" +#include "forwardcfg.h" +#include "core.h" + +#include "profile.h" +#include "profilemanager.h" + +#include "contacts/clientdataiterator.h" +#include "contacts/contact.h" +#include "contacts/group.h" +#include "contacts/client.h" + +using namespace SIM; + +Plugin *createForwardPlugin(unsigned base, bool, Buffer*) +{ + Plugin *plugin = new ForwardPlugin(base); + return plugin; +} + +static PluginInfo info = + { + I18N_NOOP("Forward"), + I18N_NOOP("Plugin provides messages forwarding on cellular"), + VERSION, + createForwardPlugin, + PLUGIN_DEFAULT + }; + +EXPORT_PROC PluginInfo* GetPluginInfo() +{ + return &info; +} + +static DataDef forwardUserData[] = + { + { "Phone", DATA_UTF, 1, 0 }, + { "Send1st", DATA_BOOL, 1, 0 }, + { "Translit", DATA_BOOL, 1, 0 }, + { NULL, DATA_UNKNOWN, 0, 0 } + }; + +static ForwardPlugin *forwardPlugin = NULL; + +static QWidget *getForwardSetup(QWidget *parent, PropertyHubPtr data) +{ + return new ForwardConfig(parent, data, forwardPlugin); +} + +ForwardPlugin::ForwardPlugin(unsigned base) + : QObject(), Plugin(base) + , EventReceiver(DefaultPriority - 1) +{ + m_propertyHub = SIM::PropertyHub::create("forward"); + forwardPlugin = this; + user_data_id = getContacts()->registerUserData(info.title, forwardUserData); + Command cmd; + cmd->id = user_data_id; + cmd->text = I18N_NOOP("&Forward"); + cmd->icon = "cell"; + cmd->param = (void*)getForwardSetup; + EventAddPreferences(cmd).process(); +} + +ForwardPlugin::~ForwardPlugin() +{ + EventRemovePreferences(user_data_id).process(); + getContacts()->unregisterUserData(user_data_id); +} + +bool ForwardPlugin::processEvent(Event *e) +{ + if (e->type() == eEventMessageReceived){ + EventMessage *em = static_cast(e); + Message *msg = em->msg(); + if (msg->type() == MessageStatus) + return false; + QString text = msg->getPlainText(); + if (text.isEmpty()) + return false; + if (msg->type() == MessageSMS){ + SMSMessage *sms = static_cast(msg); + QString phone = sms->getPhone(); + bool bMyPhone; + SIM::PropertyHubPtr data = getContacts()->getUserData("forward"); + bMyPhone = ContactList::cmpPhone(phone, data->value("Phone").toString()); + if (!bMyPhone){ + Group *grp; + ContactList::GroupIterator it; + while ((grp = ++it) != NULL){ + data = grp->getUserData("forward", false); + if (data && !data->value("Phone").toString().isEmpty()){ + bMyPhone = ContactList::cmpPhone(phone, data->value("Phone").toString()); + break; + } + } + } + if (!bMyPhone){ + Contact *contact; + ContactList::ContactIterator it; + while ((contact = ++it) != NULL){ + data = contact->getUserData("forward", false); + if (data && !data->value("Phone").toString().isEmpty()) + { + bMyPhone = ContactList::cmpPhone(phone, data->value("Phone").toString()); + break; + } + } + } + if (bMyPhone){ + int n = text.indexOf(": "); + if (n > 0){ + QString name = text.left(n); + QString msg_text = text.mid(n + 2); + Contact *contact; + ContactList::ContactIterator it; + while ((contact = ++it) != NULL){ + if (contact->getName() == name){ + Message *msg = new Message(MessageGeneric); + msg->setContact(contact->id()); + msg->setText(msg_text); + void *data; + ClientDataIterator it(contact->clientData); + while ((data = ++it) != NULL){ + if (it.client()->send(msg, data)) + break; + } + if (data == NULL) + delete msg; + return true; + } + } + } + } + } + Contact *contact = getContacts()->contact(msg->contact()); + if (contact == NULL) + return false; + SIM::PropertyHubPtr data = contact->getUserData("forward"); + if (!data || data->value("Key").toString().isEmpty()) + return false; + CorePlugin *core = GET_CorePlugin(); + unsigned status = core->getManualStatus(); + if ((status == STATUS_AWAY) || (status == STATUS_NA)){ + text = contact->getName() + ": " + text; + unsigned flags = MESSAGE_NOHISTORY; + if (data->value("Send1st").toBool()) + flags |= MESSAGE_1ST_PART; + if (data->value("Translit").toBool()) + flags |= MESSAGE_TRANSLIT; + SMSMessage *m = new SMSMessage; + m->setPhone(data->value("Phone").toString()); + m->setText(text); + m->setFlags(flags); + unsigned i; + for (i = 0; i < getContacts()->nClients(); i++){ + Client *client = getContacts()->getClient(i); + if (client->send(m, NULL)) + break; + } + if (i >= getContacts()->nClients()) + delete m; + } + } + return false; +} + +QWidget *ForwardPlugin::createConfigWindow(QWidget *parent) +{ + return new ForwardConfig(parent, getContacts()->getUserData("forward"), this); +} + +void ForwardPlugin::setPropertyHub(SIM::PropertyHubPtr hub) +{ + m_propertyHub = hub; +} + +SIM::PropertyHubPtr ForwardPlugin::propertyHub() +{ + return m_propertyHub; +} + +QVariant ForwardPlugin::value(const QString& key) +{ + return m_propertyHub->value(key); +} + +void ForwardPlugin::setValue(const QString& key, const QVariant& v) +{ + m_propertyHub->setValue(key, v); +} \ No newline at end of file diff --git a/plugins/forward/forward.h b/plugins/forward/forward.h new file mode 100644 index 0000000..1d0e48a --- /dev/null +++ b/plugins/forward/forward.h @@ -0,0 +1,52 @@ +/*************************************************************************** + forward.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _FORWARD_H +#define _FORWARD_H + +#include "cfg.h" +#include "event.h" +#include "plugins.h" +#include "propertyhub.h" + +struct ForwardUserData +{ + SIM::Data Phone; + SIM::Data Send1st; + SIM::Data Translit; +}; + +class ForwardPlugin : public QObject, public SIM::Plugin, public SIM::EventReceiver +{ +public: + ForwardPlugin(unsigned); + virtual ~ForwardPlugin(); + unsigned long user_data_id; + + void setPropertyHub(SIM::PropertyHubPtr hub); + SIM::PropertyHubPtr propertyHub(); + QVariant value(const QString& key); + void setValue(const QString& key, const QVariant& v); +protected: + virtual QWidget *createConfigWindow(QWidget *parent); + virtual bool processEvent(SIM::Event *e); +private: + SIM::PropertyHubPtr m_propertyHub; +}; + +#endif + diff --git a/plugins/forward/forward.rc b/plugins/forward/forward.rc new file mode 100644 index 0000000..9fc3ece --- /dev/null +++ b/plugins/forward/forward.rc @@ -0,0 +1,97 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,9,6,0 + PRODUCTVERSION 0,9,6,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Vladimir Shutoff\0" + VALUE "FileDescription", "Forward plugin\0" + VALUE "FileVersion", "0, 9, 6, 0\0" + VALUE "InternalName", "forward\0" + VALUE "LegalCopyright", "Copyright © 2002-2003\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "forward.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "SIM\0" + VALUE "ProductVersion", "0, 9, 6, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/forward/forward.vcproj b/plugins/forward/forward.vcproj new file mode 100644 index 0000000..3425483 --- /dev/null +++ b/plugins/forward/forward.vcproj @@ -0,0 +1,369 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/forward/forwardcfg.cpp b/plugins/forward/forwardcfg.cpp new file mode 100644 index 0000000..60dfa44 --- /dev/null +++ b/plugins/forward/forwardcfg.cpp @@ -0,0 +1,62 @@ +/*************************************************************************** + forwardcfg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include + +#include "contacts/contact.h" +#include "misc.h" + +#include "forwardcfg.h" +#include "forward.h" + +using namespace SIM; + +ForwardConfig::ForwardConfig(QWidget *parent, PropertyHubPtr data, ForwardPlugin *plugin) : QWidget(parent) +{ + setupUi(this); + m_plugin = plugin; + //PropertyHubPtr data = (ForwardUserData*)_data; + chkFirst-> setChecked(data->value("Send1st") .toBool()); + chkTranslit->setChecked(data->value("Translit") .toBool()); + cmbPhone->setEditable(true); + QString phones = getContacts()->owner()->getPhones(); + while (!phones.isEmpty()) + { + QString item = getToken(phones, ';', false); + QString number = getToken(item, ','); + getToken(item, ','); + if (item.toULong() == CELLULAR) + cmbPhone->insertItem(INT_MAX,number); + } + cmbPhone->lineEdit()->setText(data->value("Phone").toString()); +} + +void ForwardConfig::apply(PropertyHubPtr data) +{ + //ForwardUserData *data = (ForwardUserData*)_data; + data->setValue("Send1st", chkFirst->isChecked() ); + data->setValue("Translit", chkTranslit->isChecked() ); + data->setValue("Phone", cmbPhone->lineEdit()->text()); +} + +void ForwardConfig::apply() +{ + apply(getContacts()->getUserData("forward")); +} + diff --git a/plugins/forward/forwardcfg.h b/plugins/forward/forwardcfg.h new file mode 100644 index 0000000..68e1b8b --- /dev/null +++ b/plugins/forward/forwardcfg.h @@ -0,0 +1,40 @@ +/*************************************************************************** + forwardcfg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _FORWARDCFG_H +#define _FORWARDCFG_H + +#include "ui_forwardcfgbase.h" +#include "propertyhub.h" + +using namespace SIM; +class ForwardPlugin; + +class ForwardConfig : public QWidget, public Ui::ForwardConfigBase +{ + Q_OBJECT +public: + ForwardConfig(QWidget *parent, PropertyHubPtr data, ForwardPlugin *plugin); +public slots: + void apply(PropertyHubPtr data); + void apply(); +protected: + ForwardPlugin *m_plugin; +}; + +#endif + diff --git a/plugins/forward/forwardcfgbase.ui b/plugins/forward/forwardcfgbase.ui new file mode 100644 index 0000000..9b9eb0d --- /dev/null +++ b/plugins/forward/forwardcfgbase.ui @@ -0,0 +1,112 @@ + + + + + ForwardConfigBase + + + + 0 + 0 + 352 + 215 + + + + Form1 + + + + 11 + + + 6 + + + + + Send all messages in status "Away" and "N/A" on the cellular: + + + Qt::AlignVCenter|Qt::AlignLeft + + + true + + + + + + + + + + For the answer or sending of the new message you can answer on SMS having specified in the beginning of the message a line: +<UIN>: + + + Qt::AlignVCenter|Qt::AlignLeft + + + true + + + + + + + Send only &one message (don't split) + + + + + + + Send in &translit + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Vertical + + + + + + + + QWidget + QWidget +
QWidget
+ + -1 + -1 + + 0 + + 5 + 5 + + image0 + + text + +
+
+ + + 789c6dd2c10ac2300c00d07bbf2234b7229d1be245fc04c5a3201e4615f430059d0711ff5ddb2e6bb236ec90eed134cb5a19d8ef36602af5ecdbfeeac05dda0798d3abebde87e3faa374d3807fa0d633a52d38d8de6f679fe33fc776e196f53cd010188256a3600a292882096246517815ca99884606e18044a3a40d91824820924265a7923a2e8bcd05f33db1173e002913175f2a6be6d3294871a2d95fa00e8a94ee017b69d339d90df1e77c57ea072ede6758 + + +
diff --git a/plugins/gpg/CMakeLists.txt b/plugins/gpg/CMakeLists.txt new file mode 100644 index 0000000..bf059e8 --- /dev/null +++ b/plugins/gpg/CMakeLists.txt @@ -0,0 +1,41 @@ +############### +# gpg library # +############### +IF(BUILD_DROPPED) +IF(WIN32) + SET (gpg_SRCS gpgfind.cpp) + SET (gpg_HDRS gpgfind.h) + SET (gpg_UICS gpgfindbase.ui) +ENDIF(WIN32) + +SET(gpg_SRCS + gpg.cpp + gpgadv.cpp + gpgcfg.cpp + gpggen.cpp + gpguser.cpp + passphrase.cpp + ${gpg_SRCS} +) + +SET(gpg_HDRS + gpg.h + gpgadv.h + gpgcfg.h + gpggen.h + gpguser.h + passphrase.h + ${gpg_HDRS} +) + +SET(gpg_UICS + gpgadvbase.ui + gpgcfgbase.ui + gpggenbase.ui + gpguserbase.ui + passphrasebase.ui + ${gpg_UICS} +) + +SIM_ADD_PLUGIN(gpg) +ENDIF(BUILD_DROPPED) diff --git a/plugins/gpg/configure.in.in b/plugins/gpg/configure.in.in new file mode 100644 index 0000000..466093d --- /dev/null +++ b/plugins/gpg/configure.in.in @@ -0,0 +1,5 @@ +if test "$kde_use_qt_win" = "yes"; then + GPG_OBJ=gpgfind.lo + AC_SUBST([GPG_OBJ]) +fi + diff --git a/plugins/gpg/gpg.cpp b/plugins/gpg/gpg.cpp new file mode 100644 index 0000000..10e092d --- /dev/null +++ b/plugins/gpg/gpg.cpp @@ -0,0 +1,998 @@ +/*************************************************************************** + gpg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "simapi.h" + +#include "log.h" +#include "msgedit.h" +#include "userwnd.h" +#include "passphrase.h" + +#include "simgui/textshow.h" +#include "simgui/ballonmsg.h" +#include "contacts/contact.h" +#include "contacts/client.h" + +#include "profile.h" +#include "profilemanager.h" + +#include "gpg.h" +#include "gpgcfg.h" +#include "gpguser.h" + +#include +#include +#include +#include +#include +#include //for Linux: qApp->processEvents(); +#include +#include + +#ifdef HAVE_SYS_STAT_H +#include +#endif + +using namespace SIM; + +#ifndef WIN32 +static QString GPGpath; +#endif + +Plugin *createGpgPlugin(unsigned base, bool, Buffer *cfg) +{ +#ifndef WIN32 + if (GPGpath.isEmpty()) + return NULL; +#endif + Plugin *plugin = new GpgPlugin(base, cfg); + return plugin; +} + +static PluginInfo info = + { + I18N_NOOP("GPG"), + I18N_NOOP("Plugin adds GnuPG encryption/decryption support for messages"), + VERSION, + createGpgPlugin, PLUGIN_DEFAULT + }; + +EXPORT_PROC PluginInfo* GetPluginInfo() +{ +#ifndef WIN32 + QString path; + const char *p = getenv("PATH"); + if (p) + path = QFile::decodeName(p); + while (!path.isEmpty()){ + QString p = getToken(path, ':'); + p += "/gpg"; + QFile f(p); + QFileInfo fi(f); + if (fi.isExecutable()){ + GPGpath = p; + break; + } + } + if (GPGpath.isEmpty()) + info.description = I18N_NOOP("Plugin adds GnuPG encryption/decryption support for messages\n" + "GPG not found in PATH"); +#endif + return &info; +} + +static DataDef gpgUserData[] = + { + { "Key", DATA_STRING, 1, 0 }, + { "Use", DATA_BOOL, 1, 0 }, + { NULL, DATA_UNKNOWN, 0, 0 } + }; + +GpgPlugin *GpgPlugin::plugin = NULL; + +GpgPlugin::GpgPlugin(unsigned base, Buffer *cfg) + : QObject(), Plugin(base) + , EventReceiver(HighestPriority - 0x100) //??? Fixmee!! + , m_bMessage(false) + , m_passphraseDlg(NULL) +{ + m_propertyHub = SIM::PropertyHub::create("gpg"); + user_data_id = getContacts()->registerUserData(info.title, gpgUserData); + reset(); + plugin = this; +} + +GpgPlugin::~GpgPlugin() +{ + delete m_passphraseDlg; + unregisterMessage(); + QList::ConstIterator it; + for (it = m_decrypt.constBegin(); it != m_decrypt.constEnd(); ++it){ + delete it->msg; + delete it->process; + } + for (it = m_import.constBegin(); it != m_import.constEnd(); ++it){ + delete it->msg; + delete it->process; + } + for (it = m_public.constBegin(); it != m_public.constEnd(); ++it) + delete it->process; + for (it = m_wait.constBegin(); it != m_wait.constEnd(); ++it) + delete it->msg; + getContacts()->unregisterUserData(user_data_id); +} + +QString GpgPlugin::GPG() +{ +#ifdef WIN32 + return value("GPG").toString(); +#else + return GPGpath; +#endif +} + +void GpgPlugin::clear() +{ + QList::iterator it; + for (it = m_decrypt.begin(); it != m_decrypt.end();){ + if (it->msg){ + ++it; + continue; + } + delete it->process; + QFile::remove(it->infile); + QFile::remove(it->outfile); + m_decrypt.erase(it); + it = m_decrypt.begin(); + } + for (it = m_import.begin(); it != m_import.end(); ){ + if (it->msg){ + ++it; + continue; + } + delete it->process; + QFile::remove(it->infile); + QFile::remove(it->outfile); + m_import.erase(it); + it = m_import.begin(); + } + for (it = m_public.begin(); it != m_public.end(); ){ + if (it->contact){ + ++it; + continue; + } + delete it->process; + QFile::remove(it->infile); + QFile::remove(it->outfile); + m_public.erase(it); + it = m_public.begin(); + } +} + +void GpgPlugin::decryptReady() +{ + int res = 0; + for (QList::iterator it = m_decrypt.begin(); it != m_decrypt.end(); ++it){ + QProcess *p = it->process; + if (p && p->state() != QProcess::Running && it->msg){ + Message *msg = it->msg; + it->msg = NULL; + QTimer::singleShot(0, this, SLOT(clear())); + if (p->exitStatus() == QProcess::NormalExit && p->exitCode() == 0){ + QString s = it->outfile; + QFile f(s); + if (f.open(QIODevice::ReadOnly)){ + QByteArray ba = f.readAll(); + msg->setText(QString::fromUtf8(ba.data(), ba.size())); + msg->setFlags(msg->getFlags() | MESSAGE_SECURE); + }else{ + log(L_WARN, "Can't open output decrypt file %s", qPrintable(s)); + res = -1; + } + if (!it->key.isEmpty()){ + unsigned i = 1; + for (i = 1; i <= value("NPassphrases").toUInt(); i++){ + if (it->key == value("Keys").toStringList()[i]) + break; + } + if (i > value("NPassphrases").toUInt()){ + setValue("NPassphrases", i); + QStringList l = value("Keys").toStringList(); + l[i] = it->key; + setValue("Keys", l); + } + + QStringList list = value("Passphrases").toStringList(); + list[i] = it->passphrase; + setValue("Passphrases", list); + for (;;){ + QList::iterator itw; + bool bDecode = false; + for (itw = m_wait.begin(); itw != m_wait.end(); ++itw){ + if (itw->key == it->key){ + decode(itw->msg, it->passphrase, it->key); + m_wait.erase(itw); + bDecode = true; + break; + } + } + if (!bDecode) + break; + } + if (m_passphraseDlg && (it->key == m_passphraseDlg->m_key)){ + delete m_passphraseDlg; + m_passphraseDlg = NULL; + askPassphrase(); + } + } + }else{ + QString key; + QString passphrase; + p->setReadChannel(QProcess::StandardError); + QByteArray ba = p->readAll(); + QString str = QString::fromUtf8(ba.data(), ba.size()); + while(!str.isEmpty()) { + key = getToken(str, '\n'); + if (key.contains("BAD_PASSPHRASE")){ + int n = key.indexOf("BAD_PASSPHRASE "); + if(n < 0) + break; + key = key.mid(n + strlen("BAD_PASSPHRASE ")); + if (m_passphraseDlg && (it->key == m_passphraseDlg->m_key)){ + DecryptMsg m; + m.msg = msg; + m.key = key; + m_wait.push_back(m); + m_passphraseDlg->error(); + return; + } + if (it->passphrase.isEmpty()){ + for (unsigned i = 1; i <= value("NPassphrases").toUInt(); i++){ + if (key == value("Keys").toStringList()[i]){ + passphrase = value("Passphrases").toStringList()[i]; + break; + } + } + } + if (it->passphrase.isEmpty() && !passphrase.isEmpty()){ + if (decode(msg, passphrase, key)) + return; + }else{ + DecryptMsg m; + m.msg = msg; + m.key = key; + m_wait.push_back(m); + it->msg = NULL; + QTimer::singleShot(0, this, SLOT(clear())); + askPassphrase(); + return; + } + } + } + if (m_passphraseDlg && (it->key == m_passphraseDlg->m_key)){ + delete m_passphraseDlg; + m_passphraseDlg = NULL; + askPassphrase(); + } else { + msg->setText(key + '\n' + str); + } + } + EventMessageReceived e(msg); + if ((res == 0) && processEvent(&e)) + return; + if (!e.process(this)) + delete msg; + return; + } + } + log(L_WARN, "No decrypt exec"); +} + +void GpgPlugin::importReady() +{ + for (QList::iterator it = m_import.begin(); it != m_import.end(); ++it){ + QProcess *p = it->process; + if (p && p->state() != QProcess::Running){ + Message *msg = new Message(MessageGPGKey); + msg->setContact(it->msg->contact()); + msg->setClient(it->msg->client()); + msg->setFlags(it->msg->getFlags()); + + p->setReadChannel(QProcess::StandardError); + QByteArray ba = p->readAll(); + QString err = QString::fromLocal8Bit(ba.data(), ba.size()); + if (p->exitStatus() == QProcess::NormalExit && p->exitCode() == 0){ + QRegExp r1("[0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F][0-9A-F]:"); + QRegExp r2("\".*\""); + int len; + int pos = r1.indexIn(err, 0); + len = r1.matchedLength(); + if (pos >= 0) + { + QString key_name; + key_name = err.mid(pos + 1, len - 2); + QString text = key_name; + text += ' '; + pos = r2.indexIn(err, 0); + len = r2.matchedLength(); + text += err.mid(pos + 1, len - 2); + msg->setText(text); + delete it->msg; + it->msg = msg; + + QString home = GpgPlugin::plugin->getHomeDir(); + + QStringList sl; + sl += GPG(); + sl += "--no-tty"; + sl += "--homedir"; + sl += home; + sl += value("PublicList").toString().split(' '); + + QProcess *proc = new QProcess(this); + + DecryptMsg dm; + dm.process = proc; + dm.contact = msg->contact(); + dm.outfile = key_name; + m_public.push_back(dm); + connect(dm.process, SIGNAL(processExited()), this, SLOT(publicReady())); + dm.process->start(sl.join(" ")); + } else { + QString str; + if(!err.isEmpty()) + str = '(' + err + ')'; + msg->setText(i18n("Importing public key failed") + str); + } + } else { + QString str; + if(!err.isEmpty()) + str = '(' + err + ')'; + msg->setText(i18n("Importing public key failed") + str); + } + EventMessageReceived e(it->msg); + if (!e.process(this)) + delete it->msg; + it->msg = NULL; + QTimer::singleShot(0, this, SLOT(clear())); + return; + } + } + log(L_WARN, "No decrypt exec"); +} + +QByteArray GpgPlugin::getConfig() +{ + /* + QStringList keys; + QStringList passphrases; + for (unsigned i = 1; i <= getnPassphrases(); i++){ + keys.append(getKeys(i)); + passphrases.append(getPassphrases(i)); + } + if (!getSavePassphrase()){ + clearKeys(); + clearPassphrases(); + } + QByteArray res = save_data(gpgData, &data); + for (unsigned i = 0; i < getnPassphrases(); i++){ + setKeys(i + 1, keys[i]); + setPassphrases(i + 1, passphrases[i]); + } + */ + return QByteArray(); +} + +bool GpgPlugin::processEvent(Event *e) +{ + switch (e->type()){ + case eEventCheckCommandState:{ + EventCheckCommandState *ecs = static_cast(e); + CommandDef *cmd = ecs->cmd(); + if (cmd->menu_id == MenuMessage){ + if (cmd->id == MessageGPGKey){ + cmd->flags &= ~COMMAND_CHECKED; + CommandDef c = *cmd; + c.id = MessageGeneric; + return EventCheckCommandState(&c).process(); + } + if (cmd->id == MessageGPGUse){ + cmd->flags &= ~COMMAND_CHECKED; + Contact *contact = getContacts()->contact((unsigned long)(cmd->param)); + if (contact == NULL) + return false; + SIM::PropertyHubPtr data = contact->getUserData("gpg", false); + if (!data || data->value("Key").toString().isEmpty()) + return false; + if (data->value("Use").toBool()) + cmd->flags |= COMMAND_CHECKED; + return true; + } + } + return false; + } + case eEventCommandExec:{ + EventCommandExec *ece = static_cast(e); + CommandDef *cmd = ece->cmd(); + if ((cmd->menu_id == MenuMessage) && (cmd->id == MessageGPGUse)){ + Contact *contact = getContacts()->contact((unsigned long)(cmd->param)); + if (contact == NULL) + return false; + SIM::PropertyHubPtr data = contact->getUserData("gpg", false); + if (data && !data->value("Key").toString().isEmpty()) + data->setValue("Use", (cmd->flags & COMMAND_CHECKED) != 0); + return true; + } + return false; + } + case eEventCheckSend:{ + EventCheckSend *ecs = static_cast(e); + if ((ecs->id() == MessageGPGKey) && ecs->client()->canSend(MessageGeneric, ecs->data())) + return true; + return false; + } + case eEventMessageSent:{ + EventMessage *em = static_cast(e); + Message *msg = em->msg(); + for (QList::iterator it = m_sendKeys.begin(); it != m_sendKeys.end(); ++it){ + if (it->msg == msg){ + if (msg->getError().isEmpty()){ + Message m(MessageGPGKey); + m.setText(it->key); + m.setClient(msg->client()); + m.setContact(msg->contact()); + EventSent(&m).process(); + } + m_sendKeys.erase(it); + break; + } + } + return false; + } + case eEventMessageSend:{ + EventMessage *em = static_cast(e); + Message *msg = em->msg(); + if (msg->type() == MessageGeneric){ + Contact *contact = getContacts()->contact(msg->contact()); + if (contact){ + SIM::PropertyHubPtr data = contact->getUserData("gpg", false); + if (data && !data->value("Key").toString().isEmpty() && data->value("Use").toBool()){ + msg->setFlags(msg->getFlags() | MESSAGE_SECURE); + if (msg->getFlags() & MESSAGE_RICHTEXT){ + QString text = msg->getPlainText(); + msg->setText(text); + msg->setFlags(msg->getFlags() & ~MESSAGE_RICHTEXT); + } + } + } + } + return false; + } + case eEventSend:{ + EventSend *es = static_cast(e); + if ((es->msg()->type() == MessageGeneric) && + (es->msg()->getFlags() & MESSAGE_SECURE)){ + Contact *contact = getContacts()->contact(es->msg()->contact()); + if (contact) + { + SIM::PropertyHubPtr data = contact->getUserData("gpg", false); + if (data && !data->value("Key").toString().isEmpty() && data->value("Use").toBool()){ + QString output = user_file("m."); + output += QString::number((unsigned long)es->msg()); + QString input = output + ".in"; + QFile in(input); + if (!in.open(QIODevice::WriteOnly | QIODevice::Truncate)){ + log(L_WARN, "Can't create %s", qPrintable(input)); + return false; + } + in.write(es->localeText()); + in.close(); + QString home = GpgPlugin::plugin->getHomeDir(); + + QStringList sl; + sl += GPG(); + sl += "--no-tty"; + sl += "--homedir"; + sl += home; + sl += value("Encrypt").toString().split(' '); + sl = sl.replaceInStrings(QRegExp("\\%plainfile\\%"), input); + sl = sl.replaceInStrings(QRegExp("\\%cipherfile\\%"), output); + sl = sl.replaceInStrings(QRegExp("\\%userid\\%"), data->value("Key").toString()); + + QProcess proc(this); + + proc.start(sl.join(" ")); + + // FIXME: not soo good... + while(proc.state() == QProcess::Running) + qApp->processEvents(); + + if (proc.exitStatus() != QProcess::NormalExit || proc.exitCode() != 0){ + es->msg()->setError(I18N_NOOP("Encrypt failed")); + QFile::remove(input); + QFile::remove(output); + return true; + } + QFile::remove(input); + QFile out(output); + if (!out.open(QIODevice::ReadOnly)){ + QFile::remove(output); + es->msg()->setError(I18N_NOOP("Encrypt failed")); + return true; + } + es->setLocaleText(QByteArray(out.readAll())); + out.close(); + QFile::remove(output); + return false; + } + } + } + return false; + } + case eEventMessageReceived:{ + EventMessage *em = static_cast(e); + Message *msg = em->msg(); + if(!msg) + return false; + if ((msg->baseType() == MessageGeneric) && m_bMessage){ + QString text = msg->getPlainText(); + const char SIGN_MSG[] = "-----BEGIN PGP MESSAGE-----"; + const char SIGN_KEY[] = "-----BEGIN PGP PUBLIC KEY BLOCK-----"; + if (text.startsWith(SIGN_MSG)){ + if (decode(msg, "", "")) + return true; + return false; + } + if (text.startsWith(SIGN_KEY)){ + QString input = user_file("m."); + input += QString::number((unsigned long)msg); + input += ".in"; + QFile in(input); + if (!in.open(QIODevice::WriteOnly | QIODevice::Truncate)){ + log(L_WARN, "Can't create %s", qPrintable(input)); + return false; + } + QByteArray cstr = text.toUtf8(); + in.write(cstr); + in.close(); + QString home = GpgPlugin::plugin->getHomeDir(); + + QStringList sl; + sl += GPG(); + sl += "--no-tty"; + sl += "--homedir"; + sl += home; + sl += value("Import").toString().split(' '); + sl = sl.replaceInStrings(QRegExp("\\%keyfile\\%"), input); + + QProcess *proc = new QProcess(this); + + DecryptMsg dm; + dm.process = proc; + dm.msg = msg; + dm.infile = input; + m_import.push_back(dm); + connect(dm.process, SIGNAL(processExited()), this, SLOT(importReady())); + dm.process->start(sl.join(" ")); + dm.process->write("\n"); + return msg; + } + } + return false; + } + case eEventPluginLoadConfig: + { + setPropertyHub(ProfileManager::instance()->getPropertyHub("gpg")); + // Defaults: + if(!value("Home").isValid()) + setValue("Home", "keys/"); + if(!value("GenKey").isValid()) + setValue("GenKey", "--gen-key --batch"); + if(!value("PublicList").isValid()) + setValue("PublicList", "--with-colon --list-public-keys"); + if(!value("SecretList").isValid()) + setValue("SecretList", "--with-colon --list-secret-keys"); + if(!value("Import").isValid()) + setValue("Import", "--import %keyfile%"); + if(!value("Export").isValid()) + setValue("Export", "--batch --yes --armor --comment \"\" --no-version --export %userid%"); + if(!value("Encrypt").isValid()) + setValue("Encrypt", "--charset utf8 --batch --yes --armor --comment \"\" --no-version --recipient %userid% --trusted-key %userid% --output %cipherfile% --encrypt %plainfile%"); + if(!value("Decrypt").isValid()) + setValue("Decrypt", "--charset utf8 --yes --passphrase-fd 0 --status-fd 2 --output %plainfile% --decrypt %cipherfile%"); + break; + } + default: + break; + } + return false; +} + +static unsigned decode_index = 0; + +bool GpgPlugin::decode(Message *msg, const QString &aPassphrase, const QString &key) +{ + QString output = user_file("md."); + output += QString::number(decode_index++); + QString input = output + ".in"; + QFile in(input); + if (!in.open(QIODevice::WriteOnly | QIODevice::Truncate)){ + log(L_WARN, "Can't create %s", qPrintable(input)); + return false; + } + QByteArray cstr = msg->getPlainText().toUtf8(); + in.write(cstr); + in.close(); + QString home = GpgPlugin::plugin->getHomeDir(); + + QStringList sl; + sl += GPG(); + sl += "--no-tty"; + sl += "--homedir"; + sl += home; + sl += value("Decrypt").toString().split(' '); + sl = sl.replaceInStrings(QRegExp("\\%plainfile\\%"), output); + sl = sl.replaceInStrings(QRegExp("\\%cipherfile\\%"), input); + + QProcess *proc = new QProcess(this); + + DecryptMsg dm; + dm.process = proc; + dm.msg = msg; + dm.infile = input; + dm.outfile = output; + dm.passphrase = aPassphrase; + dm.key = key; + m_decrypt.push_back(dm); + + connect(dm.process, SIGNAL(processExited()), this, SLOT(decryptReady())); + dm.process->start(sl.join(" ")); + dm.process->write(aPassphrase.toUtf8().data()); + return true; +} + +void GpgPlugin::publicReady() +{ + for (QList::iterator it = m_public.begin(); it != m_public.end(); ++it){ + QProcess *p = it->process; + if (p && p->state() != QProcess::Running){ + if (p->exitStatus() == QProcess::NormalExit && p->exitCode() == 0){ + p->setReadChannel(QProcess::StandardError); + QByteArray str(p->readAll()); + for (;;){ + QByteArray line; + line = getToken(str, '\n'); + if(line.isEmpty()) + break; + QByteArray type = getToken(line, ':'); + if (type == "pub"){ + getToken(line, ':'); + getToken(line, ':'); + getToken(line, ':'); + QString sign = getToken(line, ':'); + QString name = it->outfile; + int pos = sign.length() - name.length(); + if (pos < 0) + pos = 0; + if (sign.mid(pos) == name.toLatin1()){ + Contact *contact = getContacts()->contact(it->contact); + if (contact) + { + SIM::PropertyHubPtr data = contact->getUserData("gpg", true); + data->setValue("Key", sign); + } + break; + } + } + } + } + it->contact = 0; + break; + } + } +} + +void GpgPlugin::passphraseApply(const QString &passphrase) +{ + for (QList::iterator it = m_wait.begin(); it != m_wait.end(); ++it){ + if (it->key == m_passphraseDlg->m_key){ + Message *msg = it->msg; + m_wait.erase(it); + decode(msg, passphrase, m_passphraseDlg->m_key); + return; + } + } + delete m_passphraseDlg; + m_passphraseDlg = NULL; + askPassphrase(); +} + +QWidget *GpgPlugin::createConfigWindow(QWidget *parent) +{ + return new GpgCfg(parent, this); +} + +void GpgPlugin::reset() +{ + if (!GPG().isEmpty() && !value("Home").toString().isEmpty() && !value("Key").toString().isEmpty()){ +#ifdef HAVE_CHMOD + chmod(QFile::encodeName(user_file(value("Home").toString())), 0700); +#endif + registerMessage(); + }else{ + unregisterMessage(); + } +} + +QString GpgPlugin::getHomeDir() +{ + QString home = user_file(value("Home").toString()); + if (home.endsWith("\\") || home.endsWith("/")) + home = home.left(home.length() - 1); + return home; +} + +#if 0 +i18n("%n GPG key", "%n GPG keys", 1); +#endif + +static Message *createGPGKey(Buffer *cfg) +{ + return new Message(MessageGPGKey, cfg); +} + +static QObject *generateGPGKey(MsgEdit *p, Message *msg) +{ + return new MsgGPGKey(p, msg); +} + +static MessageDef defGPGKey = + { + NULL, + NULL, + MESSAGE_INFO | MESSAGE_SYSTEM, + "%n GPG key", + "%n GPG keys", + createGPGKey, + generateGPGKey, + NULL + }; + +static MessageDef defGPGUse = + { + NULL, + NULL, + MESSAGE_SILENT, + NULL, + NULL, + NULL, + NULL, + NULL + }; + +static QWidget *getGpgSetup(QWidget *parent, void *data) +{ + return new GpgUser(parent, (GpgUserData*)data); +} + +void GpgPlugin::registerMessage() +{ + if (m_bMessage) + return; + m_bMessage = true; + Command cmd; + cmd->id = MessageGPGKey; + cmd->text = I18N_NOOP("GPG key"); + cmd->icon = "encrypted"; + cmd->param = &defGPGKey; + cmd->menu_grp = 0x4081; + EventCreateMessageType(cmd).process(); + + cmd->id = MessageGPGUse; + cmd->text = I18N_NOOP("Use GPG encryption"); + cmd->icon = QString::null; + cmd->param = &defGPGUse; + cmd->menu_grp = 0x4080; + EventCreateMessageType(cmd).process(); + + cmd->id = user_data_id; + cmd->text = I18N_NOOP("&GPG key"); + cmd->icon = "encrypted"; + cmd->param = (void*)getGpgSetup; + EventAddPreferences(cmd).process(); +} + +void GpgPlugin::unregisterMessage() +{ + if (!m_bMessage) + return; + m_bMessage = false; + EventRemoveMessageType(MessageGPGKey).process(); + EventRemoveMessageType(MessageGPGUse).process(); + EventRemovePreferences(user_data_id).process(); +} + +void GpgPlugin::askPassphrase() +{ + if (m_passphraseDlg || m_wait.empty()) + return; + m_passphraseDlg = new PassphraseDlg(this, m_wait.front().key); + connect(m_passphraseDlg, SIGNAL(finished()), this, SLOT(passphraseFinished())); + connect(m_passphraseDlg, SIGNAL(apply(const QString&)), this, SLOT(passphraseApply(const QString&))); + raiseWindow(m_passphraseDlg); +} + +void GpgPlugin::passphraseFinished() +{ + if (m_passphraseDlg){ + for (QList::iterator it = m_wait.begin(); it != m_wait.end();){ + if (it->key != m_passphraseDlg->m_key){ + ++it; + continue; + } + EventMessageReceived e(it->msg); + if (!e.process(this)) + delete it->msg; + m_wait.erase(it); + it = m_wait.begin(); + } + } + m_passphraseDlg = NULL; + askPassphrase(); +} + +void GpgPlugin::setPropertyHub(SIM::PropertyHubPtr hub) +{ + m_propertyHub = hub; +} + +SIM::PropertyHubPtr GpgPlugin::propertyHub() +{ + return m_propertyHub; +} + +QVariant GpgPlugin::value(const QString& key) +{ + return m_propertyHub->value(key); +} + +void GpgPlugin::setValue(const QString& key, const QVariant& v) +{ + m_propertyHub->setValue(key, v); +} + +MsgGPGKey::MsgGPGKey(MsgEdit *parent, Message *msg) + : QObject(parent) +{ + m_client = msg->client(); + m_edit = parent; + m_edit->m_edit->setText(QString::null); + m_edit->m_edit->setReadOnly(true); + m_edit->m_edit->setParam(m_edit); + + Command cmd; + cmd->id = CmdSend; + cmd->flags = COMMAND_DISABLED; + cmd->param = m_edit; + EventCommandDisabled(cmd).process(); + + QString gpg = GpgPlugin::plugin->GPG(); + QString home = GpgPlugin::plugin->getHomeDir(); + m_key = GpgPlugin::plugin->value("Key").toString(); + + QStringList sl; + sl += GpgPlugin::plugin->GPG(); + sl += "--no-tty"; + sl += "--homedir"; + sl += home; + sl += GpgPlugin::plugin->value("Export").toString().split(' '); + sl = sl.replaceInStrings(QRegExp("\\%userid\\%"), m_key); + + m_process = new QProcess(this); + + connect(m_process, SIGNAL(processExited()), this, SLOT(exportReady())); + m_process->start(sl.join(" ")); + exportReady(); +} + +MsgGPGKey::~MsgGPGKey() +{ + delete m_process; +} + +void MsgGPGKey::init() +{ + m_edit->m_edit->setFocus(); +} + +void MsgGPGKey::exportReady() +{ + if (m_process->exitStatus() == QProcess::NormalExit && m_process->exitCode() == 0) { + m_process->setReadChannel(QProcess::StandardOutput); + QByteArray ba1 = m_process->readAll(); + m_edit->m_edit->setText(QString::fromLocal8Bit(ba1.data(), ba1.size())); + if(ba1.isEmpty()) { + m_process->setReadChannel(QProcess::StandardError); + QByteArray ba2 = m_process->readAll(); + QString errStr; + if(!ba2.isEmpty()) + errStr = " (" + QString::fromLocal8Bit( ba2.data(), ba2.size() ) + ") "; + BalloonMsg::message(i18n("Can't read gpg key ") + errStr + + " Error code: " + QString::number(m_process->error()), m_edit->m_edit); + } + } + + Command cmd; + cmd->id = CmdSend; + cmd->flags = 0; + cmd->param = m_edit; + EventCommandDisabled(cmd).process(); + + delete m_process; + m_process = 0; +} + +bool MsgGPGKey::processEvent(Event *e) +{ + if (e->type() == eEventCheckCommandState){ + EventCheckCommandState *ecs = static_cast(e); + CommandDef *cmd = ecs->cmd(); + if (cmd->param == m_edit){ + unsigned id = cmd->bar_grp; + if ((id >= MIN_INPUT_BAR_ID) && (id < MAX_INPUT_BAR_ID)){ + cmd->flags |= BTN_HIDE; + return true; + } + switch (cmd->id){ + case CmdSend: + case CmdSendClose: + e->process(this); + cmd->flags &= ~BTN_HIDE; + return true; + case CmdTranslit: + case CmdSmile: + case CmdNextMessage: + case CmdMsgAnswer: + e->process(this); + cmd->flags |= BTN_HIDE; + return true; + } + } + } + if (e->type() == eEventCommandExec){ + EventCommandExec *ece = static_cast(e); + CommandDef *cmd = ece->cmd(); + if ((cmd->id == CmdSend) && (cmd->param == m_edit)){ + QString msgText = m_edit->m_edit->toPlainText(); + if (!msgText.isEmpty()){ + Message *msg = new Message; + msg->setText(msgText); + msg->setContact(m_edit->m_userWnd->id()); + msg->setClient(m_client); + msg->setFlags(MESSAGE_NOHISTORY); + KeyMsg km; + km.key = m_key; + km.msg = msg; + GpgPlugin::plugin->m_sendKeys.push_back(km); + EventRealSendMessage(msg, m_edit).process(); + } + return true; + } + } + return false; +} + diff --git a/plugins/gpg/gpg.h b/plugins/gpg/gpg.h new file mode 100644 index 0000000..48fa96d --- /dev/null +++ b/plugins/gpg/gpg.h @@ -0,0 +1,123 @@ +/*************************************************************************** + gpg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _GPG_H +#define _GPG_H + +#include "cfg.h" +#include "event.h" +#include "plugins.h" +#include "propertyhub.h" + +#include +#include +#include +#include + +const unsigned long MessageGPGKey = 0x5000; +const unsigned long MessageGPGUse = 0x5001; + +struct GpgUserData +{ + SIM::Data Key; + SIM::Data Use; +}; + +class QProcess; + +struct DecryptMsg +{ + SIM::Message *msg; + QProcess *process; + QString infile; + QString outfile; + unsigned contact; + QString passphrase; + QString key; +}; + +struct KeyMsg +{ + QString key; + SIM::Message *msg; +}; + +class GpgPlugin : public QObject, public SIM::Plugin, public SIM::EventReceiver +{ + Q_OBJECT +public: + GpgPlugin(unsigned, Buffer*); + virtual ~GpgPlugin(); + + QString GPG(); + void reset(); + static GpgPlugin *plugin; + QList m_sendKeys; + unsigned long user_data_id; + QString getHomeDir(); + + void setPropertyHub(SIM::PropertyHubPtr hub); + SIM::PropertyHubPtr propertyHub(); + QVariant value(const QString& key); + void setValue(const QString& key, const QVariant& v); + +protected slots: + void decryptReady(); + void importReady(); + void publicReady(); + void clear(); + void passphraseFinished(); + void passphraseApply(const QString&); +protected: + virtual QWidget *createConfigWindow(QWidget *parent); + virtual QByteArray getConfig(); + virtual bool processEvent(SIM::Event *e); + void registerMessage(); + void unregisterMessage(); + void askPassphrase(); + bool decode(SIM::Message *msg, const QString &pass, const QString &key); + bool m_bMessage; + QList m_decrypt; + QList m_import; + QList m_public; + QList m_wait; + class PassphraseDlg *m_passphraseDlg; +private: + SIM::PropertyHubPtr m_propertyHub; +}; + +class MsgEdit; + +class MsgGPGKey : public QObject, public SIM::EventReceiver +{ + Q_OBJECT +public: + MsgGPGKey(MsgEdit *parent, SIM::Message *msg); + ~MsgGPGKey(); +protected slots: + void init(); + void exportReady(); +protected: + virtual bool processEvent(SIM::Event *e); + QString m_client; + QString m_key; + MsgEdit *m_edit; + QProcess *m_process; +}; + +#endif + diff --git a/plugins/gpg/gpg.rc b/plugins/gpg/gpg.rc new file mode 100644 index 0000000..5da6a7d --- /dev/null +++ b/plugins/gpg/gpg.rc @@ -0,0 +1,97 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,9,6,0 + PRODUCTVERSION 0,9,6,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Vladimir Shutoff\0" + VALUE "FileDescription", "About plugin\0" + VALUE "FileVersion", "0, 9, 6, 0\0" + VALUE "InternalName", "about\0" + VALUE "LegalCopyright", "Copyright © 2002-2003\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "about.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "SIM\0" + VALUE "ProductVersion", "0, 9, 6, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/gpg/gpg.vcproj b/plugins/gpg/gpg.vcproj new file mode 100644 index 0000000..47492be --- /dev/null +++ b/plugins/gpg/gpg.vcproj @@ -0,0 +1,761 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/gpg/gpg_pch.h b/plugins/gpg/gpg_pch.h new file mode 100644 index 0000000..465057f --- /dev/null +++ b/plugins/gpg/gpg_pch.h @@ -0,0 +1,46 @@ +#pragma once + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef NO_QT_MOC_HEADER +#include +//#include +//#include +#endif + +#include "gpg.h" +#include "gpgadv.h" +#include "ui_gpgadvbase.h" +#include "gpgcfg.h" +#include "ui_gpgcfgbase.h" +#include "gpgfind.h" +#include "ui_gpgfindbase.h" +#include "gpggen.h" +#include "ui_gpggenbase.h" +#include "passphrase.h" +#include "ui_passphrasebase.h" diff --git a/plugins/gpg/gpgadv.cpp b/plugins/gpg/gpgadv.cpp new file mode 100644 index 0000000..7b23896 --- /dev/null +++ b/plugins/gpg/gpgadv.cpp @@ -0,0 +1,51 @@ +/*************************************************************************** + gpgadv.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "gpgadv.h" +#include "gpg.h" + +#include + +GpgAdvanced::GpgAdvanced(QWidget *parent, GpgPlugin *plugin) : QWidget(parent) +{ + setupUi(this); + m_plugin = plugin; + edtGenKey->setText(m_plugin->value("GenKey").toString()); + edtPublic->setText(m_plugin->value("PublicList").toString()); + edtSecret->setText(m_plugin->value("SecretList").toString()); + edtExport->setText(m_plugin->value("Export").toString()); + edtImport->setText(m_plugin->value("Import").toString()); + edtEncrypt->setText(m_plugin->value("Encrypt").toString()); + edtDecrypt->setText(m_plugin->value("Decrypt").toString()); +} + +GpgAdvanced::~GpgAdvanced() +{ +} + +void GpgAdvanced::apply() +{ + m_plugin->setValue("GenKey", edtGenKey->text()); + m_plugin->setValue("PublicList", edtPublic->text()); + m_plugin->setValue("SecretList", edtSecret->text()); + m_plugin->setValue("Export", edtExport->text()); + m_plugin->setValue("Import", edtImport->text()); + m_plugin->setValue("Encrypt", edtEncrypt->text()); + m_plugin->setValue("Decrypt", edtDecrypt->text()); +} + + diff --git a/plugins/gpg/gpgadv.h b/plugins/gpg/gpgadv.h new file mode 100644 index 0000000..bed738e --- /dev/null +++ b/plugins/gpg/gpgadv.h @@ -0,0 +1,38 @@ +/*************************************************************************** + gpgadv.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _GPGADV_H +#define _GPGADV_H + +#include "ui_gpgadvbase.h" + +class GpgPlugin; + +class GpgAdvanced : public QWidget, public Ui::GpgAdvanced +{ + Q_OBJECT +public: + GpgAdvanced(QWidget *parent, GpgPlugin *plugin); + ~GpgAdvanced(); +public slots: + void apply(); +protected: + GpgPlugin *m_plugin; +}; + +#endif + diff --git a/plugins/gpg/gpgadvbase.ui b/plugins/gpg/gpgadvbase.ui new file mode 100644 index 0000000..0383fa6 --- /dev/null +++ b/plugins/gpg/gpgadvbase.ui @@ -0,0 +1,164 @@ + + + GpgAdvanced + + + + 0 + 0 + 499 + 276 + + + + Form1 + + + + 6 + + + 11 + + + + + GroupBox + + + + + + Generate key: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + List public keys: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + List secret keys: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Import public: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Export public: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Encrypt: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Decrypt: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + diff --git a/plugins/gpg/gpgcfg.cpp b/plugins/gpg/gpgcfg.cpp new file mode 100644 index 0000000..7f0b3b4 --- /dev/null +++ b/plugins/gpg/gpgcfg.cpp @@ -0,0 +1,244 @@ +/*************************************************************************** + gpgcfg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "misc.h" + +#include "gpg.h" +#include "gpgcfg.h" +#include "simgui/ballonmsg.h" +#include "simgui/editfile.h" +#include "simgui/linklabel.h" +#ifdef WIN32 +#include "gpgfind.h" +#endif +#include "gpgadv.h" +#include "gpggen.h" + +#include +#include +#include +#include +#include + +using namespace SIM; + +GpgCfg::GpgCfg(QWidget *parent, GpgPlugin *plugin) : QWidget(parent) +{ + setupUi(this); + m_plugin = plugin; + m_process= NULL; + m_bNew = false; +#ifdef WIN32 + edtGPG->setText(m_plugin->GPG()); + edtGPG->setFilter(i18n("GPG(gpg.exe)")); + m_find = NULL; +#else + lblGPG->hide(); + edtGPG->hide(); +#endif + edtHome->setText(m_plugin->getHomeDir()); + edtHome->setDirMode(true); + edtHome->setShowHidden(true); + edtHome->setTitle(i18n("Select home directory")); + lnkGPG->setUrl("http://www.gnupg.org/(en)/download/index.html"); + lnkGPG->setText(i18n("Download GPG")); + connect(btnFind, SIGNAL(clicked()), this, SLOT(find())); + connect(edtGPG, SIGNAL(textChanged(const QString&)), this, SLOT(textChanged(const QString&))); + textChanged(edtGPG->text()); + for (QObject *p = parent; p != NULL; p = p->parent()){ + if (!p->inherits("QTabWidget")) + continue; + QTabWidget *tab = static_cast(p); + m_adv = new GpgAdvanced(tab, plugin); + tab->addTab(m_adv, i18n("&Advanced")); + tab->adjustSize(); + break; + } + connect(btnRefresh, SIGNAL(clicked()), this, SLOT(refresh())); + connect(cmbKey, SIGNAL(activated(int)), this, SLOT(selectKey(int))); + fillSecret(); + refresh(); +} + +GpgCfg::~GpgCfg() +{ +} + +void GpgCfg::apply() +{ + QString key; + int nKey = cmbKey->currentIndex(); + if (nKey && (nKey < cmbKey->count() - 1)){ + QString k = cmbKey->currentText(); + key = getToken(k, ' '); + } + m_plugin->setValue("Key", key); +#ifdef WIN32 + m_plugin->setValue("GPG", edtGPG->text()); +#endif + m_plugin->setValue("Home", edtHome->text()); + m_adv->apply(); + m_plugin->reset(); +} + +#ifdef WIN32 +void GpgCfg::textChanged(const QString &str) +{ + if (str.isEmpty()){ + lnkGPG->show(); + btnFind->show(); + }else{ + lnkGPG->hide(); + btnFind->hide(); + } +} +#else +void GpgCfg::textChanged(const QString&) +{ + lnkGPG->hide(); + btnFind->hide(); +} +#endif + +void GpgCfg::find() +{ +#ifdef WIN32 + if (m_find == NULL){ + m_find = new GpgFind(edtGPG); + connect(m_find, SIGNAL(finished()), this, SLOT(findFinished())); + } + raiseWindow(m_find); +#endif +} + +void GpgCfg::findFinished() +{ +#ifdef WIN32 + m_find = NULL; +#endif +} + +void GpgCfg::fillSecret(const QByteArray &ba) +{ + int cur = 0; + int n = 1; + cmbKey->clear(); + cmbKey->addItem(i18n("None")); + if (!ba.isEmpty()){ + QByteArray all(ba); + for (;;){ + QByteArray line = getToken(all, '\n'); + if(line.isEmpty()) + break; + QByteArray type = getToken(line, ':'); + if (type == "sec"){ + getToken(line, ':'); + getToken(line, ':'); + getToken(line, ':'); + QString sign = QString::fromLocal8Bit(getToken(line, ':')); + if (sign == m_plugin->value("Key").toString()) + cur = n; + getToken(line, ':'); + getToken(line, ':'); + getToken(line, ':'); + getToken(line, ':'); + QString name = QString::fromLocal8Bit(getToken(line, ':')); + cmbKey->addItem(sign + QString(" - ") + name); + n++; + } + } + } + cmbKey->addItem(i18n("New")); + if (m_bNew){ + cur = cmbKey->count() - 2; + m_bNew = false; + } + cmbKey->setCurrentIndex(cur); +} + +void GpgCfg::refresh() +{ +#ifdef WIN32 + QString gpg = edtGPG->text(); +#else + QString gpg = m_plugin->GPG(); +#endif + QString home = edtHome->text(); + + if (gpg.isEmpty() || home.isEmpty()){ + fillSecret(); + return; + } + if (m_process) + return; + + QStringList sl; + sl += gpg; + sl += "--no-tty"; + sl += "--homedir"; + sl += home; + sl += GpgPlugin::plugin->value("SecretList").toString().split(' '); + + m_process = new QProcess(this); + + connect(m_process, SIGNAL(processExited()), this, SLOT(secretReady())); + m_process->start(sl.join(" ")); +} + +void GpgCfg::secretReady() +{ + if (m_process->exitStatus() == QProcess::NormalExit && m_process->exitCode() == 0) { + m_process->setReadChannel(QProcess::StandardOutput); + fillSecret(m_process->readAll()); + } else { + QByteArray ba1, ba2; + m_process->setReadChannel(QProcess::StandardError); + ba1 = m_process->readAll(); + m_process->setReadChannel(QProcess::StandardOutput); + ba2 = m_process->readAll(); + QString s(" ("); + if (!ba1.isEmpty()) + s += QString::fromLocal8Bit(ba1.data(), ba1.size()); + if (!ba2.isEmpty()) { + if(!s.isEmpty()) + s += ' '; + s += QString::fromLocal8Bit(ba2.data(), ba2.size()); + } + s += ')'; + if(s == " ()") + s = QString::null; + BalloonMsg::message(i18n("Get secret list failed") + s, btnRefresh); + } + delete m_process; + m_process = 0; +} + +void GpgCfg::selectKey(int n) +{ + if (n == cmbKey->count() - 1){ + if(edtHome->text().isEmpty()) + edtHome->setText(m_plugin->getHomeDir()); + GpgGen gen(this); + if (gen.exec()){ + m_bNew = true; + QTimer::singleShot(0, this, SLOT(refresh())); + } + } +} + +// vim: set expandtab: + diff --git a/plugins/gpg/gpgcfg.h b/plugins/gpg/gpgcfg.h new file mode 100644 index 0000000..559a112 --- /dev/null +++ b/plugins/gpg/gpgcfg.h @@ -0,0 +1,57 @@ +/*************************************************************************** + gpgcfg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _GPGCFG_H +#define _GPGCFG_H + +#include "ui_gpgcfgbase.h" + +class GpgPlugin; +class GpgAdvanced; +class QProcess; + +#ifdef WIN32 +class GpgFind; +#endif + +class GpgCfg : public QWidget, public Ui::GpgCfgBase +{ + Q_OBJECT +public: + GpgCfg(QWidget *parent, GpgPlugin *plugin); + ~GpgCfg(); +public slots: + void apply(); + void refresh(); + void textChanged(const QString&); + void find(); + void findFinished(); + void secretReady(); + void selectKey(int); +protected: + void fillSecret(const QByteArray &ba = QByteArray()); + bool m_bNew; + QProcess *m_process; + GpgPlugin *m_plugin; +#ifdef WIN32 + GpgFind *m_find; +#endif + GpgAdvanced *m_adv; +}; + +#endif + diff --git a/plugins/gpg/gpgcfgbase.ui b/plugins/gpg/gpgcfgbase.ui new file mode 100644 index 0000000..f2690a1 --- /dev/null +++ b/plugins/gpg/gpgcfgbase.ui @@ -0,0 +1,222 @@ + + + + + GpgCfgBase + + + + 0 + 0 + 389 + 237 + + + + Form1 + + + + 11 + + + 6 + + + + + Executable: + + + Qt::AlignVCenter|Qt::AlignRight + + + false + + + + + + + + 7 + 5 + + + + + + + + Home directory: + + + Qt::AlignVCenter|Qt::AlignRight + + + false + + + + + + + + 7 + 5 + + + + + + + + 0 + + + 6 + + + + + + 7 + 1 + + + + + + + + &Find + + + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Vertical + + + + + + + 0 + + + 6 + + + + + Your key: + + + Qt::AlignVCenter|Qt::AlignRight + + + false + + + + + + + + 7 + 0 + + + + + + + + &Refresh + + + + + + + + + + QWidget + QWidget +
QWidget
+ + -1 + -1 + + 0 + + 5 + 5 + + image0 + + text + +
+ + EditFile + QWidget +
simgui/editfile.h
+ + -1 + -1 + + 0 + + 5 + 5 + + image1 +
+ + LinkLabel + QWidget +
simgui/linklabel.h
+ + -1 + -1 + + 0 + + 1 + 1 + + image1 + + text + +
+
+ + btnFind + cmbKey + btnRefresh + + + + 789c6dd2c10ac2300c00d07bbf2234b7229d1be245fc04c5a3201e4615f430059d0711ff5ddb2e6bb236ec90eed134cb5a19d8ef36602af5ecdbfeeac05dda0798d3abebde87e3faa374d3807fa0d633a52d38d8de6f679fe33fc776e196f53cd010188256a3600a292882096246517815ca99884606e18044a3a40d91824820924265a7923a2e8bcd05f33db1173e002913175f2a6be6d3294871a2d95fa00e8a94ee017b69d339d90df1e77c57ea072ede6758 + + + 789c6dd2c10ac2300c00d07bbf2234b7229d1ddec44f503c0ae2a154410f53d0ed20e2bf6bdb656dd6861dd23d9a66591b0587fd1654235ebded6f0edcd53e419d87ae7b1f4f9b8f906d0bfe012317426a70b07bdc2f3ec77f8ed6b89559061a0343d06a124cc105596482585094bc0ae599b04646c9018926491b2205e140c485cace25755c175d0a967b622ff900b8cc9c7d29af594ea722d589167f813aa852ba07d94b9dce296e883fe7bb163f23896753 + + +
diff --git a/plugins/gpg/gpgfind.cpp b/plugins/gpg/gpgfind.cpp new file mode 100644 index 0000000..d556f8d --- /dev/null +++ b/plugins/gpg/gpgfind.cpp @@ -0,0 +1,116 @@ +/*************************************************************************** + gpgfind.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include + +#include "simgui/editfile.h" +#include "icons.h" +#include "misc.h" + +#include "gpgfind.h" + +using namespace SIM; + +GpgFind::GpgFind(EditFile *edt) : QDialog(NULL) +{ + setupUi(this); + setAttribute(Qt::WA_DeleteOnClose, true); + setWindowIcon(Icon("find")); + setButtonsPict(this); + m_edit = edt; + connect(btnCancel, SIGNAL(clicked()), this, SLOT(close())); + //m_drives = *QDir::drives(); //portme + //m_drive = m_drives.first(); //portme + QTimer::singleShot(0, this, SLOT(next())); +} + +GpgFind::~GpgFind() +{ + emit finished(); +} + +void GpgFind::next() +{ + if (!m_tree.empty()){ + QStringList &subDirs = m_tree.top(); + unsigned pos = m_pos.top(); + if (pos >= (unsigned)subDirs.count()){ + m_tree.pop(); + m_pos.pop(); + m_path = m_path.left(m_path.length() - 1); + m_path = m_path.left(m_path.lastIndexOf('\\') + 1); + QTimer::singleShot(0, this, SLOT(next())); + return; + } + QString subDir = subDirs[pos++]; + m_pos.pop(); + m_pos.push(pos); + if (!subDir.startsWith(".")){ + m_path += subDir; + m_path += '\\'; + if (checkPath()) + return; + } + QTimer::singleShot(0, this, SLOT(next())); + return; + } + if (m_drive == NULL){ + close(); + return; + } + m_path = m_drive->absoluteFilePath(); + m_path = m_path.replace('/', '\\'); + if ((GetDriveTypeW((LPCWSTR)m_path.utf16()) == DRIVE_FIXED) && checkPath()) + return; + //m_drive = m_drives.next(); //portme + QTimer::singleShot(0, this, SLOT(next())); +} + +bool GpgFind::checkPath() +{ + QDir d(m_path); + if (!d.exists()) + return false; + QString p = m_path; + if (p.length() > 40){ + p = "..."; + p += m_path.mid(m_path.length() - 38); + } + lblPath->setText(p); + QFile f(m_path + "gpg.exe"); + if (f.exists()){ + m_edit->setText(m_path + "gpg.exe"); + QTimer::singleShot(0, this, SLOT(close())); + return true; + } + QStringList subDirs = d.entryList(QDir::Dirs); + if (!subDirs.isEmpty()){ + m_tree.push(subDirs); + m_pos.push(0); + }else{ + m_path = m_path.left(m_path.lastIndexOf('\\')); + } + return false; +} + diff --git a/plugins/gpg/gpgfind.h b/plugins/gpg/gpgfind.h new file mode 100644 index 0000000..c45e6de --- /dev/null +++ b/plugins/gpg/gpgfind.h @@ -0,0 +1,51 @@ +/*************************************************************************** + gpgfind.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _GPGFIND_H +#define _GPGFIND_H + +#include "ui_gpgfindbase.h" + +#include +#include +#include +#include + +class EditFile; + +class GpgFind : public QDialog, public Ui::GpgFindBase +{ + Q_OBJECT +public: + GpgFind(EditFile *edt); + ~GpgFind(); +signals: + void finished(); +protected slots: + void next(); +protected: + bool checkPath(); + QString m_path; + QStack m_tree; + QStack m_pos; + QFileInfoList m_drives; + QFileInfo *m_drive; + EditFile *m_edit; +}; + +#endif + diff --git a/plugins/gpg/gpgfindbase.ui b/plugins/gpg/gpgfindbase.ui new file mode 100644 index 0000000..4388cb0 --- /dev/null +++ b/plugins/gpg/gpgfindbase.ui @@ -0,0 +1,86 @@ + + + + + GpgFindBase + + + + 0 + 0 + 358 + 97 + + + + Find GPG + + + true + + + + 11 + + + 6 + + + + + + 1 + 7 + + + + + + + false + + + + + + + &Cancel + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Horizontal + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Horizontal + + + + + + qPixmapFromMimeSource + diff --git a/plugins/gpg/gpggen.cpp b/plugins/gpg/gpggen.cpp new file mode 100644 index 0000000..421c704 --- /dev/null +++ b/plugins/gpg/gpggen.cpp @@ -0,0 +1,188 @@ +/*************************************************************************** + gpggen.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "misc.h" +#include "icons.h" + +#include "gpggen.h" +#include "gpgcfg.h" +#include "gpg.h" + +#include "simgui/ballonmsg.h" +#include "simgui/editfile.h" +#include "contacts/group.h" +#include "contacts/contact.h" + +#include +#include +#include +#include +#include +#include + +using namespace SIM; + +GpgGen::GpgGen(GpgCfg *cfg) : QDialog() +{ + setupUi(this); + setModal(true); + SET_WNDPROC("genkey") + setWindowIcon(Icon("encrypted")); + setButtonsPict(this); + cmbMail->setEditable(true); + m_process = NULL; + m_cfg = cfg; + connect(edtName, SIGNAL(textChanged(const QString&)), this, SLOT(textChanged(const QString&))); + connect(edtPass1, SIGNAL(textChanged(const QString&)), this, SLOT(textChanged(const QString&))); + connect(edtPass2, SIGNAL(textChanged(const QString&)), this, SLOT(textChanged(const QString&))); + connect(cmbMail->lineEdit(), SIGNAL(textChanged(const QString&)), this, SLOT(textChanged(const QString&))); + Contact *owner = getContacts()->owner(); + if (owner){ + QString name; + name = owner->getFirstName(); + QString firstName = getToken(name, '/'); + name = owner->getLastName(); + QString lastName = getToken(name, '/'); + + if (firstName.isEmpty() || lastName.isEmpty()){ + name = firstName + lastName; + }else{ + name = firstName + ' ' + lastName; + } + edtName->setText(name); + QString mails = owner->getEMails(); + while (!mails.isEmpty()){ + QString item = getToken(mails, ';'); + QString mail = getToken(item, '/'); + cmbMail->addItem(mail); + } + } +} + +GpgGen::~GpgGen() +{ + delete m_process; +} + +void GpgGen::textChanged(const QString&) +{ + buttonOk->setEnabled(!edtName->text().isEmpty() && + !cmbMail->lineEdit()->text().isEmpty() && + (edtPass1->text() == edtPass2->text())); +} + +#ifdef WIN32 + #define CRLF "\r\n" +#else + #define CRLF "\n" +#endif + +void GpgGen::accept() +{ + edtName->setEnabled(false); + cmbMail->setEnabled(false); + edtComment->setEnabled(false); + buttonOk->setEnabled(false); +#ifdef WIN32 + QString gpg = m_cfg->edtGPG->text(); +#else + QString gpg = GpgPlugin::plugin->GPG(); +#endif + QString home = m_cfg->edtHome->text(); + if (gpg.isEmpty() || home.isEmpty()) + return; + lblProcess->setText(i18n("Move mouse for generate random key")); + if (home.endsWith("\\") || home.endsWith("/")) + home = home.left(home.length() - 1); + QString in = + "Key-Type: 1" CRLF + "Key-Length: 1024" CRLF + "Expire-Date: 0" CRLF + "Name-Real: "; + in += edtName->text(); + in += CRLF; + if (!edtComment->text().isEmpty()){ + in += "Name-Comment: "; + in += edtComment->text(); + in += CRLF; + } + in += "Name-Email: "; + in += cmbMail->lineEdit()->text(); + in += CRLF; + if (!edtPass1->text().isEmpty()){ + in += "Passphrase: "; + in += edtPass1->text(); + in += CRLF; + } + QString fname = user_file("keys/genkey.txt"); + QFile f(fname); + f.open(QIODevice::WriteOnly | QIODevice::Truncate); + f.write(in.toUtf8()); + f.close(); + + QStringList sl; + sl += gpg; + sl += "--no-tty"; + sl += "--homedir"; + sl += home; + sl += GpgPlugin::plugin->value("GenKey").toString().split(' '); + sl += fname; + + delete m_process; // to be sure... + m_process = new QProcess(this); + + connect(m_process, SIGNAL(finished()), this, SLOT(genKeyReady())); + + m_process->start(sl.join(" ")); +} + +void GpgGen::genKeyReady() +{ + QFile::remove(user_file("keys/genkey.txt")); + if(m_process->exitStatus() == QProcess::NormalExit && m_process->exitCode() == 0) + { + QDialog::accept(); + } + else + { + QByteArray ba1, ba2; + m_process->setReadChannel(QProcess::StandardError); + ba1 = m_process->readAll(); + m_process->setReadChannel(QProcess::StandardOutput); + ba2 = m_process->readAll(); + QString s(" ("); + if (!ba1.isEmpty()) + s += QString::fromLocal8Bit(ba1.data(), ba1.size()); + if (!ba2.isEmpty()) { + if(!s.isEmpty()) + s += ' '; + s += QString::fromLocal8Bit(ba2.data(), ba2.size()); + } + s += ')'; + if(s == " ()") + s = QString::null; + edtName->setEnabled(true); + cmbMail->setEnabled(true); + edtComment->setEnabled(true); + lblProcess->setText(QString::null); + buttonOk->setEnabled(true); + BalloonMsg::message(i18n("Generate key failed") + s, buttonOk); + } + delete m_process; + m_process = 0; +} + diff --git a/plugins/gpg/gpggen.h b/plugins/gpg/gpggen.h new file mode 100644 index 0000000..76a3702 --- /dev/null +++ b/plugins/gpg/gpggen.h @@ -0,0 +1,42 @@ +/*************************************************************************** + gpggen.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _GPGGEN_H +#define _GPGGEN_H + +#include "ui_gpggenbase.h" + +class QProcess; +class GpgCfg; + +class GpgGen : public QDialog, public Ui::GpgGenBase +{ + Q_OBJECT +public: + GpgGen(GpgCfg *parent); + ~GpgGen(); +protected slots: + void textChanged(const QString&); + void genKeyReady(); +protected: + void accept(); + QProcess *m_process; + GpgCfg *m_cfg; +}; + +#endif + diff --git a/plugins/gpg/gpggenbase.ui b/plugins/gpg/gpggenbase.ui new file mode 100644 index 0000000..6b540d5 --- /dev/null +++ b/plugins/gpg/gpggenbase.ui @@ -0,0 +1,210 @@ + + + + + GpgGenBase + + + + 0 + 0 + 385 + 241 + + + + Generate key + + + true + + + + 11 + + + 6 + + + + + EMail: + + + Qt::AlignVCenter|Qt::AlignRight + + + false + + + + + + + Comment: + + + Qt::AlignVCenter|Qt::AlignRight + + + false + + + + + + + Name: + + + Qt::AlignVCenter|Qt::AlignRight + + + false + + + + + + + + + + + + + + + + Passphrase: + + + Qt::AlignVCenter|Qt::AlignRight + + + false + + + + + + + Retype passphrase: + + + Qt::AlignVCenter|Qt::AlignRight + + + false + + + + + + + QLineEdit::Password + + + + + + + QLineEdit::Password + + + + + + + + 7 + 7 + + + + + + + Qt::AlignCenter + + + false + + + + + + + 0 + + + 6 + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Horizontal + + + + + + + &OK + + + true + + + true + + + + + + + &Cancel + + + true + + + + + + + + qPixmapFromMimeSource + + edtName + cmbMail + edtComment + edtPass1 + edtPass2 + buttonOk + buttonCancel + + + + buttonOk + clicked() + GpgGen + accept() + + + buttonCancel + clicked() + GpgGen + reject() + + + diff --git a/plugins/gpg/gpguser.cpp b/plugins/gpg/gpguser.cpp new file mode 100644 index 0000000..1c99a29 --- /dev/null +++ b/plugins/gpg/gpguser.cpp @@ -0,0 +1,120 @@ +/*************************************************************************** + gpguser.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "misc.h" + +#include "gpguser.h" +#include "gpg.h" + + +#include +#include +#include +#include + + +using namespace SIM; + +GpgUser::GpgUser(QWidget *parent, GpgUserData *data) : QWidget(parent) +{ + setupUi(this); + if(data) + m_key = data->Key.str(); + m_process = NULL; + connect(btnRefresh, SIGNAL(clicked()), this, SLOT(refresh())); + refresh(); +} + +GpgUser::~GpgUser() +{ + delete m_process; +} + +void GpgUser::apply(void *_data) +{ + GpgUserData *data = (GpgUserData*)_data; + QString key; + int nKey = cmbPublic->currentIndex(); + if (nKey && (nKey < cmbPublic->count())){ + QString k = cmbPublic->currentText(); + key = getToken(k, ' '); + } + data->Key.str() = key; + if (key.isEmpty()) + data->Use.asBool() = false; +} + +void GpgUser::refresh() +{ + if (m_process) + return; + QString gpg = GpgPlugin::plugin->GPG(); + QString home = GpgPlugin::plugin->getHomeDir(); + if (gpg.isEmpty() || home.isEmpty()) + return; + + QStringList sl; + sl += gpg; + sl += "--no-tty"; + sl += "--homedir"; + sl += home; + sl += GpgPlugin::plugin->value("PublicList").toString().split(' '); + + m_process = new QProcess(this); + + connect(m_process, SIGNAL(processExited()), this, SLOT(publicReady())); + m_process->start(sl.join(" ")); +} + +void GpgUser::publicReady() +{ + int cur = 0; + int n = 1; + cmbPublic->clear(); + cmbPublic->insertItem(INT_MAX,i18n("None")); + if (m_process->exitStatus() == QProcess::NormalExit && m_process->exitCode() == 0){ + m_process->setReadChannel(QProcess::StandardOutput); + QByteArray str(m_process->readAll()); + for (;;){ + QByteArray line; + line = getToken(str, '\n'); + if(line.isEmpty()) + break; + QByteArray type = getToken(line, ':'); + if (type == "pub"){ + getToken(line, ':'); + getToken(line, ':'); + getToken(line, ':'); + QByteArray sign = getToken(line, ':'); + if (QString::fromLocal8Bit(sign) == m_key) + cur = n; + getToken(line, ':'); + getToken(line, ':'); + getToken(line, ':'); + getToken(line, ':'); + QByteArray name = getToken(line, ':'); + cmbPublic->insertItem(INT_MAX,QString::fromLocal8Bit(sign) + QString(" - ") + + QString::fromLocal8Bit(name)); + n++; + } + } + } + cmbPublic->setCurrentIndex(cur); + delete m_process; + m_process = 0; +} + diff --git a/plugins/gpg/gpguser.h b/plugins/gpg/gpguser.h new file mode 100644 index 0000000..bb68a68 --- /dev/null +++ b/plugins/gpg/gpguser.h @@ -0,0 +1,43 @@ +/*************************************************************************** + gpguser.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _GPGUSER_H +#define _GPGUSER_H + +#include "ui_gpguserbase.h" + +struct GpgUserData; +class GpgPlugin; +class QProcess; + +class GpgUser : public QWidget, public Ui::GpgUserBase +{ + Q_OBJECT +public: + GpgUser(QWidget *parent, GpgUserData *data); + ~GpgUser(); +public slots: + void apply(void *data); + void refresh(); + void publicReady(); +protected: + QProcess *m_process; + QString m_key; +}; + +#endif + diff --git a/plugins/gpg/gpguserbase.ui b/plugins/gpg/gpguserbase.ui new file mode 100644 index 0000000..570347e --- /dev/null +++ b/plugins/gpg/gpguserbase.ui @@ -0,0 +1,98 @@ + + + + + GpgUserBase + + + + 0 + 0 + 452 + 159 + + + + Form1 + + + + 11 + + + 6 + + + + + Key: + + + Qt::AlignVCenter|Qt::AlignRight + + + false + + + + + + + + 7 + 0 + + + + + + + + &Refresh + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Vertical + + + + + + + + QWidget + QWidget +
QWidget
+ + -1 + -1 + + 0 + + 5 + 5 + + image0 + + text + +
+
+ + + 789c6dd2c10ac2300c00d07bbf2234b7229d1be245fc04c5a3201e4615f430059d0711ff5ddb2e6bb236ec90eed134cb5a19d8ef36602af5ecdbfeeac05dda0798d3abebde87e3faa374d3807fa0d633a52d38d8de6f679fe33fc776e196f53cd010188256a3600a292882096246517815ca99884606e18044a3a40d91824820924265a7923a2e8bcd05f33db1173e002913175f2a6be6d3294871a2d95fa00e8a94ee017b69d339d90df1e77c57ea072ede6758 + + +
diff --git a/plugins/gpg/passphrase.cpp b/plugins/gpg/passphrase.cpp new file mode 100644 index 0000000..7a3497b --- /dev/null +++ b/plugins/gpg/passphrase.cpp @@ -0,0 +1,70 @@ +/*************************************************************************** + passphrase.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "icons.h" +#include "misc.h" + +#include "passphrase.h" +#include "gpg.h" +#include "simgui/ballonmsg.h" + +#include +#include +#include +#include +#include + +using namespace SIM; + +PassphraseDlg::PassphraseDlg(GpgPlugin *plugin, const QString &key) : QDialog(NULL) +{ + setupUi(this); + setAttribute(Qt::WA_DeleteOnClose, true); + setObjectName("passphrase"); + m_plugin = plugin; + SET_WNDPROC("passphrase") + setWindowIcon(Icon("encrypted")); + setButtonsPict(this); + m_key = key; + lblTitle->setText(i18n("Input passphrase for key %1") .arg(key)); + connect(edtPass, SIGNAL(textChanged(const QString&)), this, SLOT(textChanged(const QString&))); + btnOk->setEnabled(false); + chkSave->setChecked(m_plugin->value("SavePassphrase").toBool()); +} + +PassphraseDlg::~PassphraseDlg() +{ + emit finished(); +} + +void PassphraseDlg::accept() +{ + m_plugin->setValue("SavePassphrase", chkSave->isChecked()); + emit apply(edtPass->text()); +} + +void PassphraseDlg::textChanged(const QString &text) +{ + btnOk->setEnabled(!text.isEmpty()); +} + +void PassphraseDlg::error() +{ + raiseWindow(this); + BalloonMsg::message(i18n("Bad passphrase"), btnOk); +} + diff --git a/plugins/gpg/passphrase.h b/plugins/gpg/passphrase.h new file mode 100644 index 0000000..6341ca3 --- /dev/null +++ b/plugins/gpg/passphrase.h @@ -0,0 +1,44 @@ +/*************************************************************************** + passphrase.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _PASSPHRASE_H +#define _PASSPHRASE_H + +#include "ui_passphrasebase.h" + +class GpgPlugin; + +class PassphraseDlg : public QDialog, public Ui::PassphraseDlgBase +{ + Q_OBJECT +public: + PassphraseDlg(GpgPlugin *plugin, const QString &key); + ~PassphraseDlg(); + QString m_key; + void error(); +signals: + void finished(); + void apply(const QString &pass); +protected slots: + void textChanged(const QString&); +protected: + void accept(); + GpgPlugin *m_plugin; +}; + +#endif + diff --git a/plugins/gpg/passphrasebase.ui b/plugins/gpg/passphrasebase.ui new file mode 100644 index 0000000..d9de98e --- /dev/null +++ b/plugins/gpg/passphrasebase.ui @@ -0,0 +1,111 @@ + + + + + PassphraseDlgBase + + + + 0 + 0 + 388 + 119 + + + + Input passphrase + + + + 11 + + + 6 + + + + + + 7 + 7 + + + + + + + Qt::AlignVCenter|Qt::AlignLeft + + + true + + + + + + + &Save passphrase + + + + + + + QLineEdit::Password + + + + + + + &OK + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Horizontal + + + + + + + &Cancel + + + + + + qPixmapFromMimeSource + + edtPass + chkSave + btnOk + btnCancel + + + + btnOk + clicked() + Passphrase + accept() + + + btnCancel + clicked() + Passphrase + reject() + + + diff --git a/plugins/gpg/resource.h b/plugins/gpg/resource.h new file mode 100644 index 0000000..b4a4ae1 --- /dev/null +++ b/plugins/gpg/resource.h @@ -0,0 +1,18 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by gpg.rc +// +#define LANG_NEUTRAL 0 +#define SUBLANG_NEUTRAL 0 +#define IDI_ICON1 1 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 103 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/icons/CMakeLists.txt b/plugins/icons/CMakeLists.txt new file mode 100644 index 0000000..0b672a9 --- /dev/null +++ b/plugins/icons/CMakeLists.txt @@ -0,0 +1,23 @@ +################# +# icons library # +################# +IF(BUILD_DROPPED) +SET(icons_SRCS + icon.cpp + iconcfg.cpp +) + +SET(icons_HDRS + icon.h + iconcfg.h +) + +SET(icons_UICS + iconcfgbase.ui +) + +REMOVE_DEFINITIONS(-DQT3_SUPPORT) +REMOVE_DEFINITIONS(-DQT_3SUPPORT_LIB) +REMOVE_DEFINITIONS(-DQT3_SUPPORT_WARNINGS) +SIM_ADD_PLUGIN(icons) +ENDIF(BUILD_DROPPED) diff --git a/plugins/icons/icon.cpp b/plugins/icons/icon.cpp new file mode 100644 index 0000000..1234d87 --- /dev/null +++ b/plugins/icons/icon.cpp @@ -0,0 +1,129 @@ +/*************************************************************************** + icon.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "icons.h" +#include "misc.h" +#include "log.h" + +#include "profile.h" +#include "profilemanager.h" + +#include "icon.h" +#include "iconcfg.h" + +#include + +using namespace std; +using namespace SIM; + +Plugin *createIconsPlugin(unsigned base, bool, Buffer *config) +{ + Plugin *plugin = new IconsPlugin(base, config); + return plugin; +} + +static PluginInfo info = + { + I18N_NOOP("Icons"), + I18N_NOOP("Plugin provides JISP icons themes and emoticons"), + VERSION, + createIconsPlugin, + PLUGIN_NOLOAD_DEFAULT + }; + +EXPORT_PROC PluginInfo* GetPluginInfo() +{ + return &info; +} + +IconsPlugin::IconsPlugin(unsigned base, Buffer *config) + : QObject(), Plugin(base), EventReceiver(HighestPriority - 0x100) +{ + m_propertyHub = SIM::PropertyHub::create("icon"); + setIcons(false); +} + +IconsPlugin::~IconsPlugin() +{ + +} + +void IconsPlugin::setIcons(bool bForce) +{ + if (!bForce && value("Default").toBool()) + return; + getIcons()->removeIconSet(NULL); + if (value("Default").toBool()){ + getIcons()->addIconSet("icons/smile.jisp", false); + }else{ + const QStringList l = value("Icons").toStringList(); + for (unsigned i = 0; i < value("NIcons").toUInt(); i++) + { + if(i >= (unsigned)l.size()) + break; + getIcons()->addIconSet(l[i], false); + } + } + EventIconChanged().process(); +} + +QByteArray IconsPlugin::getConfig() +{ + return QByteArray(); +} + +bool IconsPlugin::processEvent(Event *e) +{ + switch (e->type()) + { + case eEventPluginLoadConfig: + { + PropertyHubPtr hub = ProfileManager::instance()->getPropertyHub("icon"); + if(!hub.isNull()) + setPropertyHub(hub); + setIcons(false); + break; + } + default: + break; + } + return false; +} +QWidget *IconsPlugin::createConfigWindow(QWidget *parent) +{ + return new IconCfg(parent, this); +} + +void IconsPlugin::setPropertyHub(SIM::PropertyHubPtr hub) +{ + m_propertyHub = hub; +} + +SIM::PropertyHubPtr IconsPlugin::propertyHub() +{ + return m_propertyHub; +} + +QVariant IconsPlugin::value(const QString& key) +{ + return m_propertyHub->value(key); +} + +void IconsPlugin::setValue(const QString& key, const QVariant& v) +{ + m_propertyHub->setValue(key, v); +} diff --git a/plugins/icons/icon.h b/plugins/icons/icon.h new file mode 100644 index 0000000..ec565f2 --- /dev/null +++ b/plugins/icons/icon.h @@ -0,0 +1,46 @@ +/*************************************************************************** + icon.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _ICON_H +#define _ICON_H + +#include "cfg.h" +#include "plugins.h" +#include "propertyhub.h" + + +class IconsPlugin : public QObject, public SIM::Plugin, public SIM::EventReceiver +{ +public: + IconsPlugin(unsigned, Buffer*); + virtual ~IconsPlugin(); + void setIcons(bool bForce); + + void setPropertyHub(SIM::PropertyHubPtr hub); + SIM::PropertyHubPtr propertyHub(); + QVariant value(const QString& key); + void setValue(const QString& key, const QVariant& v); +protected: + bool processEvent(SIM::Event *e); + virtual QWidget *createConfigWindow(QWidget *parent); + virtual QByteArray getConfig(); +private: + SIM::PropertyHubPtr m_propertyHub; +}; + +#endif + diff --git a/plugins/icons/iconcfg.cpp b/plugins/icons/iconcfg.cpp new file mode 100644 index 0000000..7706ae3 --- /dev/null +++ b/plugins/icons/iconcfg.cpp @@ -0,0 +1,132 @@ +/*************************************************************************** + iconcfg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "simapi.h" + +#include +#include + +#ifdef USE_KDE +# include +# define QFileDialog KFileDialog +#else +# include +#endif + +#include "icons.h" +#include "misc.h" + +#include "iconcfg.h" +#include "icon.h" + +IconCfg::IconCfg(QWidget *parent, IconsPlugin *plugin) + : QWidget(parent) + , m_plugin(plugin) +{ + setupUi(this); + connect(btnUp, SIGNAL(clicked()), this, SLOT(up())); + connect(btnDown, SIGNAL(clicked()), this, SLOT(down())); + connect(btnAdd, SIGNAL(clicked()), this, SLOT(add())); + connect(btnRemove, SIGNAL(clicked()), this, SLOT(remove())); + connect(lstIcon, SIGNAL(itemSelectionChanged()), this, SLOT(itemSelectionChanged())); + if (m_plugin->value("Default").toBool()){ + lstIcon->addItem(QDir::toNativeSeparators("icons/smiles.jisp")); + + }else{ + const QStringList l = m_plugin->value("Icons").toStringList(); + for (int i = 0; i < m_plugin->value("NIcons").toInt(); i++) + { + if(i >= l.size()) + break; + lstIcon->addItem(l[i]); + } + } + itemSelectionChanged(); +} + +void IconCfg::apply() +{ + m_plugin->setValue("Default", false); + QStringList l; + for (int i = 0; i < lstIcon->count(); i++) + l.append(lstIcon->item(i)->text()); + m_plugin->setValue("Icons", l); + m_plugin->setValue("NIcons", lstIcon->count()); + m_plugin->setIcons(true); +} + +void IconCfg::up() +{ + int n = lstIcon->currentRow(); + if (n < 1) + return; + QListWidgetItem *item = lstIcon->takeItem(n); + lstIcon->insertItem(n - 1, item); + if (n==lstIcon->count()-1) + lstIcon->setCurrentRow(lstIcon->currentRow()-1); + else + lstIcon->setCurrentRow(lstIcon->currentRow()-2); + + itemSelectionChanged(); +} + +void IconCfg::down() +{ + int n = lstIcon->currentRow(); + if ((n < 0) || (n >= lstIcon->count() - 1)) + return; + QListWidgetItem *item = lstIcon->takeItem(n); + lstIcon->insertItem(n + 1, item); + lstIcon->setCurrentRow(lstIcon->currentRow()+1); + itemSelectionChanged(); +} + +void IconCfg::add() +{ +#ifdef USE_KDE + QString filter = i18n("*.jisp|Icon set"); +#else + QString filter = i18n("Icon set(*.jisp)"); +#endif + QString jisp = QFileDialog::getOpenFileName(topLevelWidget(), i18n("Select icon set"), SIM::app_file("icons/"), filter); + if (!jisp.isEmpty()) { + int n = lstIcon->currentRow(); + lstIcon->insertItem(n, QDir::toNativeSeparators(jisp)); + itemSelectionChanged(); + } +} + +void IconCfg::remove() +{ + delete lstIcon->takeItem(lstIcon->currentRow()); + itemSelectionChanged(); +} + +void IconCfg::itemSelectionChanged() +{ + int n = lstIcon->currentRow(); + if (n < 0){ + btnUp->setEnabled(false); + btnDown->setEnabled(false); + btnRemove->setEnabled(false); + return; + } + btnRemove->setEnabled(true); + btnUp->setEnabled(n > 0); + btnDown->setEnabled(n < lstIcon->count() - 1); +} + diff --git a/plugins/icons/iconcfg.h b/plugins/icons/iconcfg.h new file mode 100644 index 0000000..790638f --- /dev/null +++ b/plugins/icons/iconcfg.h @@ -0,0 +1,43 @@ +/*************************************************************************** + iconcfg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _ICONCFG_H +#define _ICONCFG_H + + +#include "ui_iconcfgbase.h" + +class IconsPlugin; + +class IconCfg : public QWidget, public Ui::IconCfgBase +{ + Q_OBJECT +public: + IconCfg(QWidget *parent, IconsPlugin *plugin); +public slots: + void apply(); + void up(); + void down(); + void add(); + void remove(); + void itemSelectionChanged(); +protected: + IconsPlugin *m_plugin; +}; + +#endif + diff --git a/plugins/icons/iconcfgbase.ui b/plugins/icons/iconcfgbase.ui new file mode 100644 index 0000000..534937e --- /dev/null +++ b/plugins/icons/iconcfgbase.ui @@ -0,0 +1,84 @@ + + + IconCfgBase + + + + 0 + 0 + 459 + 322 + + + + Form1 + + + + 11 + + + 6 + + + + + &Up + + + true + + + + + + + &Down + + + + + + + &Remove + + + + + + + &New + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + + + btnUp + btnDown + btnAdd + btnRemove + lstIcon + + + + diff --git a/plugins/icons/icons.rc b/plugins/icons/icons.rc new file mode 100644 index 0000000..4e48104 --- /dev/null +++ b/plugins/icons/icons.rc @@ -0,0 +1,97 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,9,6,0 + PRODUCTVERSION 0,9,6,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Vladimir Shutoff\0" + VALUE "FileDescription", "Icons plugin\0" + VALUE "FileVersion", "0, 9, 6, 0\0" + VALUE "InternalName", "icons\0" + VALUE "LegalCopyright", "Copyright © 2002-2003\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "icons.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "SIM\0" + VALUE "ProductVersion", "0, 9, 6, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/icons/icons.vcproj b/plugins/icons/icons.vcproj new file mode 100644 index 0000000..4669928 --- /dev/null +++ b/plugins/icons/icons.vcproj @@ -0,0 +1,372 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/icq/CMakeLists.txt b/plugins/icq/CMakeLists.txt new file mode 100644 index 0000000..487bb0f --- /dev/null +++ b/plugins/icq/CMakeLists.txt @@ -0,0 +1,105 @@ +############### +# icq library # +############### +SET(icq_SRCS + aboutinfo.cpp + advsearch.cpp + aimconfig.cpp + aiminfo.cpp + aimsearch.cpp + aimservices.cpp + encodingdlg.cpp + homeinfo.cpp + icq.cpp + icqbos.cpp + icqbuddy.cpp + icqbuffer.cpp + icqclient.cpp + icqconfig.cpp + icqdirect.cpp + icqicmb.cpp + icqinfo.cpp + icqlists.cpp + icqlocation.cpp + icqlogin.cpp + icqmessage.cpp + icqpicture.cpp + icqping.cpp + icqsearch.cpp + icqsecure.cpp + icqservice.cpp + icqssbi.cpp + icqstatus.cpp + icqvarious.cpp + interestsinfo.cpp + moreinfo.cpp + pastinfo.cpp + polling.cpp + rtfgen.cpp + securedlg.cpp + verifydlg.cpp + warndlg.cpp + workinfo.cpp + xml.cpp + snac.cpp +) + +SET(icq_HDRS + aboutinfo.h + advsearch.h + aimconfig.h + aiminfo.h + aimsearch.h + encodingdlg.h + homeinfo.h + icq.h + icqbuffer.h + icqclient.h + icqconfig.h + icqinfo.h + icqlocation.h + icqmessage.h + icqdirect.h + icqicmb.h + icqpicture.h + icqsearch.h + icqsecure.h + icqssbi.h + icqstatus.h + interestsinfo.h + moreinfo.h + pastinfo.h + polling.h + securedlg.h + verifydlg.h + warndlg.h + workinfo.h + xml.h + snac.h +) + +SET(icq_UICS + aboutinfobase.ui + advsearchbase.ui + aimconfigbase.ui + aiminfobase.ui + aimsearchbase.ui + encodingdlgbase.ui + homeinfobase.ui + icqconfigbase.ui + icqinfobase.ui + icqpicturebase.ui + icqsearchbase.ui + icqsecurebase.ui + interestsinfobase.ui + moreinfobase.ui + pastinfobase.ui + securedlgbase.ui + verifydlgbase.ui + warndlgbase.ui + workinfobase.ui +) + +ADD_FLEX_FILES(icq_SRCS rtf.ll) + +SIM_ADD_PLUGIN(icq) diff --git a/plugins/icq/aboutinfo.cpp b/plugins/icq/aboutinfo.cpp new file mode 100644 index 0000000..0014da0 --- /dev/null +++ b/plugins/icq/aboutinfo.cpp @@ -0,0 +1,83 @@ +/*************************************************************************** + aboutinfo.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "aboutinfo.h" +#include "icqclient.h" +#include "simgui/textshow.h" +#include "contacts/contact.h" + +using namespace SIM; + +AboutInfo::AboutInfo(QWidget *parent, ICQUserData *data, unsigned contact, ICQClient *client) : QWidget(parent) +{ + setupUi(this); + m_data = data; + m_client = client; + if (m_data) + edtAbout->setReadOnly(true); + m_contact = contact; + fill(); +} + +void AboutInfo::apply() +{ +} + +void AboutInfo::apply(Client *client, void *_data) +{ + if (client != m_client) + return; + ICQUserData *data = m_client->toICQUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + data->About.str() = edtAbout->toPlainText(); +} + +bool AboutInfo::processEvent(Event *e) +{ + if (e->type() == eEventContact){ + EventContact *ec = static_cast(e); + if(ec->action() != EventContact::eChanged) + return false; + Contact *contact = ec->contact(); + if (contact->clientData.have(m_data)) + fill(); + } + if ((e->type() == eEventClientChanged) && (m_data == 0)){ + EventClientChanged *ecc = static_cast(e); + if (ecc->client() == m_client) + fill(); + } + return false; +} + +void AboutInfo::fill() +{ + ICQUserData *data = m_data; + if(data == NULL) data = &m_client->data.owner; + if(data->Uin.toULong()) + { +// edtAbout->setTextFormat(Qt::PlainText); + edtAbout->setText(data->About.str()); + } + else + { +// edtAbout->setTextFormat(Qt::RichText); + edtAbout->setText(data->About.str()); + //if (m_data == NULL) + //edtAbout->showBar(); + } +} + diff --git a/plugins/icq/aboutinfo.h b/plugins/icq/aboutinfo.h new file mode 100644 index 0000000..fa9407c --- /dev/null +++ b/plugins/icq/aboutinfo.h @@ -0,0 +1,45 @@ +/*************************************************************************** + aboutinfo.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _ABOUTINFO_H +#define _ABOUTINFO_H + +#include "contacts.h" + +#include "ui_aboutinfobase.h" + +class ICQClient; +struct ICQUserData; + +class AboutInfo : public QWidget, public Ui::aboutInfo, public SIM::EventReceiver +{ + Q_OBJECT +public: + AboutInfo(QWidget *parent, ICQUserData *data, unsigned contact, ICQClient *client); +public slots: + void apply(); + void apply(SIM::Client*, void*); +protected: + virtual bool processEvent(SIM::Event *e); + void fill(); + ICQUserData *m_data; + unsigned m_contact; + ICQClient *m_client; +}; + +#endif + diff --git a/plugins/icq/aboutinfobase.ui b/plugins/icq/aboutinfobase.ui new file mode 100644 index 0000000..499eadd --- /dev/null +++ b/plugins/icq/aboutinfobase.ui @@ -0,0 +1,57 @@ + + + aboutInfo + + + + 0 + 0 + 374 + 288 + + + + Form4 + + + + 6 + + + 11 + + + + + + A&bout + + + + 6 + + + 11 + + + + + Additional information about user: + + + false + + + + + + + + + + + + + + + diff --git a/plugins/icq/advsearch.cpp b/plugins/icq/advsearch.cpp new file mode 100644 index 0000000..dd9d0ee --- /dev/null +++ b/plugins/icq/advsearch.cpp @@ -0,0 +1,64 @@ +/*************************************************************************** + advsearch.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "country.h" +#include "misc.h" + +#include "advsearch.h" +#include + +using namespace SIM; + +extern const ext_info *p_genders; +extern const ext_info *p_languages; +extern const ext_info *p_occupations; +extern const ext_info *p_interests; +extern const ext_info *p_pasts; +extern const ext_info *p_affilations; + +const ext_info ages[] = + { + { "18-22", 1 }, + { "23-29", 2 }, + { "30-39", 3 }, + { "40-49", 4 }, + { "50-59", 5 }, + { "> 60", 6 }, + { "", 0 } + }; + +const ext_info *p_ages = ages; + +AdvSearch::AdvSearch() : QWidget(NULL) +{ + setupUi(this); + initCombo(cmbGender, 0, p_genders); + initCombo(cmbAge, 0, ages); + initCombo(cmbCountry, 0, getCountries(), true, getCountryCodes()); + initCombo(cmbLang, 0, p_languages); + initCombo(cmbOccupation, 0, p_occupations); + initCombo(cmbInterests, 0, p_interests); + initCombo(cmbPast, 0, p_pasts); + initCombo(cmbAffilation, 0, p_affilations); +} + +void AdvSearch::showEvent(QShowEvent *e) +{ + QWidget::showEvent(e); + emit enableOptions(false); +} + diff --git a/plugins/icq/advsearch.h b/plugins/icq/advsearch.h new file mode 100644 index 0000000..1cdbaff --- /dev/null +++ b/plugins/icq/advsearch.h @@ -0,0 +1,36 @@ +/*************************************************************************** + advsearch.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _ADVSEARCH_H +#define _ADVSEARCH_H + +#include "ui_advsearchbase.h" +#include + +class AdvSearch : public QWidget, public Ui::AdvSearch +{ + Q_OBJECT +public: + AdvSearch(); +signals: + void enableOptions(bool); +protected: + void showEvent(QShowEvent*); +}; + +#endif + diff --git a/plugins/icq/advsearchbase.ui b/plugins/icq/advsearchbase.ui new file mode 100644 index 0000000..71d1c86 --- /dev/null +++ b/plugins/icq/advsearchbase.ui @@ -0,0 +1,328 @@ + + + AdvSearch + + + + 0 + 0 + 613 + 418 + + + + Form1 + + + + 6 + + + 0 + + + + + 6 + + + 0 + + + + + Info + + + + + + Gender: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Age: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Country: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + State: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + City: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Language: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + + + + Work + + + + + + Occupation: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Company: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Department: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Position: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + + 6 + + + 0 + + + + + Interests + + + + + + + + + + + + + + + Past + + + + + + + + + + + + + + + + + + + Affiliations + + + + + + + + + + + + + + + Keywords + + + + + + + + + + + + Search &online users only + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + + chkOnline + + + + diff --git a/plugins/icq/aimconfig.cpp b/plugins/icq/aimconfig.cpp new file mode 100644 index 0000000..1427e7b --- /dev/null +++ b/plugins/icq/aimconfig.cpp @@ -0,0 +1,95 @@ +/*************************************************************************** + aimconfig.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "aimconfig.h" +#include "icq.h" +#include "simgui/linklabel.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace SIM; + +AIMConfig::AIMConfig(QWidget *parent, ICQClient *client, bool bConfig) : QDialog(parent) +{ + setupUi(this); + m_client = client; + m_bConfig = bConfig; + if (m_bConfig){ + QTimer::singleShot(0, this, SLOT(changed())); + edtScreen->setText(m_client->data.owner.Screen.str()); + edtPasswd->setText(m_client->getPassword()); + connect(edtScreen, SIGNAL(textChanged(const QString&)), this, SLOT(changed(const QString&))); + connect(edtPasswd, SIGNAL(textChanged(const QString&)), this, SLOT(changed(const QString&))); + lnkReg->setText(i18n("Register new ScreenName")); + lnkReg->setUrl("http://my.screenname.aol.com/_cqr/login/login.psp?siteId=aimregistrationPROD&authLev=1&mcState=initialized&createSn=1&triedAimAuth=y"); + }else{ + tabConfig->removeTab(tabConfig->indexOf(tabAIM)); + } + edtServer->setText(m_client->getServer()); + edtPort->setValue(m_client->getPort()); + connect(edtServer, SIGNAL(textChanged(const QString&)), this, SLOT(changed(const QString&))); + connect(edtPort, SIGNAL(valueChanged(const QString&)), this, SLOT(changed(const QString&))); + chkHTTP->setChecked(client->getUseHTTP()); + connect(chkAuto, SIGNAL(toggled(bool)), this, SLOT(autoToggled(bool))); + chkAuto->setChecked(client->getAutoHTTP()); + chkKeepAlive->setChecked(client->getKeepAlive()); +} + +void AIMConfig::autoToggled(bool bState) +{ + chkHTTP->setEnabled(!bState); +} + +void AIMConfig::apply(Client*, void*) +{ +} + +void AIMConfig::apply() +{ + if (m_bConfig){ + m_client->setScreen(edtScreen->text().toLower()); + m_client->setPassword(edtPasswd->text()); + } + m_client->setServer(edtServer->text()); + m_client->setPort(edtPort->text().toUShort()); + m_client->setUseHTTP(chkHTTP->isChecked()); + m_client->setAutoHTTP(chkAuto->isChecked()); + m_client->setKeepAlive(chkKeepAlive->isChecked()); +} + +void AIMConfig::changed(const QString&) +{ + changed(); +} + +void AIMConfig::changed() +{ + bool bOK = true; + bOK = !edtScreen->text().isEmpty() && + !edtPasswd->text().isEmpty() && + !edtServer->text().isEmpty() && + edtPort->text().toUShort(); + emit okEnabled(bOK); +} + diff --git a/plugins/icq/aimconfig.h b/plugins/icq/aimconfig.h new file mode 100644 index 0000000..bd0d129 --- /dev/null +++ b/plugins/icq/aimconfig.h @@ -0,0 +1,44 @@ +/*************************************************************************** + aimconfig.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _AIMCONFIG_H +#define _AIMCONFIG_H + +#include "ui_aimconfigbase.h" +#include "icqclient.h" + +class AIMConfig : public QDialog, public Ui::AIMConfigBase +{ + Q_OBJECT +public: + AIMConfig(QWidget *parent, ICQClient *client, bool bConfig); +signals: + void okEnabled(bool); +public slots: + void apply(); + void apply(SIM::Client*, void*); +protected slots: + void changed(); + void changed(const QString&); + void autoToggled(bool); +protected: + bool m_bConfig; + ICQClient *m_client; +}; + +#endif + diff --git a/plugins/icq/aimconfigbase.ui b/plugins/icq/aimconfigbase.ui new file mode 100644 index 0000000..4d38300 --- /dev/null +++ b/plugins/icq/aimconfigbase.ui @@ -0,0 +1,251 @@ + + + + + AIMConfigBase + + + + 0 + 0 + 318 + 258 + + + + Form1 + + + + 11 + + + 6 + + + + + + &AIM + + + + 11 + + + 6 + + + + + ScreenName: + + + Qt::AlignVCenter|Qt::AlignRight + + + false + + + + + + + + + + Password: + + + Qt::AlignVCenter|Qt::AlignRight + + + false + + + + + + + QLineEdit::Password + + + + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Vertical + + + + + + + + &Network + + + + 11 + + + 6 + + + + + + + + Port: + + + Qt::AlignVCenter|Qt::AlignRight + + + false + + + + + + + 65535 + + + 1 + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Horizontal + + + + + + + Server: + + + Qt::AlignVCenter|Qt::AlignRight + + + false + + + + + + + Use &HTTP polling + + + + + + + &Automatically use HTTP polling if proxy required + + + + + + + Note: For HTTP-polling using proxy settings for HTTP + + + Qt::AlignVCenter|Qt::AlignLeft + + + true + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Vertical + + + + + + + &Keep-alive connection + + + + + + + + + + + + LinkLabel + QWidget +
simgui/linklabel.h
+ + -1 + -1 + + 0 + + 1 + 1 + + image0 + + text + +
+
+ + tabConfig + edtScreen + edtPasswd + edtServer + edtPort + chkHTTP + chkAuto + + + + 789c6dd2c10ac2300c00d07bbf2234b7229d1ddec44f503c0ae2a154410f53d0ed20e2bf6bdb656dd6861dd23d9a66591b0587fd1654235ebded6f0edcd53e419d87ae7b1f4f9b8f906d0bfe012317426a70b07bdc2f3ec77f8ed6b89559061a0343d06a124cc105596482585094bc0ae599b04646c9018926491b2205e140c485cace25755c175d0a967b622ff900b8cc9c7d29af594ea722d589167f813aa852ba07d94b9dce296e883fe7bb163f23896753 + + +
diff --git a/plugins/icq/aiminfo.cpp b/plugins/icq/aiminfo.cpp new file mode 100644 index 0000000..92d5449 --- /dev/null +++ b/plugins/icq/aiminfo.cpp @@ -0,0 +1,227 @@ +/*************************************************************************** + aiminfo.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "icons.h" +#include "aiminfo.h" +#include "icqclient.h" +#include "contacts/contact.h" + +#include +#include +#include +#include +#include + +using namespace SIM; + +AIMInfo::AIMInfo(QWidget *parent, ICQUserData *data, unsigned contact, ICQClient *client) : QWidget(parent) +{ + setupUi(this); + m_client = client; + m_data = data; + m_contact = contact; + edtScreen->setReadOnly(true); + if (m_data){ + edtFirst->setReadOnly(true); + edtLast->setReadOnly(true); + edtMiddle->setReadOnly(true); + edtMaiden->setReadOnly(true); + edtNick->setReadOnly(true); + edtStreet->setReadOnly(true); + edtCity->setReadOnly(true); + edtState->setReadOnly(true); + edtZip->setReadOnly(true); + edtAutoReply->setReadOnly(true); + disableWidget(cmbCountry); + }else{ + edtAutoReply->hide(); + } + edtOnline->setReadOnly(true); + edtNA->setReadOnly(true); + edtExtIP->setReadOnly(true); + edtIntIP->setReadOnly(true); + edtClient->setReadOnly(true); + fill(); +} + +void AIMInfo::apply() +{ + ICQUserData *data = m_data; + if (data == NULL) + data = &m_client->data.owner; +} + +void AIMInfo::apply(Client *client, void *_data) +{ + if (client != m_client) + return; + ICQUserData *data = m_client->toICQUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + data->FirstName.str() = edtFirst->text(); + data->LastName.str() = edtLast->text(); + data->MiddleName.str() = edtMiddle->text(); + data->Maiden.str() = edtMaiden->text(); + data->Nick.str() = edtNick->text(); + data->Address.str() = edtStreet->text(); + data->City.str() = edtCity->text(); + data->State.str() = edtState->text(); + data->Zip.str() = edtZip->text(); + data->Country.asULong() = getComboValue(cmbCountry, getCountries()); +} + +bool AIMInfo::processEvent(Event *e) +{ + if (e->type() == eEventContact){ + EventContact *ec = static_cast(e); + if(ec->action() != EventContact::eChanged) + return false; + Contact *contact = ec->contact(); + if (contact->clientData.have(m_data)) + fill(); + } else + if ((e->type() == eEventMessageReceived) && m_data){ + EventMessage *em = static_cast(e); + Message *msg = em->msg(); + if (msg->type() == MessageStatus){ + if (m_client->dataName(m_data) == msg->client()) + fill(); + } + } else + if ((e->type() == eEventClientChanged) && (m_data == 0)){ + EventClientChanged *ecc = static_cast(e); + if (ecc->client() == m_client) + fill(); + } + return false; +} + +void AIMInfo::fill() +{ + ICQUserData *data = m_data; + if (data == NULL) data = &m_client->data.owner; + + edtScreen->setText(data->Screen.str()); + edtFirst->setText(data->FirstName.str()); + edtLast->setText(data->LastName.str()); + edtMiddle->setText(data->MiddleName.str()); + edtMaiden->setText(data->Maiden.str()); + edtNick->setText(data->Nick.str()); + edtStreet->setText(data->Address.str()); + edtCity->setText(data->City.str()); + edtState->setText(data->State.str()); + edtZip->setText(data->Zip.str()); + initCombo(cmbCountry, data->Country.toULong(), getCountries()); + + if (m_data == NULL){ + if (edtFirst->text().isEmpty()) { + QString firstName = getContacts()->owner()->getFirstName(); + firstName = getToken(firstName, '/'); + edtFirst->setText(firstName); + } + if (edtLast->text().isEmpty()) { + QString lastName = getContacts()->owner()->getLastName(); + lastName = getToken(lastName, '/'); + edtLast->setText(lastName); + } + } + + cmbStatus->clear(); + unsigned status = STATUS_ONLINE; + if (m_data){ + switch (m_data->Status.toULong()){ + case STATUS_ONLINE: + case STATUS_OFFLINE: + status = m_data->Status.toULong(); + break; + default: + status = STATUS_AWAY; + } + }else{ + status = m_client->getStatus(); + } + if (m_data && !m_data->AutoReply.str().isEmpty()){ + edtAutoReply->setPlainText(m_data->AutoReply.str()); + }else{ + edtAutoReply->hide(); + } + + int current = 0; + QString text; + ProtocolPtr proto = ICQPlugin::icq_plugin->m_aim; + AIMProtocol* aim = static_cast(proto.data()); + for (const CommandDef *cmd = aim->statusList(); cmd->id; cmd++){ + if (cmd->flags & COMMAND_CHECK_STATE) + continue; + if (status == cmd->id){ + current = cmbStatus->count(); + text = cmd->text; + } + cmbStatus->addItem(Pict(cmd->icon), i18n(cmd->text)); + } + + cmbStatus->setCurrentIndex(current); + disableWidget(cmbStatus); + if (status == STATUS_OFFLINE){ + lblOnline->setText(i18n("Last online") + ':'); + edtOnline->setText(formatDateTime(QDateTime::fromTime_t(data->StatusTime.toULong()))); + lblNA->hide(); + edtNA->hide(); + }else{ + if (data->OnlineTime.toULong()){ + edtOnline->setText(formatDateTime(QDateTime::fromTime_t(data->OnlineTime.toULong()))); + }else{ + lblOnline->hide(); + edtOnline->hide(); + } + if ((status == STATUS_ONLINE) || text.isEmpty()){ + lblNA->hide(); + edtNA->hide(); + }else{ + lblNA->setText(i18n(text)); + edtNA->setText(formatDateTime(QDateTime::fromTime_t(data->StatusTime.toULong()))); + } + } + if (data->IP.ip()){ + edtExtIP->setText(formatAddr(data->IP, data->Port.toULong())); + }else{ + lblExtIP->hide(); + edtExtIP->hide(); + } + if (data->RealIP.ip() && ((data->IP.ip() == NULL) || (get_ip(data->IP) != get_ip(data->RealIP)))){ + edtIntIP->setText(formatAddr(data->RealIP, data->Port.toULong())); + }else{ + lblIntIP->hide(); + edtIntIP->hide(); + } + if (m_data){ + QString client_name = m_client->clientName(data); + if (client_name.length()){ + edtClient->setText(client_name); + }else{ + lblClient->hide(); + edtClient->hide(); + } + }else{ + QString name = PACKAGE; + name += ' '; + name += VERSION; +#ifdef WIN32 + name += "/win32"; +#endif + edtClient->setText(name); + } +} + diff --git a/plugins/icq/aiminfo.h b/plugins/icq/aiminfo.h new file mode 100644 index 0000000..0969a2e --- /dev/null +++ b/plugins/icq/aiminfo.h @@ -0,0 +1,44 @@ +/*************************************************************************** + aiminfo.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _AIMINFO_H +#define _AIMINFO_H + +#include "ui_aiminfobase.h" +#include "event.h" + +class ICQClient; +struct ICQUserData; + +class AIMInfo : public QWidget, public Ui::AIMInfo, public SIM::EventReceiver +{ + Q_OBJECT +public: + AIMInfo(QWidget *parent, ICQUserData*, unsigned contact, ICQClient *client); +public slots: + void apply(); + void apply(SIM::Client*, void*); +protected: + virtual bool processEvent(SIM::Event *e); + void fill(); + ICQUserData *m_data; + unsigned m_contact; + ICQClient *m_client; +}; + +#endif + diff --git a/plugins/icq/aiminfobase.ui b/plugins/icq/aiminfobase.ui new file mode 100644 index 0000000..4bd9791 --- /dev/null +++ b/plugins/icq/aiminfobase.ui @@ -0,0 +1,430 @@ + + + AIMInfo + + + + 0 + 0 + 477 + 344 + + + + Form1 + + + + 6 + + + 11 + + + + + + &Profile + + + + 11 + + + 6 + + + + + First Name: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + Last Name: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + + + + Middle: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Maiden: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Nick: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Street: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + City: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + State: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + Zip: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Country: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + 6 + + + 0 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + + ScreenName: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + &Status + + + + 11 + + + 6 + + + + + + + + + + + Online: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + + + + External IP: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + + + + + Client: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + Status: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + Internal IP: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + + + + + + + TabWidget3 + edtScreen + edtFirst + edtLast + edtMiddle + edtMaiden + edtNick + edtStreet + edtCity + edtState + edtZip + cmbCountry + edtClient + edtIntIP + edtOnline + edtExtIP + edtNA + cmbStatus + + + + diff --git a/plugins/icq/aimsearch.cpp b/plugins/icq/aimsearch.cpp new file mode 100644 index 0000000..f89e446 --- /dev/null +++ b/plugins/icq/aimsearch.cpp @@ -0,0 +1,36 @@ +/*************************************************************************** + aimsearch.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "misc.h" + +#include "aimsearch.h" +#include + +using namespace SIM; + +AIMSearch::AIMSearch() : QWidget(NULL) +{ + setupUi(this); + initCombo(cmbCountry, 0, getCountries(), true, getCountryCodes()); +} + +void AIMSearch::showEvent(QShowEvent *e) +{ + QWidget::showEvent(e); + emit enableOptions(false); +} + diff --git a/plugins/icq/aimsearch.h b/plugins/icq/aimsearch.h new file mode 100644 index 0000000..50d8a10 --- /dev/null +++ b/plugins/icq/aimsearch.h @@ -0,0 +1,36 @@ +/*************************************************************************** + aimsearch.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _AIMSEARCH_H +#define _AIMSEARCH_H + +#include "ui_aimsearchbase.h" +#include + +class AIMSearch : public QWidget, public Ui::AIMSearch +{ + Q_OBJECT +public: + AIMSearch(); +signals: + void enableOptions(bool); +protected: + void showEvent(QShowEvent*); +}; + +#endif + diff --git a/plugins/icq/aimsearchbase.ui b/plugins/icq/aimsearchbase.ui new file mode 100644 index 0000000..63f6af9 --- /dev/null +++ b/plugins/icq/aimsearchbase.ui @@ -0,0 +1,221 @@ + + + AIMSearch + + + + 0 + 0 + 477 + 383 + + + + Form1 + + + + 6 + + + 0 + + + + + Names + + + + + + First: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Last: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Middle: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Maiden: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Nick: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + + + + Location + + + + + + Country: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + State: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + City: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Zip: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Street: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + diff --git a/plugins/icq/aimservices.cpp b/plugins/icq/aimservices.cpp new file mode 100644 index 0000000..335ade7 --- /dev/null +++ b/plugins/icq/aimservices.cpp @@ -0,0 +1,430 @@ +/*************************************************************************** + services.cpp - description + ------------------- + begin : Sun Mar 10 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "log.h" + +#include "icqclient.h" + +#include + +using namespace std; +using namespace SIM; + +ServiceSocket::ServiceSocket(ICQClient *client, unsigned short id) + : m_client( client ) + , m_id ( id) + , m_socket( NULL) + , m_bConnected( false) + +{ + m_client->m_snacService->addService(this); +} + +ServiceSocket::~ServiceSocket() +{ + m_client->m_snacService->deleteService(this); + delete m_socket; +} + +void ServiceSocket::connect(const char *addr, unsigned short port, const QByteArray &cookie) +{ + log(L_DEBUG, "%s: connect to %s:%d ", serviceSocketName(), addr, port); + m_cookie = cookie; + if (m_socket != NULL) + { + m_socket->close(); + delete m_socket; + } + m_socket = new ICQClientSocket(this); + m_socket->connect(addr, port, m_client); +} + +void ServiceSocket::close() +{ + log(L_DEBUG, "%s: close()", serviceSocketName()); + m_socket->close(); +} + +bool ServiceSocket::error_state(const QString &err, unsigned) +{ + log(L_DEBUG, "%s: Service error %s", serviceSocketName(), qPrintable(err)); + return true; +} + +void ServiceSocket::connect_ready() +{ + log(L_DEBUG, "%s: connect_ready()", serviceSocketName()); + OscarSocket::connect_ready(); +} + +void ServiceSocket::packet_ready() +{ + log(L_DEBUG, "%s: packet_ready()", serviceSocketName()); + OscarSocket::packet_ready(); +} + +void ServiceSocket::packet(unsigned long size) //Fixme: Unsed Parameter size +{ + EventLog::log_packet(m_socket->readBuffer(), false,ICQPlugin::icq_plugin->OscarPacket); + switch (m_nChannel) + { + case ICQ_CHNxNEW: + flap(ICQ_CHNxNEW); + m_socket->writeBuffer() << 0x00000001L; + m_socket->writeBuffer().tlv(6, m_cookie.data(), (unsigned short)(m_cookie.size())); + m_cookie.resize(0); + sendPacket(); + break; + case ICQ_CHNxDATA: + unsigned short food, type; + unsigned short flags, seq, cmd; + m_socket->readBuffer() >> food >> type >> flags >> seq >> cmd; + if (flags & 0x8000) + { // some unknown data before real snac data + // just read the length and forget it ;-) + unsigned short unknown_length = 0; + m_socket->readBuffer() >> unknown_length; + m_socket->readBuffer().incReadPos(unknown_length); + } + // now just take a look at the type because 0x0001 == error + // in all foodgroups + if (type == 0x0001) + { + unsigned short err_code; + m_socket->readBuffer() >> err_code; + log(L_DEBUG,"%s: Error! foodgroup: %04X reason", serviceSocketName(), food); + // now decrease for icqicmb & icqvarious + m_socket->readBuffer().decReadPos(sizeof(unsigned short)); + } + data(food, type, seq); + break; + default: + log(L_ERROR, "%s: Unknown channel %u", serviceSocketName(), m_nChannel & 0xFF); + } + m_socket->readBuffer().init(6); + m_socket->readBuffer().packetStart(); + m_bHeader = true; +} + +const unsigned short USER_DIRECTORY_SERVICE = 0x000F; + +const unsigned short USER_DIRECTORY_SEARCH = 0x0002; +const unsigned short USER_DIRECTORY_RESULT = 0x0003; + +const unsigned short SNACxSRV_CLIENTxREADY = 0x0002; +const unsigned short SNACxSRV_READYxSERVER = 0x0003; +const unsigned short SNACxSRV_REQxRATExINFO = 0x0006; +const unsigned short SNACxSRV_RATExINFO = 0x0007; +const unsigned short SNACxSRV_RATExACK = 0x0008; +const unsigned short SNACxSRV_I_AM_ICQ = 0x0017; +const unsigned short SNACxSRV_ACK_ICQ = 0x0018; + +typedef QMap REQUEST_MAP; +typedef QMap SEQ_MAP; + +class SearchSocket : public ServiceSocket +{ +public: + SearchSocket(ICQClient*); + unsigned short add(const QStringList &str); +protected: + virtual const char *serviceSocketName() { return "SearchSocket"; } + void data(unsigned short food, unsigned short type, unsigned short seq); + void snac_service(unsigned short type); + void snac_search(unsigned short type, unsigned short seq); + void process(); + void addTlv(unsigned short n, const QString&, bool); + REQUEST_MAP m_requests; + SEQ_MAP m_seq; + unsigned short m_id; +}; + +SearchSocket::SearchSocket(ICQClient *client) + : ServiceSocket(client, USER_DIRECTORY_SERVICE) +{ + m_id = 0; +} + +static bool bLatin1(const QString &s) +{ + for (int i = 0; i < (int)(s.length()); i++) + { + if (s[i].unicode() > 0x7F) + return false; + } + return true; +} + +void SearchSocket::addTlv(unsigned short n, const QString &s, bool bLatin) +{ + QByteArray str; + if (bLatin) + str = s.toLatin1(); + else + str = s.toUtf8(); + m_socket->writeBuffer().tlv(n, str.data()); +} + +void SearchSocket::process() +{ + if (!connected()) + return; + for (REQUEST_MAP::iterator it = m_requests.begin(); it != m_requests.end(); ++it){ + snac(USER_DIRECTORY_SERVICE, USER_DIRECTORY_SEARCH, true); + bool bLatin; + if (!it->count() == 0) + continue; + if (!it->count() == 1) + { + QStringList sl = (*it); + QString mail = sl[0]; + bLatin = bLatin1(mail); + m_socket->writeBuffer().tlv(0x1C, bLatin ? "us-ascii" : "utf8"); + m_socket->writeBuffer().tlv(0x0A, (unsigned short)1); + addTlv(0x05, mail, bLatin); + } + else + { + QStringList sl = (*it); + bLatin = bLatin1(sl[0]) && + bLatin1(sl[1]) && + bLatin1(sl[2]) && + bLatin1(sl[3]) && + bLatin1(sl[4]) && + bLatin1(sl[5]) && + bLatin1(sl[6]) && + bLatin1(sl[7]) && + bLatin1(sl[8]) && + bLatin1(sl[9]); + m_socket->writeBuffer().tlv(0x1C, bLatin ? "us-ascii" : "utf8"); + m_socket->writeBuffer().tlv(0x0A, (unsigned short)0); + if (!sl[0].isEmpty()) + addTlv(0x01, sl[0], bLatin); + if (!sl[1].isEmpty()) + addTlv(0x02, sl[1], bLatin); + if (!sl[2].isEmpty()) + addTlv(0x03, sl[2], bLatin); + if (!sl[3].isEmpty()) + addTlv(0x04, sl[3], bLatin); + if (!sl[4].isEmpty()) + addTlv(0x06, sl[4], bLatin); + if (!sl[5].isEmpty()) + addTlv(0x07, sl[5], bLatin); + if (!sl[6].isEmpty()) + addTlv(0x08, sl[6], bLatin); + if (!sl[7].isEmpty()) + addTlv(0x0C, sl[7], bLatin); + if (!sl[8].isEmpty()) + addTlv(0x0D, sl[8], bLatin); + if (!sl[9].isEmpty()) + addTlv(0x21, sl[9], bLatin); + } + sendPacket(); + m_seq.insert(m_nMsgSequence, it.key()); + } + m_requests.clear(); +} + +unsigned short SearchSocket::add(const QStringList &name) +{ + m_requests.insert(++m_id, name); + process(); + return m_id; +} + +void SearchSocket::data(unsigned short food, unsigned short type, unsigned short seq) +{ + switch (food) + { + case ICQ_SNACxFOOD_SERVICE: + snac_service(type); + break; + case USER_DIRECTORY_SERVICE: + snac_search(type, seq); + break; + default: + log(L_WARN, "Unknown foodgroup %04X", food); + } +} + +void SearchSocket::snac_service(unsigned short type) +{ + switch (type){ + case SNACxSRV_READYxSERVER: + snac(ICQ_SNACxFOOD_SERVICE, SNACxSRV_I_AM_ICQ); + m_socket->writeBuffer() << 0x00010004L << 0x000F0001L; + sendPacket(); + break; + case SNACxSRV_ACK_ICQ: + snac(ICQ_SNACxFOOD_SERVICE, SNACxSRV_REQxRATExINFO); + sendPacket(); + break; + case SNACxSRV_RATExINFO: + snac(ICQ_SNACxFOOD_SERVICE, SNACxSRV_RATExACK); + m_socket->writeBuffer() << 0x00010002L << 0x00030004L << 0x0005; + sendPacket(); + snac(ICQ_SNACxFOOD_SERVICE, SNACxSRV_CLIENTxREADY); + m_socket->writeBuffer() << 0x00010003L << 0x00100739L << 0x000F0001L << 0x00100739L; + sendPacket(); + m_bConnected = true; + process(); + break; + default: + log(L_DEBUG, "Unknown service type %u", type); + } +} + +void SearchSocket::snac_search(unsigned short type, unsigned short seq) +{ + SEQ_MAP::iterator it; + switch (type){ + case USER_DIRECTORY_RESULT: + it = m_seq.find(seq); + if (it == m_seq.end()) + log(L_WARN, "Bad sequence in search answer"); + else + { + unsigned short r; + unsigned long nSearch; + m_socket->readBuffer() >> r >> nSearch; + + SearchResult res; + res.id = (*it); + res.client = m_client; + for (unsigned n = 0; n < nSearch; n++) + { + unsigned short nTlvs; + m_socket->readBuffer() >> nTlvs; + TlvList tlvs(m_socket->readBuffer(), nTlvs); + Tlv *tlv = tlvs(0x09); + if (tlv) + { + load_data(ICQProtocol::icqUserData, &res.data, NULL); + res.data.Screen.str() = tlv->Data(); // utf8 ? + tlv = tlvs(0x01); + if (tlv) + { + QString str = ICQClient::convert(tlv, tlvs, 0x1C); + res.data.FirstName.str() = str; + } + tlv = tlvs(0x02); + if (tlv) + { + QString str = ICQClient::convert(tlv, tlvs, 0x1C); + res.data.LastName.str() = str; + } + tlv = tlvs(0x03); + if (tlv) + { + QString str = ICQClient::convert(tlv, tlvs, 0x1C); + res.data.MiddleName.str() = str; + } + tlv = tlvs(0x07); + if (tlv){ + QString str = ICQClient::convert(tlv, tlvs, 0x1C); + res.data.Address.str() = str; + } + tlv = tlvs(0x08); + if (tlv) + { + QString str = ICQClient::convert(tlv, tlvs, 0x1C); + res.data.City.str() = str; + } + tlv = tlvs(0x0C); + if (tlv) + { + QString str = ICQClient::convert(tlv, tlvs, 0x1C); + res.data.Nick.str() = str; + } + tlv = tlvs(0x07); + if (tlv) + { + QString str = ICQClient::convert(tlv, tlvs, 0x1C); + res.data.State.str() = str; + } + tlv = tlvs(0x06); + if (tlv) + { + QString country_text; + country_text = QString::fromLatin1(tlv->Data()); + country_text = country_text.toLower(); + for (const ext_info *info = getCountryCodes(); info->szName; ++info) + { + if (country_text != info->szName) + continue; + + res.data.Country.asULong() = info->nCode; + break; + } + } + EventSearch(&res).process(); + free_data(ICQProtocol::icqUserData, &res.data); + } + } + if (r != 6) + { + load_data(ICQProtocol::icqUserData, &res.data, NULL); + EventSearchDone(&res).process(); + free_data(ICQProtocol::icqUserData, &res.data); + m_seq.erase(it); + } + } + break; + default: + log(L_WARN, "Unknown search foodgroup type %04X", type); + } +} + +unsigned short ICQClient::aimEMailSearch(const QString &name) +{ + SearchSocket *s = static_cast(m_snacService->getService(USER_DIRECTORY_SERVICE)); + if (s == NULL) + { + s = new SearchSocket(this); + snacService()->requestService(s); + } + QStringList sl; + sl.append(name); + return s->add(sl); +} + +unsigned short ICQClient::aimInfoSearch(const QString &first, const QString &last, const QString &middle, + const QString &maiden, const QString &country, const QString &street, + const QString &city, const QString &nick, const QString &zip, + const QString &state) +{ + SearchSocket *s = static_cast(m_snacService->getService(USER_DIRECTORY_SERVICE)); + if(s == NULL) + { + s = new SearchSocket(this); + snacService()->requestService(s); + } + QStringList info; + + info.append(first); + info.append(last); + info.append(middle); + info.append(maiden); + info.append(country); + info.append(street); + info.append(city); + info.append(nick); + info.append(zip); + info.append(state); + return s->add(info); +} + diff --git a/plugins/icq/configure.in.in b/plugins/icq/configure.in.in new file mode 100644 index 0000000..fdbdd84 --- /dev/null +++ b/plugins/icq/configure.in.in @@ -0,0 +1,5 @@ +if test "$have_ssl" != yes; then + AC_MSG_WARN([OpenSSL library disabled. ICQ plugin is disabled]) +fi +AM_CONDITIONAL(ENABLE_ICQ, test "$have_ssl" = "yes") + diff --git a/plugins/icq/encodingdlg.cpp b/plugins/icq/encodingdlg.cpp new file mode 100644 index 0000000..8e431bd --- /dev/null +++ b/plugins/icq/encodingdlg.cpp @@ -0,0 +1,92 @@ +/*************************************************************************** + encodingdlg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "icons.h" +#include "encodingdlg.h" +#include "icqclient.h" +#include "contacts/contact.h" + +#include +#include +#include + +using namespace SIM; + +class ICQClient; + +EncodingDlg::EncodingDlg(QWidget *parent, ICQClient *client) + : QDialog(parent) +{ + setupUi(this); + setModal(true); + SET_WNDPROC("encoding") + setWindowIcon(Icon("encoding")); + setButtonsPict(this); + setWindowTitle(windowTitle()); + m_client = client; + connect(buttonOk, SIGNAL(clicked()), this, SLOT(apply())); + connect(cmbEncoding, SIGNAL(activated(int)), this, SLOT(changed(int))); + cmbEncoding->addItem(QString()); + const ENCODING *e = getContacts()->getEncodings(); + for (e++; e->language; e++){ + if (!e->bMain) + continue; + cmbEncoding->addItem(i18n(e->language) + " (" + e->codec + ')'); + } + for (e = getContacts()->getEncodings(); e->language; e++){ + if (e->bMain) + continue; + cmbEncoding->addItem(i18n(e->language) + " (" + e->codec + ')'); + } + buttonOk->setEnabled(false); +} + +void EncodingDlg::apply() +{ + // Subtract 1 to account for the first menu item which is empty + int n = cmbEncoding->currentIndex(); + + if (n == 0) + return; // User selected the empty menu item + + const ENCODING *e; + for (e = getContacts()->getEncodings() + 1; e->language; e++){ + if (!e->bMain) + continue; + --n; + if (n == 0){ + getContacts()->owner()->setEncoding(e->codec); + return; + } + } + + for (e = getContacts()->getEncodings(); e->language; e++){ + if (!e->bMain) + continue; + --n; + if (n == 0){ + getContacts()->owner()->setEncoding(e->codec); + return; + } + } +} + +void EncodingDlg::changed(int n) +{ + buttonOk->setEnabled(n > 0); +} + diff --git a/plugins/icq/encodingdlg.h b/plugins/icq/encodingdlg.h new file mode 100644 index 0000000..44a9f50 --- /dev/null +++ b/plugins/icq/encodingdlg.h @@ -0,0 +1,38 @@ +/*************************************************************************** + encodingdlg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _ENCODINGDLG_H +#define _ENCODINGDLG_H + +#include "ui_encodingdlgbase.h" + +class ICQClient; + +class EncodingDlg : public QDialog, public Ui::EncodingDlgBase +{ + Q_OBJECT +public: + EncodingDlg(QWidget *parent, ICQClient *m_client); +public slots: + void apply(); + void changed(int); +protected: + ICQClient *m_client; +}; + +#endif + diff --git a/plugins/icq/encodingdlgbase.ui b/plugins/icq/encodingdlgbase.ui new file mode 100644 index 0000000..7693da3 --- /dev/null +++ b/plugins/icq/encodingdlgbase.ui @@ -0,0 +1,126 @@ + + + + + EncodingDlgBase + + + + 0 + 0 + 311 + 180 + + + + Choose default encoding + + + true + + + + 11 + + + 6 + + + + + + 1 + 7 + + + + Your current system encoding (UTF-8) may cause problems saving your personal information and reading offline messages from other users. + + + Qt::AlignCenter + + + true + + + + + + + You will choose the coding by default which want to use: + + + false + + + + + + + + + + 0 + + + 6 + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Horizontal + + + + + + + &OK + + + true + + + true + + + + + + + &Cancel + + + true + + + + + + + + qPixmapFromMimeSource + + + buttonOk + clicked() + EncodingDlg + accept() + + + buttonCancel + clicked() + EncodingDlg + reject() + + + diff --git a/plugins/icq/homeinfo.cpp b/plugins/icq/homeinfo.cpp new file mode 100644 index 0000000..80f5b39 --- /dev/null +++ b/plugins/icq/homeinfo.cpp @@ -0,0 +1,134 @@ +/*************************************************************************** + homeinfo.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "homeinfo.h" +#include "icqclient.h" +#include "log.h" +#include "contacts/contact.h" + +#include +#include +#include + +using namespace SIM; + +HomeInfo::HomeInfo(QWidget *parent, ICQUserData *data, unsigned contact, ICQClient *client) : QWidget(parent) +{ + setupUi(this); + m_data = data; + m_client = client; + m_contact = contact; + if (m_data){ + edtAddress->setReadOnly(true); + edtCity->setReadOnly(true); + edtState->setReadOnly(true); + edtZip->setReadOnly(true); + disableWidget(cmbCountry); + disableWidget(cmbZone); + } + fill(); + btnWebLocation->setText(i18n("map")); + connect(btnWebLocation, SIGNAL(clicked()), this, SLOT(goUrl())); +} + +void HomeInfo::apply() +{ +} + +void HomeInfo::apply(Client *client, void *_data) +{ + if (client != m_client) + return; + ICQUserData *data = m_client->toICQUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + data->Address.str() = edtAddress->toPlainText(); + data->City.str() = edtCity->text(); + data->State.str() = edtState->text(); + data->Zip.str() = edtZip->text(); + data->Country.asULong() = getComboValue(cmbCountry, getCountries()); +} + +bool HomeInfo::processEvent(Event *e) +{ + if (e->type() == eEventContact){ + EventContact *ec = static_cast(e); + if(ec->action() != EventContact::eChanged) + return false; + Contact *contact = ec->contact(); + if (contact->clientData.have(m_data)) + fill(); + } else + if ((e->type() == eEventClientChanged) && (m_data == 0)){ + EventClientChanged *ecc = static_cast(e); + if (ecc->client() == m_client) + fill(); + } + return false; +} + +static QString formatTime(char n) +{ + QString res; + res.sprintf("%+i:%02u", -n/2, (n & 1) * 30); + return res; +} + +static void initTZCombo(QComboBox *cmb, char tz) +{ + if (tz < -24) + tz = 0; + if (tz > 24) + tz = 0; + if (cmb->isEnabled()){ + unsigned nSel = 12; + unsigned n = 0; + for (char i = 24; i >= -24; i--, n++){ + cmb->addItem(formatTime(i)); + if (i == tz) nSel = n; + } + cmb->setCurrentIndex(nSel); + }else{ + cmb->addItem(formatTime(tz)); + } +} + +void HomeInfo::fill() +{ + ICQUserData *data = m_data; + if (data == NULL) + data = &m_client->data.owner; + edtAddress->setPlainText(data->Address.str()); + edtCity->setText(data->City.str()); + edtState->setText(data->State.str()); + edtZip->setText(data->Zip.str()); + initCombo(cmbCountry, data->Country.toULong(), getCountries()); + initTZCombo(cmbZone, data->TimeZone.toULong()); +} + +void HomeInfo::goUrl() +{ + ICQUserData *data = m_data; + if (data == NULL) + data = &m_client->data.owner; + QString url = QString("http://www.mapquest.com/maps/map.adp?city=%1&state=%2&country=%3&zip=%4") + .arg(edtCity->text()) + .arg(edtState->text()) + .arg(cmbCountry->currentText()) + .arg(edtZip->text()); + EventGoURL e(url); + e.process(); +} + diff --git a/plugins/icq/homeinfo.h b/plugins/icq/homeinfo.h new file mode 100644 index 0000000..a8b9c43 --- /dev/null +++ b/plugins/icq/homeinfo.h @@ -0,0 +1,47 @@ +/*************************************************************************** + homeinfo.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _HOMEINFO_H +#define _HOMEINFO_H + +#include "contacts.h" +#include "event.h" + +#include "ui_homeinfobase.h" + +class ICQClient; +struct ICQUserData; + +class HomeInfo : public QWidget, public Ui::HomeInfo, public SIM::EventReceiver +{ + Q_OBJECT +public: + HomeInfo(QWidget *parent, ICQUserData*, unsigned contact, ICQClient *client); +public slots: + void apply(); + void apply(SIM::Client*, void*); + void goUrl(); +protected: + virtual bool processEvent(SIM::Event *e); + void fill(); + ICQUserData *m_data; + unsigned m_contact; + ICQClient *m_client; +}; + +#endif + diff --git a/plugins/icq/homeinfobase.ui b/plugins/icq/homeinfobase.ui new file mode 100644 index 0000000..e2819a6 --- /dev/null +++ b/plugins/icq/homeinfobase.ui @@ -0,0 +1,242 @@ + + + HomeInfo + + + + 0 + 0 + 407 + 315 + + + + Form1 + + + + 6 + + + 11 + + + + + + &Home info + + + + 6 + + + 11 + + + + + 0 + + + 6 + + + + + + + + State: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + Address: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + 6 + + + 0 + + + + + + + + Country: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + + 0 + 0 + + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + + City: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Zip code: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + + + + 0 + 5 + + + + QFrame::HLine + + + QFrame::Sunken + + + + + + + 6 + + + 0 + + + + + Time zone: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + + + + + + edtCity + edtState + edtZip + cmbCountry + cmbZone + TabWidget2 + + + + diff --git a/plugins/icq/icq.cpp b/plugins/icq/icq.cpp new file mode 100644 index 0000000..5863651 --- /dev/null +++ b/plugins/icq/icq.cpp @@ -0,0 +1,439 @@ +/*************************************************************************** + icq.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "icq.h" +#include "icqconfig.h" +#include "core.h" +#include "log.h" +#include "clientmanager.h" +#include "icons.h" + +#include "contacts/protocolmanager.h" + +using namespace SIM; + +Plugin *createICQPlugin(unsigned base, bool, Buffer*) +{ + Plugin *plugin = new ICQPlugin(base); + return plugin; +} + +static PluginInfo info = + { + NULL, + NULL, + VERSION, + createICQPlugin, + PLUGIN_PROTOCOL + }; + +EXPORT_PROC PluginInfo* GetPluginInfo() +{ + return &info; +} + +ICQProtocol::ICQProtocol(Plugin *plugin) + : Protocol(plugin) +{ + initStatuses(); +} + +ICQProtocol::~ICQProtocol() +{ +} + +ClientPtr ICQProtocol::createClient(Buffer *cfg) +{ + ClientPtr icq = ClientPtr(new ICQClient(this, cfg, false)); + getClientManager()->addClient(icq); + return icq; +} + +QStringList ICQProtocol::statuses() +{ + QStringList list; + foreach(const ICQStatusPtr& status, m_statuses) { + list.append(status->id()); + } + return list; +} + +void ICQProtocol::initStatuses() +{ + m_statuses.clear(); + addStatus(ICQStatusPtr(new ICQStatus("online", "Online", true, "", Icon("ICQ_online")))); + addStatus(ICQStatusPtr(new ICQStatus("away", "Away", true, "", Icon("ICQ_away")))); + addStatus(ICQStatusPtr(new ICQStatus("n/a", "N/A", true, "", Icon("ICQ_na")))); + addStatus(ICQStatusPtr(new ICQStatus("dnd", "Do not disturb", true, "", Icon("ICQ_dnd")))); + addStatus(ICQStatusPtr(new ICQStatus("occupied", "Occupied", true, "", Icon("ICQ_occupied")))); + addStatus(ICQStatusPtr(new ICQStatus("free_for_chat", "Free for chat", true, "", Icon("ICQ_ffc")))); + addStatus(ICQStatusPtr(new ICQStatus("offline", "Offline", true, "", Icon("ICQ_offline")))); +} + +void ICQProtocol::addStatus(ICQStatusPtr status) +{ + m_statuses.append(status); +} + +SIM::IMStatusPtr ICQProtocol::status(const QString& id) +{ + foreach(const ICQStatusPtr& status, m_statuses) { + if(status->id() == id) { + return status; + } + } + + return SIM::IMStatusPtr(); +} + +static CommandDef icq_descr = + CommandDef ( + 0, + I18N_NOOP("ICQ"), + "ICQ_online", + "ICQ_invisible", + "http://www.icq.com/password/", + 0, + 0, + 0, + 0, + 0, + PROTOCOL_INFO | PROTOCOL_SEARCH | PROTOCOL_INVISIBLE | PROTOCOL_AR_USER | PROTOCOL_ANY_PORT | PROTOCOL_NODATA, + NULL, + QString::null + ); + +const CommandDef *ICQProtocol::description() +{ + return &icq_descr; +} + +static CommandDef icq_status_list[] = + { + CommandDef ( + STATUS_ONLINE, + I18N_NOOP("Online"), + "ICQ_online", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + STATUS_AWAY, + I18N_NOOP("Away"), + "ICQ_away", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + STATUS_NA, + I18N_NOOP("N/A"), + "ICQ_na", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + STATUS_DND, + I18N_NOOP("Do not Disturb"), + "ICQ_dnd", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + STATUS_OCCUPIED, + I18N_NOOP("Occupied"), + "ICQ_occupied", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + STATUS_FFC, + I18N_NOOP("Free for chat"), + "ICQ_ffc", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + STATUS_OFFLINE, + I18N_NOOP("Offline"), + "ICQ_offline", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef () + }; + +const CommandDef *ICQProtocol::statusList() +{ + return icq_status_list; +} + +const CommandDef *ICQProtocol::_statusList() +{ + return icq_status_list; +} + +AIMProtocol::AIMProtocol(Plugin *plugin) + : Protocol(plugin) +{ +} + +AIMProtocol::~AIMProtocol() +{ +} + +QStringList AIMProtocol::statuses() +{ + // TODO + return QStringList(); +} + +SIM::IMStatusPtr AIMProtocol::status(const QString& /*id*/) +{ + // TODO + return SIM::IMStatusPtr(); +} + +ClientPtr AIMProtocol::createClient(Buffer *cfg) +{ + ClientPtr aim = ClientPtr(new ICQClient(this, cfg, true)); + getClientManager()->addClient(aim); + return aim; +} + +static CommandDef aim_descr = + CommandDef ( + 0, + I18N_NOOP("AIM"), + "AIM_online", + QString::null, + "http://www.aim.com/help_faq/forgot_password/password.adp", + 0, + 0, + 0, + 0, + 0, + PROTOCOL_INFO | PROTOCOL_AR | PROTOCOL_ANY_PORT, + NULL, + QString::null + ); + +const CommandDef *AIMProtocol::description() +{ + return &aim_descr; +} + +static CommandDef aim_status_list[] = + { + CommandDef ( + STATUS_ONLINE, + I18N_NOOP("Online"), + "AIM_online", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + STATUS_AWAY, + I18N_NOOP("Away"), + "AIM_away", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + STATUS_OFFLINE, + I18N_NOOP("Offline"), + "AIM_offline", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef () + }; + +const CommandDef *AIMProtocol::statusList() +{ + return aim_status_list; +} + +//Protocol *ICQPlugin::m_icq = NULL; +//Protocol *ICQPlugin::m_aim = NULL; + +ICQPlugin *ICQPlugin::icq_plugin = NULL; + +ICQPlugin::ICQPlugin(unsigned base) + : Plugin(base) +{ + icq_plugin = this; + + OscarPacket = registerType(); + getContacts()->addPacketType(OscarPacket, "Oscar"); + ICQDirectPacket = registerType(); + getContacts()->addPacketType(ICQDirectPacket, "ICQ.Direct"); + AIMDirectPacket = registerType(); + getContacts()->addPacketType(AIMDirectPacket, "AIM.Direct"); + + m_icq = ProtocolPtr(new ICQProtocol(this)); + getProtocolManager()->addProtocol(m_icq); + m_aim = ProtocolPtr(new AIMProtocol(this)); + getProtocolManager()->addProtocol(m_aim); + + EventMenu(MenuSearchResult, EventMenu::eAdd).process(); + EventMenu(MenuIcqGroups, EventMenu::eAdd).process(); + + Command cmd; + cmd->id = CmdVisibleList; + cmd->text = I18N_NOOP("Visible list"); + cmd->menu_id = MenuContactGroup; + cmd->menu_grp = 0x8010; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdInvisibleList; + cmd->text = I18N_NOOP("Invisible list"); + cmd->menu_grp = 0x8011; + EventCommandCreate(cmd).process(); + + cmd->id = CmdIcqSendMessage; + cmd->text = I18N_NOOP("&Message"); + cmd->icon = "message"; + cmd->menu_id = MenuSearchResult; + cmd->menu_grp = 0x1000; + cmd->bar_id = 0; + cmd->popup_id = 0; + cmd->flags = COMMAND_DEFAULT; + EventCommandCreate(cmd).process(); + + cmd->id = CmdInfo; + cmd->text = I18N_NOOP("User &info"); + cmd->icon = "info"; + cmd->menu_grp = 0x1001; + EventCommandCreate(cmd).process(); + + cmd->id = CmdGroups; + cmd->text = I18N_NOOP("&Add to group"); + cmd->icon = QString::null; + cmd->menu_grp = 0x1002; + cmd->popup_id = MenuIcqGroups; + EventCommandCreate(cmd).process(); + + cmd->id = CmdGroups; + cmd->text = "_"; + cmd->menu_id = MenuIcqGroups; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + registerMessages(); + + RetrySendDND = registerType(); + RetrySendOccupied = registerType(); +} + +ICQPlugin::~ICQPlugin() +{ + unregisterMessages(); + getProtocolManager()->removeProtocol(m_aim); + getProtocolManager()->removeProtocol(m_icq); + + getContacts()->removePacketType(OscarPacket); + getContacts()->removePacketType(ICQDirectPacket); + getContacts()->removePacketType(AIMDirectPacket); + + EventCommandRemove(CmdVisibleList).process(); + EventCommandRemove(CmdInvisibleList).process(); + + EventMenu(MenuSearchResult, EventMenu::eRemove).process(); + EventMenu(MenuIcqGroups, EventMenu::eRemove).process(); +} + diff --git a/plugins/icq/icq.h b/plugins/icq/icq.h new file mode 100644 index 0000000..899fcff --- /dev/null +++ b/plugins/icq/icq.h @@ -0,0 +1,95 @@ +/*************************************************************************** + icq.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _ICQ_H +#define _ICQ_H + +#include "contacts.h" +#include "contacts/client.h" +#include "contacts/imstatus.h" +#include "icqstatus.h" + +class CorePlugin; + +const unsigned IcqCmdBase = 0x00040000; + +#include "icq_events.h" + +const unsigned long CmdVisibleList = IcqCmdBase; +const unsigned long CmdInvisibleList = IcqCmdBase + 1; +const unsigned long CmdGroups = IcqCmdBase + 2; +const unsigned long CmdIcqSendMessage = IcqCmdBase + 5; +const unsigned long CmdShowWarning = IcqCmdBase + 6; +const unsigned long CmdPasswordFail = IcqCmdBase + 7; +const unsigned long CmdPasswordSuccess = IcqCmdBase + 8; + +const unsigned long MenuSearchResult = IcqCmdBase; +const unsigned long MenuIcqGroups = IcqCmdBase + 2; + +class ICQProtocol : public SIM::Protocol +{ +public: + ICQProtocol(SIM::Plugin *plugin); + ~ICQProtocol(); + SIM::ClientPtr createClient(Buffer *cfg); + const SIM::CommandDef *description(); + const SIM::CommandDef *statusList(); + static const SIM::CommandDef *_statusList(); + virtual const SIM::DataDef *userDataDef(); + static const SIM::DataDef *icqUserData; + virtual QStringList statuses(); + virtual SIM::IMStatusPtr status(const QString& id); + +private: + void initStatuses(); + void addStatus(ICQStatusPtr status); + QList m_statuses; +}; + +class AIMProtocol : public SIM::Protocol +{ +public: + AIMProtocol(SIM::Plugin *plugin); + ~AIMProtocol(); + SIM::ClientPtr createClient(Buffer *cfg); + const SIM::CommandDef *description(); + const SIM::CommandDef *statusList(); + virtual const SIM::DataDef *userDataDef(); + static const SIM::DataDef *icqUserData; + virtual QStringList statuses(); + virtual SIM::IMStatusPtr status(const QString& id); +}; + +class ICQPlugin : public SIM::Plugin +{ +public: + ICQPlugin(unsigned base); + virtual ~ICQPlugin(); + unsigned OscarPacket; + unsigned ICQDirectPacket; + unsigned AIMDirectPacket; + unsigned RetrySendDND; + unsigned RetrySendOccupied; + SIM::ProtocolPtr m_icq; + SIM::ProtocolPtr m_aim; + static ICQPlugin *icq_plugin; + void registerMessages(); + void unregisterMessages(); +}; + +#endif + diff --git a/plugins/icq/icq.rc b/plugins/icq/icq.rc new file mode 100644 index 0000000..3368573 --- /dev/null +++ b/plugins/icq/icq.rc @@ -0,0 +1,97 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,9,6,0 + PRODUCTVERSION 0,9,6,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Vladimir Shutoff\0" + VALUE "FileDescription", "ICQ plugin\0" + VALUE "FileVersion", "0, 9, 6, 0\0" + VALUE "InternalName", "icq\0" + VALUE "LegalCopyright", "Copyright © 2002-2003\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "icq.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "SIM\0" + VALUE "ProductVersion", "0, 9, 6, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/icq/icq.vcproj b/plugins/icq/icq.vcproj new file mode 100644 index 0000000..bc069c4 --- /dev/null +++ b/plugins/icq/icq.vcproj @@ -0,0 +1,2669 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/icq/icq_events.h b/plugins/icq/icq_events.h new file mode 100644 index 0000000..61ce144 --- /dev/null +++ b/plugins/icq/icq_events.h @@ -0,0 +1,33 @@ +#ifndef _ICQ_EVENTS_H +#define _ICQ_EVENTS_H + +#include "event.h" + +struct SearchResult; + +class EventSearchInternal : public SIM::Event +{ +public: + EventSearchInternal(SIM::SIMEvent e, SearchResult *res) + : Event(e), m_res(res) {} + + SearchResult *searchResult() const { return m_res; } +protected: + SearchResult *m_res; +}; + +class EventSearchDone : public EventSearchInternal +{ +public: + EventSearchDone(SearchResult *res) + : EventSearchInternal(SIM::eEventICQSearchDone, res) {} +}; + +class EventSearch : public EventSearchInternal +{ +public: + EventSearch(SearchResult *res) + : EventSearchInternal(SIM::eEventICQSearch, res) {} +}; + +#endif // _ICQ_EVENTS_H diff --git a/plugins/icq/icq_pch.h b/plugins/icq/icq_pch.h new file mode 100644 index 0000000..bf0acbb --- /dev/null +++ b/plugins/icq/icq_pch.h @@ -0,0 +1,61 @@ +#pragma once + +#include + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef NO_QT_MOC_HEADER +#include +//#include +//#include +#endif + +#include "aboutinfo.h" +#include "advsearch.h" +#include "aimconfig.h" +#include "aiminfo.h" +#include "aimsearch.h" +#include "encodingdlg.h" +#include "homeinfo.h" +#include "icq.h" +#include "icqclient.h" +#include "icqconfig.h" +#include "icqinfo.h" +#include "icqmessage.h" +#include "icqpicture.h" +#include "icqsearch.h" +#include "icqsecure.h" +#include "interestsinfo.h" +#include "moreinfo.h" +#include "pastinfo.h" +#include "polling.h" +#include "securedlg.h" +#include "verifydlg.h" +#include "warndlg.h" +#include "workinfo.h" +#include "xml.h" diff --git a/plugins/icq/icqbos.cpp b/plugins/icq/icqbos.cpp new file mode 100644 index 0000000..ba6cb25 --- /dev/null +++ b/plugins/icq/icqbos.cpp @@ -0,0 +1,46 @@ +/*************************************************************************** + icqbos.cpp - description + ------------------- + begin : Sun Mar 10 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "log.h" + +#include "icqclient.h" + +using namespace SIM; + +const unsigned short ICQ_SNACxBOS_REQUESTxRIGHTS = 0x0002; +const unsigned short ICQ_SNACxBOS_RIGHTSxGRANTED = 0x0003; +const unsigned short ICQ_SNACxBOS_ADDxVISIBLExLIST = 0x0005; +const unsigned short ICQ_SNACxBOS_REMxVISIBLExLIST = 0x0006; +const unsigned short ICQ_SNACxBOS_ADDxINVISIBLExLIST = 0x0007; +const unsigned short ICQ_SNACxBOS_REMxINVISIBLExLIST = 0x0008; + +void ICQClient::snac_bos(unsigned short type, unsigned short) +{ + switch (type){ + case ICQ_SNACxBOS_RIGHTSxGRANTED: + log(L_DEBUG, "BOS rights granted"); + break; + default: + log(L_WARN, "Unknown bos foodgroup type %04X", type); + } +} + +void ICQClient::bosRequest() +{ + snac(ICQ_SNACxFOOD_BOS, ICQ_SNACxBOS_REQUESTxRIGHTS); + sendPacket(true); +} diff --git a/plugins/icq/icqbuddy.cpp b/plugins/icq/icqbuddy.cpp new file mode 100644 index 0000000..5a4ddc7 --- /dev/null +++ b/plugins/icq/icqbuddy.cpp @@ -0,0 +1,640 @@ +/*************************************************************************** + icqbuddy.cpp - description + ------------------- + begin : Sun Mar 10 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "icqclient.h" + +#include +#include + +#ifdef WIN32 +#include +#else +#include +#include +#include +#endif + +#include +#include + +#include "log.h" +#include "icqbuddy.h" +#include "contacts/clientdataiterator.h" +#include "contacts/contact.h" + +using namespace SIM; + +const unsigned short ICQ_SNACxBDY_REQUESTxRIGHTS = 0x0002; +const unsigned short ICQ_SNACxBDY_RIGHTSxGRANTED = 0x0003; +const unsigned short ICQ_SNACxBDY_ADDxTOxLIST = 0x0004; +const unsigned short ICQ_SNACxBDY_REMOVExFROMxLIST = 0x0005; +const unsigned short ICQ_SNACxBDY_USERONLINE = 0x000B; +const unsigned short ICQ_SNACxBDY_USEROFFLINE = 0x000C; + +const unsigned short TLV_USER_CLASS = 0x0001; +const unsigned short TLV_USER_SIGNON_TIME = 0x0003; +const unsigned short TLV_USER_MEMBER_SINCE = 0x0005; // not interpreted +const unsigned short TLV_USER_STATUS = 0x0006; +const unsigned short TLV_USER_EXT_IP = 0x000A; +const unsigned short TLV_USER_DC_INFO = 0x000C; +const unsigned short TLV_USER_CAPS = 0x000D; +const unsigned short TLV_USER_ONLINE_TIME = 0x000F; // not interpreted +const unsigned short TLV_USER_TIMES_UPDATED = 0x0011; // ???? +const unsigned short TLV_USER_NEWCAPS = 0x0019; +const unsigned short TLV_USER_BUDDYINFO = 0x001D; + +static QString makeCapStr( const capability cap, unsigned size ) +{ + QString str, tmp; + for(unsigned int i = 0; i < size; i++ ) { + str += tmp.sprintf( "0x%02x ", cap[i] ); + } + return str; +} + + +SnacIcqBuddy::SnacIcqBuddy(ICQClient* client) : SnacHandler(client, 0x0003) +{ +} + +SnacIcqBuddy::~SnacIcqBuddy() +{ +} + +bool SnacIcqBuddy::process(unsigned short subtype, ICQBuffer* buf, unsigned short seq) +{ + switch (subtype) + { + case ICQ_SNACxBDY_RIGHTSxGRANTED: + log(L_DEBUG, "Buddy rights granted"); + break; + case ICQ_SNACxBDY_USEROFFLINE: + { + Contact *contact; + QString screen = buf->unpackScreen(); + ICQUserData *data = m_client->findContact(screen, NULL, false, contact); + if(!data) + break; + if(data->Status.toULong() != ICQ_STATUS_OFFLINE) + { + m_client->setOffline(data); + StatusMessage *m = new StatusMessage; + m->setContact(contact->id()); + m->setClient(m_client->dataName(data)); + m->setStatus(STATUS_OFFLINE); + m->setFlags(MESSAGE_RECEIVED); + EventMessageReceived e(m); + if(!e.process()) + delete m; + } + else + { + // hack for trillian + EventContact e(contact, EventContact::eOnline); + e.process(); + } + break; + } + case ICQ_SNACxBDY_USERONLINE: + { + Contact *contact; + QString screen = buf->unpackScreen(); + ICQUserData *data = m_client->findContact(screen, NULL, false, contact); + if(data) + { + bool bChanged = false; + bool bAwayChanged = false; + unsigned long prevStatus = data->Status.toULong(); + + unsigned short level, len; + (*buf) >> level >> len; + data->WarningLevel.asULong() = level; + + TlvList tlv((*buf)); + Tlv* tlvClass = tlv(TLV_USER_CLASS); + if(tlvClass) + { + unsigned short userClass = *tlvClass; + if(userClass != data->Class.toULong()) + { + if ((userClass & CLASS_AWAY) != (data->Class.toULong() & CLASS_AWAY)) + { + data->StatusTime.asULong() = (unsigned long)time(NULL); + bAwayChanged = true; + } + data->Class.asULong() = userClass; + bChanged = true; + } + if(data->Uin.toULong() == 0) + { + if (userClass & CLASS_AWAY) + { + m_client->fetchAwayMessage(data); + } + else + { + data->AutoReply.str() = QString::null; + } + } + } + + // Status TLV + Tlv *tlvStatus = tlv(TLV_USER_STATUS); + if(tlvStatus) + { + uint32_t status = *tlvStatus; + if (status != data->Status.toULong()) + { + data->Status.asULong() = status; + if ((status & 0xFF) == 0) + data->AutoReply.str() = QString::null; + data->StatusTime.asULong() = (unsigned long)time(NULL); + } + } + else if(data->Status.toULong() == ICQ_STATUS_OFFLINE) + { + data->Status.asULong() = ICQ_STATUS_ONLINE; + data->StatusTime.asULong() = (unsigned long)time(NULL); + } + + // Online time TLV + Tlv *tlvOnlineTime = tlv(TLV_USER_SIGNON_TIME); + if(tlvOnlineTime) + { + uint32_t OnlineTime = *tlvOnlineTime; + if(OnlineTime != data->OnlineTime.toULong()) + { + data->OnlineTime.asULong() = OnlineTime; + bChanged = true; + } + } + Tlv *tlvNATime = tlv(0x0004); + if(tlvNATime) + { + unsigned short na_time = *tlvNATime; + unsigned long StatusTime = (unsigned long)time(NULL) - na_time * 60; + if(StatusTime != data->StatusTime.toULong()) + { + data->StatusTime.asULong() = StatusTime; + bChanged = true; + } + } + + // IP TLV + Tlv *tlvIP = tlv(TLV_USER_EXT_IP); + if(tlvIP) + bChanged |= set_ip(&data->IP, htonl((uint32_t)(*tlvIP))); + + // short caps tlv + Tlv *tlvCapShort = tlv(TLV_USER_NEWCAPS); + if(tlvCapShort) + { + data->Caps.asULong() = 0; + data->Caps2.asULong() = 0; + + ICQBuffer info(*tlvCapShort); + + for (; info.readPos() < (unsigned)info.size(); ) + { + unsigned char shortcap[2]; + info.unpack((char*)shortcap, sizeof(shortcap)); + for (unsigned i = 0;; i++) + { + if(!memcmp(&m_client->capabilities[i][2], shortcap, sizeof(shortcap))) + { + m_client->setCap(data, (cap_id_t)i); + break; + } + // we don't go through all caps, only the first ones starting with 0x09 + if (*m_client->capabilities[i] != '\x09') + { + log(L_DEBUG, "%lu unknown cap %s", data->Uin.toULong(), + qPrintable(makeCapStr(shortcap, sizeof(shortcap)))); + break; + } + } + } + } + // normal cap tlv + Tlv *tlvCapability = tlv(TLV_USER_CAPS); + if (tlvCapability) + { + if(!tlvCapShort) + { + data->Caps.asULong() = 0; + data->Caps2.asULong() = 0; + } + ICQBuffer info(*tlvCapability); + for(; info.readPos() < (unsigned)info.size(); ) + { + capability cap; + info.unpack((char*)cap, sizeof(capability)); + for(unsigned i = 0;; i++) + { + unsigned size = sizeof(capability); + if (i == CAP_SIMOLD) + size--; + + if (*m_client->capabilities[i] == 0) + { + log( L_DEBUG, "%lu unknown cap %s", data->Uin.toULong(), qPrintable(makeCapStr( cap, size )) ); + break; + } + if ((i == CAP_MICQ) || (i == CAP_LICQ) || (i == CAP_SIM) || (i == CAP_KOPETE)) + size -= 4; + if ((i == CAP_ANDRQ)) + size -= 7; + if ((i == CAP_MIRANDA)) + size -= 8; + if ((i == CAP_JIMM)) + size -= 11; + + if (i == CAP_ICQJP) + size -= (16 - 4); + + if (!memcmp(cap, m_client->capabilities[i], size)) + { + if (i == CAP_SIMOLD) + { + unsigned char build = cap[sizeof(capability)-1]; + if (build && ((build == 0x92) || (build < (1 << 6)))) continue; + data->Build.asULong() = build; + } + if ((i == CAP_MICQ) || (i == CAP_LICQ) || (i == CAP_SIM) || (i == CAP_KOPETE)) + { + unsigned char *p = (unsigned char*)cap; + p += 12; + data->Build.asULong() = (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3]; + } + if ((i == CAP_ANDRQ)) + { + unsigned char *p = (unsigned char*)cap; + p += 9; + data->Build.asULong() = (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3]; + } + if ((i == CAP_MIRANDA)) + { + unsigned char *p = (unsigned char*)cap; + p += 8; + data->Build.asULong() = (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3]; + } + if ((i == CAP_JIMM)) + { + char *p = (char*)cap; + p += 5; + const QString str = QString::fromAscii(p, 10); + const QStringList sl = str.split('.'); + unsigned char maj = 0, min = 0; + unsigned short rev = 0; + if(sl.count() > 0) + maj = sl[0].toUShort(); + if(sl.count() > 1) + min = sl[1].toUShort(); + if(sl.count() > 2) + rev = sl[2].toUShort(); + + data->Build.asULong() = (maj << 24) + (min << 16) + rev; + } + if (i == CAP_ICQJP) + { + log(L_DEBUG, "%lu ICQJP cap is set", data->Uin.toULong()); + data->Build.asULong() = cap[0x4] << 0x18 | cap[0x5] << 0x10 | + cap[0x6] << 8 | cap[0x7]; + } + m_client->setCap(data, (cap_id_t)i); + break; + } + } + } + } + + // buddy info + Tlv *tlvBuddy = tlv(TLV_USER_BUDDYINFO); + if (tlvBuddy) + { + const QByteArray &ba = data->buddyHash.toBinary(); + unsigned short iconID; + unsigned char iconFlags, hashSize; + ICQBuffer info(*tlvBuddy); + QByteArray hash; + QString fname = m_client->pictureFile(data); + QFileInfo fi(fname); + + info >> iconID >> iconFlags >> hashSize; + hash.resize(hashSize); + info.unpack(hash.data(), hashSize); + if(data->buddyID.toULong() != iconID || + ba != hash || + !fi.exists() || fi.size() == 0) { + data->buddyID.asULong() = iconID; + data->buddyHash.asBinary() = hash; + m_client->requestBuddy(data); + } + } + + unsigned long infoUpdateTime = 0; + unsigned long pluginInfoTime = 0; + unsigned long pluginStatusTime = 0; + + // Direct connection info + Tlv *tlvDirect = tlv(TLV_USER_DC_INFO); + if(tlvDirect) + { + ICQBuffer info(*tlvDirect); + unsigned long realIP; + unsigned short port; + char mode, version, junk; + info >> realIP; + info.incReadPos(2); + info >> port; + if (realIP == 0x7F000001) + realIP = 0; + bChanged |= set_ip(&data->RealIP, htonl(realIP)); + data->Port.asULong() = port; + unsigned long DCcookie; + info >> mode >> junk >> version >> DCcookie; + data->DCcookie.asULong() = DCcookie; + info.incReadPos(8); + info + >> infoUpdateTime + >> pluginInfoTime + >> pluginStatusTime; + if (mode == MODE_DENIED) mode = MODE_INDIRECT; + if ((mode != MODE_DIRECT) && (mode != MODE_INDIRECT)) + mode = MODE_INDIRECT; + data->Mode.asULong() = mode; + data->Version.asULong() = version; + } + + Tlv *tlvPlugin = tlv(0x0011); + if(tlvPlugin && data->Uin.toULong()) + { + ICQBuffer info(*tlvPlugin); + char type; + unsigned long time; + info >> type; + info.unpack(time); + plugin p; + unsigned plugin_index; + unsigned long plugin_status; + switch (type){ + case 1: + m_client->addFullInfoRequest(data->Uin.toULong()); + break; + case 2: + if ((m_client->getInvisible() && data->VisibleId.toULong()) || + (!m_client->getInvisible() && (data->InvisibleId.toULong() == 0))){ + info.incReadPos(6); + info.unpack((char*)p, sizeof(p)); + data->PluginInfoTime.asULong() = time; + for (plugin_index = 0; plugin_index < PLUGIN_NULL; plugin_index++) + if (!memcmp(p, m_client->plugins[plugin_index], sizeof(p))) + break; + switch (plugin_index) + { + case PLUGIN_PHONEBOOK: + log(L_DEBUG, "Updated phonebook"); + m_client->addPluginInfoRequest(data->Uin.toULong(), plugin_index); + break; + case PLUGIN_PICTURE: + log(L_DEBUG, "Updated picture"); + // when buddyID -> new avatar support, no need to ask for old picture plugin + if(data->buddyID.toULong() == 0 || data->buddyHash.toBinary().size() != 16) { + data->buddyID.asULong() = 0; + m_client->addPluginInfoRequest(data->Uin.toULong(), plugin_index); + } + break; + case PLUGIN_QUERYxINFO: + log(L_DEBUG, "Updated info plugin list"); + m_client->addPluginInfoRequest(data->Uin.toULong(), plugin_index); + break; + default: + if (plugin_index >= PLUGIN_NULL) + log(L_WARN, "Unknown plugin sign (%04X %04X)", + type, plugin_index); + } + } + break; + case 3: + info.incReadPos(6); + info.unpack((char*)p, sizeof(p)); + info.incReadPos(1); + info.unpack(plugin_status); + data->PluginStatusTime.asULong() = time; + for (plugin_index = 0; plugin_index < PLUGIN_NULL; plugin_index++) + if (!memcmp(p, m_client->plugins[plugin_index], sizeof(p))) + break; + switch (plugin_index){ + case PLUGIN_FOLLOWME: + if (data->FollowMe.toULong() == plugin_status) + break; + data->FollowMe.asULong() = plugin_status; + bChanged = true; + break; + case PLUGIN_FILESERVER: + if ((data->SharedFiles.toBool() != 0) == (plugin_status != 0)) + break; + data->SharedFiles.asBool() = (plugin_status != 0); + bChanged = true; + break; + case PLUGIN_ICQPHONE: + if (data->ICQPhone.toULong() == plugin_status) + break; + data->ICQPhone.asULong() = plugin_status; + bChanged = true; + break; + default: + if (plugin_index >= PLUGIN_NULL) + log(L_WARN, "Unknown plugin sign (%04X %04X)", + type, plugin_index); + } + break; + + } + } + else + { + data->InfoUpdateTime.asULong() = infoUpdateTime; + data->PluginInfoTime.asULong() = pluginInfoTime; + data->PluginStatusTime.asULong() = pluginStatusTime; + if (!m_client->getDisableAutoUpdate() && + ((m_client->getInvisible() && data->VisibleId.toULong()) || + (!m_client->getInvisible() && (data->InvisibleId.toULong() == 0)))){ + if (infoUpdateTime == 0) + infoUpdateTime = 1; + if (infoUpdateTime != data->InfoFetchTime.toULong()) + m_client->addFullInfoRequest(data->Uin.toULong()); + if ((data->PluginInfoTime.toULong() != data->PluginInfoFetchTime.toULong())){ + if (data->PluginInfoTime.toULong()) + m_client->addPluginInfoRequest(data->Uin.toULong(), PLUGIN_QUERYxINFO); + } + if ((data->PluginInfoTime.toULong() != data->PluginInfoFetchTime.toULong()) || + (data->PluginStatusTime.toULong() != data->PluginStatusFetchTime.toULong())){ + if (data->SharedFiles.toBool()){ + data->SharedFiles.asBool() = false; + bChanged = true; + } + if (data->FollowMe.toULong()){ + data->FollowMe.asULong() = 0; + bChanged = true; + } + if (data->ICQPhone.toULong()){ + data->ICQPhone.asULong() = 0; + bChanged = true; + } + if (data->PluginStatusTime.toULong()) + m_client->addPluginInfoRequest(data->Uin.toULong(), PLUGIN_QUERYxSTATUS); + } + } + } + if (data->bInvisible.toBool()){ + data->bInvisible.asBool() = false; + bChanged = true; + } + if (bChanged){ + EventContact(contact, EventContact::eChanged).process(); + } + if ((data->Status.toULong() != prevStatus) || bAwayChanged){ + unsigned status = STATUS_OFFLINE; + if ((data->Status.toULong() & 0xFFFF) != ICQ_STATUS_OFFLINE){ + status = STATUS_ONLINE; + if (data->Status.toULong() & ICQ_STATUS_DND){ + status = STATUS_DND; + }else if (data->Status.toULong() & ICQ_STATUS_OCCUPIED){ + status = STATUS_OCCUPIED; + }else if (data->Status.toULong() & ICQ_STATUS_NA){ + status = STATUS_NA; + }else if (data->Status.toULong() & ICQ_STATUS_AWAY){ + status = STATUS_AWAY; + }else if (data->Status.toULong() & ICQ_STATUS_FFC){ + status = STATUS_FFC; + } + } + if((status == STATUS_ONLINE) && (data->Class.toULong() & CLASS_AWAY)) + status = STATUS_AWAY; + StatusMessage *m = new StatusMessage(); + m->setContact(contact->id()); + m->setClient(m_client->dataName(data)); + m->setStatus(status); + m->setFlags(MESSAGE_RECEIVED); + EventMessageReceived e(m); + if(!e.process()) + delete m; + if (!contact->getIgnore() && + ((data->Class.toULong() & CLASS_AWAY) == 0) && + (((data->Status.toULong() & 0xFF) == ICQ_STATUS_ONLINE) && + (((prevStatus & 0xFF) != ICQ_STATUS_ONLINE)) || bAwayChanged) && + (((prevStatus & 0xFFFF) != ICQ_STATUS_OFFLINE) || + (data->OnlineTime.toULong() > m_client->data.owner.OnlineTime.toULong()))){ + EventContact e(contact, EventContact::eOnline); + e.process(); + } + if (!m_client->getDisableAutoReplyUpdate() && ((data->Status.toULong() & 0xFF) != ICQ_STATUS_ONLINE)){ + if ((m_client->getInvisible() && data->VisibleId.toULong()) || + (!m_client->getInvisible() && (data->InvisibleId.toULong() == 0))) + m_client->addPluginInfoRequest(data->Uin.toULong(), PLUGIN_AR); + } + } + } + break; + } + default: + log(L_WARN, "Unknown buddy foodgroup type %04X", subtype); + } + return false; +} + +void ICQClient::buddyRequest() +{ + snac(ICQ_SNACxFOOD_BUDDY, ICQ_SNACxBDY_REQUESTxRIGHTS); + sendPacket(true); +} + +void ICQClient::sendContactList() +{ + buddies.clear(); + Contact *contact; + ContactList::ContactIterator it; + while ((contact = ++it) != NULL){ + ClientDataIterator it_data(contact->clientData, this); + ICQUserData *data; + while ((data = toICQUserData(++it_data)) != NULL){ + if (data->IgnoreId.toULong() == 0) + buddies.push_back(screen(data)); + } + } + if (buddies.empty()) + return; + snac(ICQ_SNACxFOOD_BUDDY, ICQ_SNACxBDY_ADDxTOxLIST); + it.reset(); + while ((contact = ++it) != NULL){ + ClientDataIterator it_data(contact->clientData, this); + ICQUserData *data; + while ((data = toICQUserData(++it_data)) != NULL){ + if (data->IgnoreId.toULong() == 0) + socket()->writeBuffer().packScreen(screen(data)); + } + } + sendPacket(true); +} + +void SnacIcqBuddy::addBuddy(Contact *contact) +{ + if (m_client->getState() != ICQClient::Connected) + return; + if (contact->id() == 0) + return; + ICQUserData *data; + ClientDataIterator it_data(contact->clientData, m_client); + while ((data = m_client->toICQUserData(++it_data)) != NULL){ + int it = m_client->buddies.indexOf(m_client->screen(data)); + if (it != -1) + continue; + if ((data->IgnoreId.toULong() == 0) && (data->WaitAuth.toBool() || (data->GrpId.toULong() == 0))){ + m_client->snac(ICQ_SNACxFOOD_BUDDY, ICQ_SNACxBDY_ADDxTOxLIST); + m_client->socket()->writeBuffer().packScreen(m_client->screen(data)); + m_client->sendPacket(true); + m_client->buddies.push_back(m_client->screen(data)); + } + } +} + +void SnacIcqBuddy::removeBuddy(Contact *contact) +{ + if (m_client->getState() != ICQClient::Connected) + return; + if (contact->id() == 0) + return; + ICQUserData *data; + ClientDataIterator it_data(contact->clientData, m_client); + while ((data = m_client->toICQUserData(++it_data)) != NULL){ + int it = m_client->buddies.indexOf(m_client->screen(data)); + if (it == -1) + continue; + if(data->WantAuth.toBool()) + { + Message *msg = new Message; + msg->setText(i18n("removed from buddy list")); + m_client->sendAuthRefused(msg, data); + } + m_client->snac(ICQ_SNACxFOOD_BUDDY, ICQ_SNACxBDY_REMOVExFROMxLIST); + m_client->socket()->writeBuffer().packScreen(m_client->screen(data)); + m_client->sendPacket(true); + m_client->buddies.removeAt(it); + } +} + diff --git a/plugins/icq/icqbuddy.h b/plugins/icq/icqbuddy.h new file mode 100644 index 0000000..1567b24 --- /dev/null +++ b/plugins/icq/icqbuddy.h @@ -0,0 +1,20 @@ + +#ifndef _ICQBUDDY_H +#define _ICQBUDDY_H + +#include "snac.h" +#include "contacts.h" + +class ICQClient; +class SnacIcqBuddy : public SnacHandler +{ +public: + SnacIcqBuddy(ICQClient* client); + virtual ~SnacIcqBuddy(); + + virtual bool process(unsigned short subtype, ICQBuffer* buf, unsigned short seq); + void addBuddy(SIM::Contact *contact); + void removeBuddy(SIM::Contact *contact); +}; + +#endif diff --git a/plugins/icq/icqbuffer.cpp b/plugins/icq/icqbuffer.cpp new file mode 100644 index 0000000..28e19fc --- /dev/null +++ b/plugins/icq/icqbuffer.cpp @@ -0,0 +1,539 @@ +/*************************************************************************** + msnfiltetransfer.cpp - description + ------------------- + begin : Fri Jan 05 2007 + copyright : (C) 2007 Christian Ehrlicher + email : ch.ehrlicher@gmx.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifdef WIN32 +#include +#else +#include +#include +#include +#include +#include +#endif + +#include "simapi.h" +#include "log.h" + +#include "icqbuffer.h" +#include + +using namespace SIM; + +// FIXME: move into own file +#ifdef WORDS_BIGENDIAN +# define SWAP_S(s) s = ((s&0xFF)<<8) + ((s&0xFF00)>>8); +# define SWAP_L(s) s = ((s&0xFF)<<24) + ((s&0xFF00)<<8) + ((s&0xFF0000)>>8) + ((s&0xFF000000)>>24); +#else +# define SWAP_S(s) +# define SWAP_L(s) +#endif +// Tlv +Tlv::Tlv(unsigned short num, unsigned short size, const char *data) + : m_nNum(num), m_nSize(size) +{ + m_data.resize(m_nSize + 1); + memcpy(m_data.data(), data, m_nSize); + m_data[(int)m_nSize] = 0; +} +Tlv::Tlv(unsigned short num, QByteArray& array) : m_nNum(num), m_nSize(array.size()) +{ + m_data = array; +} + +Tlv::operator uint16_t () const +{ + return (m_nSize >= 2) ? htons(*((uint16_t*)m_data.data())) : 0; +} + +Tlv::operator uint32_t () const +{ + return (m_nSize >= 4) ? htonl(*((uint32_t*)m_data.data())) : 0; +} + +// TlvList +TlvList::TlvList() +{} + +TlvList::TlvList(ICQBuffer &b, unsigned nTlvs) +{ + for(unsigned n = 0; (b.readPos() < (unsigned)b.size()) && (n < nTlvs); n++) + { + unsigned short num, size; + b >> num >> size; + if (b.readPos() + size > (unsigned)b.size()) + break; + append(new Tlv(num, size, b.data(b.readPos()))); + b.incReadPos(size); + } +} + +TlvList::~TlvList() +{ + qDeleteAll(*this); +} + +Tlv *TlvList::operator()(unsigned short num, int skip) +{ + for(uint i = 0; i < (unsigned)count(); i++) { + if ((at(i))->Num() == num) { + if(skip == 0) + return at(i); + --skip; + } + } + return NULL; +} + +ICQBuffer::ICQBuffer(unsigned size) + : Buffer(size) +{} + +ICQBuffer::ICQBuffer(const QByteArray &ba) + : Buffer(ba) +{} + +ICQBuffer::ICQBuffer(Tlv &tlv) + : Buffer(tlv.Size()) +{ + pack((char*)tlv, tlv.Size()); +} + + +ICQBuffer::~ICQBuffer() +{} + +void ICQBuffer::tlv(unsigned short n, const char *data, unsigned short len) +{ + *this << n << len; + pack(data, len); +} + +void ICQBuffer::tlvLE(unsigned short n, const char *data, unsigned short len) +{ + pack(n); + pack(len); + pack(data, len); +} + +void ICQBuffer::tlv(unsigned short n, const char *data) +{ + if (data == NULL) + data = ""; + tlv(n, data, (unsigned short)strlen(data)); +} + +void ICQBuffer::tlvLE(unsigned short n, const char *data) +{ + if (data == NULL) + data = ""; + unsigned short len = strlen(data) + 1; + pack(n); + pack((unsigned short)(len + 2)); + pack(len); + pack(data, len); +} + +void ICQBuffer::tlv(unsigned short n, unsigned short c) +{ + c = htons(c); + tlv(n, (char*)&c, 2); +} + +void ICQBuffer::tlvLE(unsigned short n, unsigned short c) +{ + pack(n); + pack((unsigned short)2); + pack(c); +} + +void ICQBuffer::tlv(unsigned short n, unsigned long c) +{ + /* XXX: + * WARNING! BUG HERE. sizeof(long) is not 4 on 64bit platform */ + c = htonl(c); + tlv(n, (char*)&c, 4); +} + +void ICQBuffer::tlvLE(unsigned short n, unsigned long c) +{ + /* XXX: + * WARNING! BUG HERE. sizeof(long) is not 4 on 64bit platform */ + pack(n); + pack((unsigned short)4); + pack(c); +} + +ICQBuffer &ICQBuffer::operator << (const TlvList &tlvList) +{ + unsigned size = 0; + for (uint i = 0; i < (unsigned)tlvList.count(); i++) + size += tlvList[(int)i]->Size() + 4; + *this << (unsigned short)size; + for (uint i = 0; i < (unsigned)tlvList.count(); i++) { + Tlv *tlv = tlvList[(int)i]; + *this << tlv->Num() << (int)tlv->Size(); + pack(*tlv, tlv->Size()); + } + return *this; +} + +ICQBuffer &ICQBuffer::operator << (const QString &s) +{ + QByteArray utf8 = s.toUtf8(); + unsigned short size = (unsigned short)(utf8.length() + 1); + *this << (unsigned short)htons(size); + pack(utf8, size); + return *this; +} + +/*ICQBuffer &ICQBuffer::operator << (const QByteArray &s) +{ + if(!s.length()) + return *this; + unsigned short size = (unsigned short)(s.length() + 1); + *this << (unsigned short)htons(size); + pack(s, size); + return *this; +}*/ + +ICQBuffer &ICQBuffer::operator << (const QByteArray &s) +{ + if(!s.size()) + return *this; + unsigned short size = (unsigned short)(s.size()); + *this << (unsigned short)htons(size); + pack(s, size); + return *this; +} + +ICQBuffer &ICQBuffer::operator << (const Buffer &b) +{ + unsigned short size = (unsigned short)(b.size() - b.readPos()); + *this << (unsigned short)htons(size); + pack(b.data(b.readPos()), size); + return *this; +} + +ICQBuffer &ICQBuffer::operator << (char c) +{ + pack(&c, 1); + return *this; +} + +ICQBuffer &ICQBuffer::operator << (const char *str) +{ + if(!str) + return *this; + pack(str, strlen(str)); + return *this; +} + +ICQBuffer &ICQBuffer::operator << (unsigned short c) +{ + c = htons(c); + pack((char*)&c, 2); + return *this; +} + +ICQBuffer &ICQBuffer::operator << (unsigned long c) +{ + /* XXX: + * WARNING! BUG HERE. sizeof(long) is not 4 on 64bit platform */ + c = htonl(c); + pack((char*)&c, 4); + return *this; +} + +ICQBuffer &ICQBuffer::operator << (bool b) +{ + char c = b ? (char)1 : (char)0; + pack(&c, 1); + return *this; +} + +ICQBuffer &ICQBuffer::operator >> (std::string &s) +{ + unsigned short size; + *this >> size; + size = htons(size); + s.erase(); + if (size){ + if (size > this->size() - m_posRead) + size = (unsigned short)(this->size() - m_posRead); + s.append((unsigned)size, '\x00'); + unpack((char*)s.c_str(), size); + } + return *this; +} + +ICQBuffer &ICQBuffer::operator >> (QByteArray &str) +{ + unsigned short s; + str = ""; + + *this >> s; + s = htons(s); + if (s == 0) + return *this; + if (s > size() - m_posRead) + s = (unsigned short)(size() - m_posRead); + unpack(str, s); + return *this; +} + +ICQBuffer &ICQBuffer::operator >> (char &c) +{ + if (unpack(&c, 1) != 1) + c = 0; + return *this; +} + +ICQBuffer &ICQBuffer::operator >> (unsigned short &c) +{ + if (unpack((char*)&c, 2) != 2) + c = 0; + c = ntohs(c); + return *this; +} + +ICQBuffer &ICQBuffer::operator >> (unsigned long &c) +{ + /* XXX: + * WARNING! BUG HERE. sizeof(long) is not 4 on 64bit platform */ + if (unpack((char*)&c, 4) != 4) + c = 0; + c = ntohl(c); + return *this; +} + +ICQBuffer &ICQBuffer::operator >> (int &c) +{ + if (unpack((char*)&c, 4) != 4) + c = 0; + c = ntohl(c); + return *this; +} + +void ICQBuffer::packScreen(const QString &screen) +{ + char len = screen.toUtf8().length(); + pack(&len, 1); + pack(screen.toUtf8(), len); +} + +void ICQBuffer::packStr32(const char *s) +{ + if (s) { + unsigned long size = strlen(s); + pack(size); + pack(s, strlen(s)); + } else { + pack((unsigned long)0); + pack("", 0); + } +} + +void ICQBuffer::packStr32(const QByteArray &s) +{ + unsigned long size = s.length(); + pack(size); + pack(s, size); +} + +void ICQBuffer::pack32(const Buffer &b) +{ + /* XXX: + * WARNING! BUG HERE. sizeof(long) is not 4 on 64bit platform */ + unsigned long size = b.size() - b.readPos(); + *this << (unsigned long)htonl(size); + pack(b.data(b.readPos()), size); +} + +void ICQBuffer::pack(const QByteArray &s) +{ + unsigned short size = (unsigned short)(s.size()); + *this << size; + pack(s, size); +} + +void ICQBuffer::pack(const QString &s) +{ + QByteArray cstr = s.toUtf8(); + unsigned short size = (unsigned short)(s.length()); + *this << size; + pack(cstr, size); +} + +void ICQBuffer::pack(unsigned short s) +{ + SWAP_S(s); + pack((char*)&s, 2); +} + +void ICQBuffer::pack(unsigned long s) +{ + /* XXX: + * WARNING! BUG HERE. sizeof(long) is not 4 on 64bit platform */ + unsigned int i = s; + SWAP_L(i); + pack((char*)&i, 4); +} +bool ICQBuffer::unpackStr(QString &str) +{ + unsigned short s; + str = QString::null; + *this >> s; + if (s == 0) + return false; + if (s > size() - m_posRead) + s = (unsigned short)(size() - m_posRead); + unpack(str, s); + return true; +} + +bool ICQBuffer::unpackStr(QByteArray &str) +{ + unsigned short s; + str = ""; + *this >> s; + if (s == 0) + return false; + if (s > size() - m_posRead) + s = (unsigned short)(size() - m_posRead); + unpack(str, s); + return true; +} + +void ICQBuffer::unpackStr32(std::string &s) +{ + unsigned long size; + *this >> size; + size = htonl(size); + s.erase(); + if (size == 0) return; + if (size > this->size() - m_posRead) + size = this->size() - m_posRead; + s.append(size, '\x00'); + unpack((char*)s.c_str(), size); +} + +bool ICQBuffer::unpackStr32(QByteArray &str) +{ + unsigned long s; + *this >> s; + s = ntohl(s); + str = ""; + if (s == 0) + return false; + if (s > size() - m_posRead) + s = size() - m_posRead; + unpack(str, s); + return true; +} + +/*bool ICQBuffer::unpackStr32(QByteArray &str) +{ + unsigned long s; + *this >> s; + s = ntohl(s); + str = QByteArray(); + if (s == 0) + return false; + if (s > size() - m_posRead) + s = size() - m_posRead; + unpack(str, s); + return true; +}*/ + +QString ICQBuffer::unpackScreen() +{ + char len; + QString res; + + *this >> len; + /* 13 isn't right, AIM allows 16. But when we get a longer + name, we *must* unpack them if we won't lose the TLVs + behind the Screenname ... */ + if (len > 16) + log(L_DEBUG,"Too long Screenname! Length: %d",len); + unpack(res, len); + return res; +} + +unsigned ICQBuffer::unpack(char *d, unsigned s) +{ + unsigned readn = size() - m_posRead; + if (s < readn) + readn = s; + memcpy(d, data() + m_posRead, readn); + m_posRead += readn; + return readn; +} + +unsigned ICQBuffer::unpack(QString &d, unsigned s) +{ + unsigned readn = size() - m_posRead; + if (s < readn) + readn = s; + d = QString::fromUtf8(data() + m_posRead, readn); + m_posRead += readn; + return readn; +} + +/*unsigned ICQBuffer::unpack(QByteArray &d, unsigned s) +{ + unsigned readn = size() - m_posRead; + if (s < readn) + readn = s; + d = QByteArray(data() + m_posRead, readn + 1); + m_posRead += readn; + return readn; +}*/ + +unsigned ICQBuffer::unpack(QByteArray &d, unsigned s) +{ + unsigned readn = size() - m_posRead; + if (s < readn) + readn = s; + d = QByteArray( data() + m_posRead, readn ); + unsigned size = d.size(); + d.resize(size); + m_posRead += readn; + if(d.endsWith((char)0)) + { + d.chop(1); + } + return readn; +} + +void ICQBuffer::unpack(unsigned short &c) +{ + if (unpack((char*)&c, 2) != 2) + c = 0; + SWAP_S(c); +} + +void ICQBuffer::unpack(unsigned long &c) +{ + // FIXME: This needs to be rewritten for 64-bit machines. + // Kludge for now. + unsigned int i; + if (unpack((char*)&i, 4) != 4) + i = 0; + SWAP_L(i); + c = i; +} diff --git a/plugins/icq/icqbuffer.h b/plugins/icq/icqbuffer.h new file mode 100644 index 0000000..f15ee25 --- /dev/null +++ b/plugins/icq/icqbuffer.h @@ -0,0 +1,152 @@ +/*************************************************************************** + icqbuffer.h - description + ------------------- + begin : Fri Jan 05 2007 + copyright : (C) 2007 by Christian Ehrlicher + email : ch.ehrlicher@gmx.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +#ifndef _ICQBUFFER_H +#define _ICQBUFFER_H + +#include "buffer.h" +#include "socket/socket.h" +#include "socket/clientsocket.h" +#include //Fixme +#include + +class QByteArray; +class ICQBuffer; +class Tlv +{ +public: + Tlv(unsigned short num = 0, unsigned short size = 0, const char *data = NULL); + Tlv(unsigned short num, QByteArray& array); + unsigned short Num() const { return m_nNum; } + unsigned short Size() const { return m_nSize; } + const char *Data() const { return m_data.data(); } + operator const char* () const { return (const char*)m_data.data(); } + operator char* () { return m_data.data(); } + const QByteArray &byteArray() const { return m_data; } + operator uint16_t () const; + operator uint32_t () const; +protected: + unsigned int m_nNum; + unsigned int m_nSize; + QByteArray m_data; +}; + +class TlvList : public QList +{ +public: + TlvList(); + TlvList(ICQBuffer&, unsigned nTlvs = ~0U); + ~TlvList(); + // return Tlv, since there can be more than one Tlv inside + // a package, you can specificy how much Tlv should be skipped + Tlv *operator() (unsigned short num, int skip = 0); +}; + +class ICQBuffer : public Buffer +{ +public: + ICQBuffer(unsigned size = 0); + ICQBuffer(const QByteArray &ba); + ICQBuffer(Tlv&); + virtual ~ICQBuffer(); + + void tlv(unsigned short n, const char *data, unsigned short len); + void tlv(unsigned short n) { tlv(n, NULL, 0); } + void tlv(unsigned short n, const char *data); + void tlv(unsigned short n, unsigned short c); + void tlv(unsigned short n, int c) { tlv(n, (unsigned short)c); } + void tlv(unsigned short n, unsigned long c); + void tlv(unsigned short n, long c) { tlv(n, (unsigned long)c); } + void tlv(unsigned short n, Buffer &b) { tlv(n, b.data(), (unsigned short)(b.size())); } + + void tlvLE(unsigned short n, const char *data, unsigned short len); + void tlvLE(unsigned short n, const char *data); + void tlvLE(unsigned short n, char c) { tlvLE(n, &c, 1); } + void tlvLE(unsigned short n, unsigned short c); + void tlvLE(unsigned short n, unsigned long c); + void tlvLE(unsigned short n, Buffer &b) { tlvLE(n, b.data(), (unsigned short)(b.size())); } + + ICQBuffer &operator << (const TlvList&); + ICQBuffer &operator << (const QString &s); // utf8 + ICQBuffer &operator << (const QByteArray &s); + //ICQBuffer &operator << (const QByteArray &s); + ICQBuffer &operator << (const Buffer &b); + ICQBuffer &operator << (char c); + ICQBuffer &operator << (unsigned char c) { return operator << ((char)c); } + ICQBuffer &operator << (const char *str); + ICQBuffer &operator << (unsigned short c); + ICQBuffer &operator << (int c) { return operator << ((unsigned short)c); } + ICQBuffer &operator << (unsigned long c); + ICQBuffer &operator << (long c) { return operator << ((unsigned long)c); } + ICQBuffer &operator << (const bool b); + + ICQBuffer &operator >> (std::string &s); //Ported from 0.9.4 + ICQBuffer &operator >> (QByteArray &s); // size is 2 byte & little endian! + ICQBuffer &operator >> (char &c); + ICQBuffer &operator >> (unsigned char &c) { return operator >> ((char&)c); } + ICQBuffer &operator >> (unsigned short &c); + ICQBuffer &operator >> (unsigned long &c); + ICQBuffer &operator >> (int &c); + + void pack(const QString &s); + void pack(const QByteArray &s); + void pack(const char *d, unsigned size) { Buffer::pack(d, size); } + void pack(const unsigned char *d, unsigned size) { Buffer::pack((const char*)d, size); } + void pack(char c) { *this << c; } + void pack(unsigned char c) { *this << c; } + void pack(unsigned short c); + void pack(unsigned long c); + void pack(long c) { pack((unsigned long)c); } + + void packScreen(const QString &); + void packStr32(const char *s); + void packStr32(const QByteArray &); + void pack32(const Buffer &b); + + // 2 byte size + string + bool unpackStr(QString &s); // utf8 + bool unpackStr(QByteArray &s); + // 4 byte size + string + void unpackStr32(std::string &s); // Ported from 0.9.4 + bool unpackStr32(QByteArray &s); + //bool unpackStr32(QByteArray &s); + QString unpackScreen(); + + void unpack(char &c) { *this >> c; } + void unpack(unsigned char &c) { *this >> c; } + unsigned unpack(char *d, unsigned size); + unsigned unpack(QString &d, unsigned size); // utf8 + unsigned unpack(QByteArray &d, unsigned size); + //unsigned unpack(QByteArray &d, unsigned size); + void unpack(unsigned short &c); + void unpack(unsigned long &c); +}; + +class ICQClientSocket : public SIM::ClientSocket +{ +public: + ICQClientSocket(SIM::ClientSocketNotify *notify, SIM::Socket *sock = NULL) + : ClientSocket(notify, sock) {}; + ~ICQClientSocket() {}; + + virtual ICQBuffer &readBuffer() { return m_readICQBuffer; } + virtual ICQBuffer &writeBuffer() { return m_writeICQBuffer; } +protected: + ICQBuffer m_readICQBuffer; + ICQBuffer m_writeICQBuffer; +}; + +#endif // _ICQBUFFER_H diff --git a/plugins/icq/icqclient.cpp b/plugins/icq/icqclient.cpp new file mode 100644 index 0000000..0f4470f --- /dev/null +++ b/plugins/icq/icqclient.cpp @@ -0,0 +1,3568 @@ +/*************************************************************************** + icqclient.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "buffer.h" +#include "socket/socket.h" +#include "unquot.h" +#include "log.h" +#include "icons.h" +#include "contacts/contact.h" +#include "contacts/group.h" + +#include "icq.h" +#include "icqconfig.h" +#include "aimconfig.h" +#include "icqinfo.h" +#include "homeinfo.h" +#include "workinfo.h" +#include "moreinfo.h" +#include "aboutinfo.h" +#include "interestsinfo.h" +#include "pastinfo.h" +#include "icqpicture.h" +#include "aiminfo.h" +#include "icqsearch.h" +#include "icqsecure.h" +#include "icqmessage.h" +#include "securedlg.h" +#include "msgedit.h" +#include "simgui/ballonmsg.h" +#include "encodingdlg.h" +#include "warndlg.h" + +#include "icqbuddy.h" +#include "icqservice.h" + +#include "icqdirect.h" + + +using namespace std; +using namespace SIM; + +static DataDef _icqUserData[] = + { + { "", DATA_ULONG, 1, DATA(1) }, // Sign + { "LastSend", DATA_ULONG, 1, 0 }, + { "Alias", DATA_UTF, 1, 0 }, // Alias + { "Cellular", DATA_UTF, 1, 0 }, // Cellular + { "", DATA_ULONG, 1, DATA(0xFFFF) }, // Status + { "", DATA_ULONG, 1, 0 }, // Class + { "StatusTime", DATA_ULONG, 1, 0 }, + { "", DATA_ULONG, 1, 0 }, // OnlineTime + { "WarningLevel", DATA_ULONG, 1, 0 }, + { "IP", DATA_IP, 1, 0 }, + { "RealIP", DATA_IP, 1, 0 }, + { "Port", DATA_ULONG, 1, 0 }, + { "", DATA_ULONG, 1, 0 }, // DCcookie + { "Caps", DATA_ULONG, 1, 0 }, + { "Caps2", DATA_ULONG, 1, 0 }, + { "", DATA_STRING, 1, 0 }, // AutoReply + { "Uin", DATA_ULONG, 1, 0 }, + { "Screen", DATA_STRING, 1, 0 }, + { "ID", DATA_ULONG, 1, 0 }, + { "", DATA_BOOL, 1, DATA(1) }, // bChecked + { "GroupID", DATA_ULONG, 1, 0 }, + { "Ignore", DATA_ULONG, 1, 0 }, + { "Visible", DATA_ULONG, 1, 0 }, + { "", DATA_ULONG, 1, 0 }, // ContactVisibleId + { "Invsible", DATA_ULONG, 1, 0 }, + { "", DATA_ULONG, 1, 0 }, // ContactInvisibleId + { "WaitAuth", DATA_BOOL, 1, 0 }, // Need auth from to add to our contact list + { "WantAuth", DATA_BOOL, 1, 0 }, // Want's auth from us + { "WebAware", DATA_BOOL, 1, DATA(1) }, + { "InfoUpdateTime", DATA_ULONG, 1, 0 }, + { "PluginInfoTime", DATA_ULONG, 1, 0 }, + { "PluginStatusTime", DATA_ULONG, 1, 0 }, + { "InfoFetchTime", DATA_ULONG, 1, 0 }, + { "PluginInfoFetchTime", DATA_ULONG, 1, 0 }, + { "PluginStatusFetchTime", DATA_ULONG, 1, 0 }, + { "Mode", DATA_ULONG, 1, 0 }, + { "Version", DATA_ULONG, 1, 0 }, + { "Build", DATA_ULONG, 1, 0 }, + { "Nick", DATA_STRING, 1, 0 }, + { "FirstName", DATA_STRING, 1, 0 }, + { "LastName", DATA_STRING, 1, 0 }, + { "MiddleName", DATA_STRING, 1, 0 }, + { "Maiden", DATA_STRING, 1, 0 }, + { "EMail", DATA_STRING, 1, 0 }, + { "HiddenEMail", DATA_BOOL, 1, 0 }, + { "City", DATA_STRING, 1, 0 }, + { "State", DATA_STRING, 1, 0 }, + { "HomePhone", DATA_STRING, 1, 0 }, + { "HomeFax", DATA_STRING, 1, 0 }, + { "Address", DATA_UTF, 1, 0 }, + { "PrivateCellular", DATA_STRING, 1, 0 }, + { "Zip", DATA_STRING, 1, 0 }, + { "Country", DATA_ULONG, 1, 0 }, + { "TimeZone", DATA_ULONG, 1, 0 }, + { "Age", DATA_ULONG, 1, 0 }, + { "Gender", DATA_ULONG, 1, 0 }, + { "Homepage", DATA_STRING, 1, 0 }, + { "BirthYear", DATA_ULONG, 1, 0 }, + { "BirthMonth", DATA_ULONG, 1, 0 }, + { "BirthDay", DATA_ULONG, 1, 0 }, + { "Language", DATA_ULONG, 1, 0 }, + { "", DATA_STRING, 1, 0 }, + { "WorkCity", DATA_STRING, 1, 0 }, + { "WorkState", DATA_STRING, 1, 0 }, + { "", DATA_STRING, 1, 0 }, + { "", DATA_STRING, 1, 0 }, + { "WorkAddress", DATA_STRING, 1, 0 }, + { "WorkZip", DATA_STRING, 1, 0 }, + { "WorkCountry", DATA_ULONG, 1, 0 }, + { "WorkName", DATA_STRING, 1, 0 }, + { "WorkDepartment", DATA_STRING, 1, 0 }, + { "WorkPosition", DATA_STRING, 1, 0 }, + { "Occupation", DATA_ULONG, 1, 0 }, + { "WorkHomepage", DATA_STRING, 1, 0 }, + { "About", DATA_STRING, 1, 0 }, + { "Interests", DATA_STRING, 1, 0 }, + { "Backgrounds", DATA_STRING, 1, 0 }, + { "Affilations", DATA_STRING, 1, 0 }, + { "FollowMe", DATA_ULONG, 1, 0 }, + { "SharedFiles", DATA_BOOL, 1, 0 }, // Shared files + { "ICQPhone", DATA_ULONG, 1, 0 }, // ICQPhone + { "Picture", DATA_UTF, 1, 0 }, + { "PictureWidth", DATA_ULONG, 1, 0 }, + { "PictureHeight", DATA_ULONG, 1, 0 }, + { "PhoneBook", DATA_STRING, 1, 0 }, + { "ProfileFetch", DATA_BOOL, 1, 0 }, + { "", DATA_BOOL, 1, 0 }, // bTyping + { "", DATA_BOOL, 1, 0 }, // bBadClient + { "", DATA_OBJECT, 1, 0 }, // Direct + { "", DATA_OBJECT, 1, 0 }, // DirectPluginInfo + { "", DATA_OBJECT, 1, 0 }, // DirectPluginStatus + { "", DATA_BOOL, 1, 0 }, // bNoDirect + { "", DATA_BOOL, 1, 0 }, // bInviisble + { "", DATA_ULONG, 1, 0}, // buddyRosterID + { "buddyID", DATA_ULONG, 1, 0}, + { "buddyHash", DATA_BINARY, 1, 0}, + { "unknown2", DATA_BINARY, 1, 0}, + { "unknown4", DATA_BINARY, 1, 0}, + { "unknown5", DATA_BINARY, 1, 0}, + { NULL, DATA_UNKNOWN, 0, 0 } + }; + +const DataDef *ICQProtocol::icqUserData = _icqUserData; + +static DataDef icqClientData[] = + { + { "Server", DATA_STRING, 1, 0 }, + { "ServerPort", DATA_ULONG, 1, DATA(5190) }, + { "", DATA_ULONG, 1, 0 }, + { "", DATA_ULONG, 1, 0 }, + { "", DATA_ULONG, 1, 0 }, + { "HideIP", DATA_BOOL, 1, 0 }, + { "IgnoreAuth", DATA_BOOL, 1, 0 }, + { "UseMD5", DATA_BOOL, 1, 0 }, + { "DirectMode", DATA_ULONG, 1, 0 }, + { "IdleTime", DATA_ULONG, 1, 0 }, + { "ListRequests", DATA_STRING, 1, 0 }, + { "Picture", DATA_UTF, 1, 0 }, + { "RandomChatGroup", DATA_ULONG, 1, 0 }, + { "", DATA_ULONG, 1, 0 }, // RandomChatGroupCurrent + { "SendFormat", DATA_ULONG, 1, DATA(1) }, // use utf-8 whereever possible + { "DisablePlugins", DATA_BOOL, 1, 0 }, + { "DisableAutoUpdate", DATA_BOOL, 1, 0 }, + { "DisableAutoReplyUpdate", DATA_BOOL, 1, 0 }, + { "DisableTypingNotification", DATA_BOOL, 1, 0 }, + { "AcceptInDND", DATA_BOOL, 1, DATA(1) }, + { "AcceptInOccupied", DATA_BOOL, 1, DATA(1) }, + { "MinPort", DATA_ULONG, 1, DATA(1024) }, + { "MaxPort", DATA_ULONG, 1, DATA(0xFFFE) }, + { "WarnAnonimously", DATA_BOOL, 1, 0 }, + { "ACKMode", DATA_ULONG, 1, DATA(1) }, + { "UseHTTP", DATA_BOOL, 1, DATA(0) }, + { "AutoHTTP", DATA_BOOL, 1, DATA(0) }, + { "KeepAlive", DATA_BOOL, 1, DATA(1) }, + { "MediaSense", DATA_BOOL, 1, DATA(1) }, + { "", DATA_STRUCT, sizeof(ICQUserData) / sizeof(Data), DATA(_icqUserData) }, + { NULL, DATA_UNKNOWN, 0, 0 } + }; + +ICQClient::ICQClient(Protocol *protocol, Buffer *cfg, bool bAIM) + : TCPClient(protocol, cfg, HighPriority - 1), + m_bVerifying (false), + m_listener (NULL), + m_listRequest (NULL), + m_bRosters (false), + m_bBirthday (false), + m_bNoSend (true), + m_bJoin (false), + m_bFirstTry (false), + m_bReady (false), + m_bconnectionLost (false), + m_ifChecker (NULL), + m_bBirthdayInfoDisplayed (false) +{ + m_bAIM = bAIM; + + load_data(icqClientData, &data, cfg); + if (data.owner.Uin.toULong() != 0) + m_bAIM = false; + if (!data.owner.Screen.str().isEmpty()) + m_bAIM = true; + + data.owner.DCcookie.asULong() = rand(); + + QString requests = getListRequests(); + while (requests.length()) + { + QString req = getToken(requests, ';'); + QString n = getToken(req, ','); + ListRequest lr; + lr.type = n.toUInt(); + lr.screen = req; + listRequests.push_back(lr); + } + + m_snacBuddy = new SnacIcqBuddy(this); + m_snacICBM = new SnacIcqICBM(this); + m_snacService = new SnacIcqService(this); + addSnacHandler(m_snacBuddy); + addSnacHandler(m_snacICBM); + addSnacHandler(m_snacService); + + m_processTimer = new QTimer(this); + connect(m_processTimer, SIGNAL(timeout()), m_snacICBM, SLOT(processSendQueue())); + + disconnected(); + + ContactList::ContactIterator it; + Contact *contact; + while ((contact = ++it) != NULL) + { + ClientDataIterator itd(contact->clientData, this); + ICQUserData *data; + while ((data = toICQUserData(++itd)) != NULL) + data->Alias.str() = contact->getName(); + } + if ( !getMediaSense() ) + return; + + m_ifChecker = new SIM::InterfaceChecker(); + connect(m_ifChecker, SIGNAL(interfaceDown(QString)), this, SLOT(interfaceDown(QString))); + connect(m_ifChecker, SIGNAL(interfaceUp(QString)), this, SLOT(interfaceUp(QString))); + +} + +ICQClient::~ICQClient() +{ + setStatus(STATUS_OFFLINE, false); + freeData(); // before deleting of other members! + + delete m_listener; + delete m_snacService; + delete m_snacBuddy; + delete m_snacICBM; + delete m_ifChecker; //independed if MediaSense is activated, it can be risk-less deleted, because it is initilized with NULL + free_data(icqClientData, &data); + delete socket(); + for(list::iterator it = m_processMsg.begin(); it != m_processMsg.end(); ++it) + { + Message *msg = *it; + msg->setError(I18N_NOOP("Process message failed")); //crashed on shutdown + // FIXME: this does not work and could crash!!!! + // Event e(EventRealSendMessage, msg); + // e.process(); + delete msg; + } + while (!m_sockets.empty()) + delete m_sockets.front(); + m_processMsg.clear(); +} + +bool ICQClient::addSnacHandler(SnacHandler* handler) +{ + if(!handler) + return false; + mapSnacHandlers::iterator it = m_snacHandlers.find(handler->getType()); + if(it != m_snacHandlers.end()) + delete it->second; + m_snacHandlers[handler->getType()] = handler; + return true; +} + +void ICQClient::clearSnacHandlers() +{ + // TODO +} + +void ICQClient::deleteFileMessage(MessageId const& cookie) +{ + for(list::iterator it = m_processMsg.begin(); it != m_processMsg.end(); ++it) + { + if((*it)->baseType() == MessageFile) + { + AIMFileMessage* afm = static_cast(*it); + if (afm && afm->getID_L() == cookie.id_l && afm->getID_H() == cookie.id_h) + { + m_processMsg.erase(it); + return; + } + } + } +} + +void ICQClient::contactsLoaded() +{ + /* outdated + QTextCodec *codec = getContacts()->getCodec(NULL); + QString cdc = codec->name(); + if (codec && (cdc.lower().indexOf("utf") >= 0)){ + QString _def_enc = I18N_NOOP("Dear translator! type this default encoding for your language"); + QString def_enc = i18n(_def_enc); + if (def_enc == _def_enc){ + EncodingDlg dlg(NULL, this); + dlg.exec(); + }else{ + getContacts()->owner()->setEncoding(def_enc); + } + } + */ +} + +const DataDef *ICQProtocol::userDataDef() +{ + return _icqUserData; +} + +const DataDef *AIMProtocol::userDataDef() +{ + return _icqUserData; +} + +bool ICQClient::compareData(void *d1, void *d2) +{ + ICQUserData *data1 = toICQUserData((SIM::clientData*) d1); // FIXME unsafe type conversion + ICQUserData *data2 = toICQUserData((SIM::clientData*) d2); // FIXME unsafe type conversion + if (data1->Uin.toULong()) + return data1->Uin.toULong() == data2->Uin.toULong(); + if (data2->Uin.toULong()) + return false; + return (data1->Screen.str() == data2->Screen.str()); +} + +QByteArray ICQClient::getConfig() +{ + QString listRequest; + for (list::iterator it = listRequests.begin(); it != listRequests.end(); ++it) + { + if (listRequest.length()) + listRequest += ';'; + listRequest += QString::number(it->type); + listRequest += ','; + listRequest += it->screen; + } + setListRequests(listRequest); + QByteArray res = Client::getConfig(); + if (res.length()) + res += '\n'; + return res += save_data(icqClientData, &data); +} + +QString ICQClient::name() +{ + if (m_bAIM) + return "AIM." + data.owner.Screen.str(); + return "ICQ." + QString::number(data.owner.Uin.toULong()); +} + +QString ICQClient::getScreen() +{ + if (m_bAIM) + return data.owner.Screen.str(); + return QString::number(data.owner.Uin.toULong()); +} + +QWidget *ICQClient::setupWnd() +{ + if (m_bAIM) + return new AIMConfig(NULL, this, true); + return new ICQConfig(NULL, this, true); +} + +static const char aim_server[] = "login.oscar.aol.com"; +static const char icq_server[] = "login.icq.com"; + +QString ICQClient::getServer() const +{ + if (!data.Server.str().isEmpty()) + return data.Server.str(); + return m_bAIM ? aim_server : icq_server; +} + +void ICQClient::setServer(const QString &server) +{ + if (server == (m_bAIM ? aim_server : icq_server)) + data.Server.str() = QString::null; + else + data.Server.str() = server; +} + +void ICQClient::setUin(unsigned long uin) +{ + data.owner.Uin.asULong() = uin; +} + +void ICQClient::setScreen(const QString &screen) +{ + data.owner.Screen.str() = screen; +} + +unsigned long ICQClient::getUin() +{ + return data.owner.Uin.toULong(); +} + +void ICQClient::generateCookie(MessageId& id) +{ + // Just for fun: + id.id_h = rand() + (rand() << 16); + id.id_l = rand() + (rand() << 16); +} + +bool ICQClient::isMyData(clientData *&_data, Contact *&contact) +{ + if (_data->Sign.toULong() != ICQ_SIGN) + return false; + ICQUserData *data = toICQUserData(_data); + if (m_bAIM) + { + if (!data->Screen.str().isEmpty() && + !this->data.owner.Screen.str().isEmpty() && + data->Screen.str().toLower() == this->data.owner.Screen.str().toLower()) + return false; + } + else if (data->Uin.toULong() == this->data.owner.Uin.toULong()) + return false; + ICQUserData *my_data = findContact(screen(data), NULL, false, contact); + if (my_data) + data = my_data; + else + contact = NULL; + return true; +} + +bool ICQClient::createData(clientData *&_data, Contact *contact) +{ + ICQUserData *data = toICQUserData(_data); + ICQUserData *new_data = toICQUserData((SIM::clientData*)contact->clientData.createData(this)); // FIXME unsafe type conversion + new_data->Uin = data->Uin; + new_data->Screen.str() = data->Screen.str(); + _data = (clientData*)new_data; + return true; +} + +OscarSocket::OscarSocket() +{ + //m_nFlapSequence = (unsigned short)(rand() & 0x7FFF); + m_nFlapSequence = 8984; + m_nMsgSequence = 0; +} + +void OscarSocket::connect_ready() +{ + socket()->readBuffer().init(6); + socket()->readBuffer().packetStart(); + m_bHeader = true; +} + +void ICQClient::connect_ready() +{ + log(L_DEBUG, "ICQClient::connect_ready()"); + m_bFirstTry = false; + if (m_listener == NULL) + { + m_listener = new ICQListener(this); + m_listener->bind(getMinPort(), getMaxPort(), NULL); + } + m_bNoSend = false; + m_bReady = true; + OscarSocket::connect_ready(); + TCPClient::connect_ready(); +} + +void ICQClient::setNewLevel(RateInfo &r) +{ + QDateTime now = QDateTime::currentDateTime(); + unsigned delta = 0; + if (now.date() == r.m_lastSend.date()) + delta = r.m_lastSend.time().msecsTo(now.time()); + unsigned res = (((r.m_winSize - 1) * r.m_curLevel) + delta) / 4 * r.m_winSize; + if (res > r.m_maxLevel) + res = r.m_maxLevel; + r.m_curLevel = res; + r.m_lastSend = now; + log(L_DEBUG, "Level: %04X [%04X %04X]", res, r.m_minLevel, r.m_winSize); +} + +RateInfo *ICQClient::rateInfo(unsigned snac) +{ + RATE_MAP::iterator it = m_rate_grp.find(snac); + if (it == m_rate_grp.end()) + return NULL; + return &m_rates[it->second]; +} + +unsigned ICQClient::delayTime(unsigned snac) +{ + RateInfo *r = rateInfo(snac); + if (r == NULL) + return 0; + return delayTime(*r); +} + +unsigned ICQClient::delayTime(RateInfo &r) +{ + if (r.m_winSize == 0) + return 0; + int res = r.m_minLevel * r.m_winSize - r.m_curLevel * (r.m_winSize - 1); + if (res < 0) + return 0; + QDateTime now = QDateTime::currentDateTime(); + unsigned delta = 0; + if (now.date() == r.m_lastSend.date()) + delta = r.m_lastSend.time().msecsTo(now.time()); + res -= delta; + return (res > 0) ? res : 0; +} + +void ICQClient::setStatus(unsigned status, bool bCommon) +{ + if (status != STATUS_OFFLINE) + { + if (status != STATUS_NA && status != STATUS_AWAY) + setIdleTime(0); + else if (getIdleTime() == 0) + setIdleTime(QDateTime::currentDateTime().toTime_t()); + } + TCPClient::setStatus(status, bCommon); +} + +void ICQClient::changeStatus(const SIM::IMStatusPtr& status) +{ + if (status->id() == "offline") + { + flap(ICQ_CHNxCLOSE); + return; + } + if (m_bAIM) + { + if (status->id() == "online") + { + IMStatusPtr newstatus = protocol()->status("away"); + // TODO obtain AR + + /* + ar_request req; + req.bDirect = true; + arRequests.push_back(req); + + ARRequest ar; + ar.contact = NULL; + ar.param = &arRequests.back(); + ar.receiver = this; + ar.status = status; + EventARRequest(&ar).process(); + EventClientChanged(this).process(); + */ + } + else if (m_status != STATUS_ONLINE) + { + setAwayMessage(); + } + } + else + { + if (status->id() == currentStatus()->id()) + return; + + snacService()->sendStatus(fullStatus(status)); + } + TCPClient::changeStatus(status); +} + +void ICQClient::setStatus(unsigned status) +{ + if (status == STATUS_OFFLINE) + { + flap(ICQ_CHNxCLOSE); + return; + } + if (m_bAIM) + { + if (status != STATUS_ONLINE) + { + m_status = STATUS_AWAY; + + ar_request req; + req.type = 0; + req.flags = 0; + req.ack = 0; + req.id1 = req.id2 = 0; + req.bDirect = true; + arRequests.push_back(req); + + ARRequest ar; + ar.contact = NULL; + ar.param = &arRequests.back(); + ar.receiver = this; + ar.status = status; + EventARRequest(&ar).process(); + EventClientChanged(this).process(); + } + else if (m_status != STATUS_ONLINE) + { + m_status = STATUS_ONLINE; + setAwayMessage(); + EventClientChanged(this).process(); + } + return; + } + if (status == m_status) + return; + + m_status = status; + snacService()->sendStatus(); + EventClientChanged(this).process(); +} + +void ICQClient::setInvisible(bool bState) +{ + if (bState != getInvisible()) + { + TCPClient::setInvisible(bState); + if (getState() == Connected) + snacService()->setInvisible(); + EventClientChanged(this).process(); + } +} + +void ICQClient::disconnected() +{ + TCPClient::changeStatus(protocol()->status("offline")); + m_rates.clear(); + m_rate_grp.clear(); + snacICBM()->getSendTimer()->stop(); + m_processTimer->stop(); + clearServerRequests(); + clearListServerRequest(); + clearSMSQueue(); + snacICBM()->clearMsgQueue(); + buddies.clear(); + Contact *contact; + ContactList::ContactIterator it; + arRequests.clear(); + while ((contact = ++it) != NULL) + { + ICQUserData *data; + ClientDataIterator it(contact->clientData, this); + while ((data = toICQUserData(++it)) != NULL) + { + if ((data->Status.toULong() != ICQ_STATUS_OFFLINE) || data->bInvisible.toBool()) + { + setOffline(data); + StatusMessage *m = new StatusMessage(); + m->setContact(contact->id()); + m->setClient(dataName(data)); + m->setStatus(STATUS_OFFLINE); + m->setFlags(MESSAGE_RECEIVED); + EventMessageReceived e(m); + if(e.process()) + continue; + delete m; + } + } + } + for (list::iterator itm = m_acceptMsg.begin(); itm != m_acceptMsg.end(); ++itm) + { + EventMessageDeleted(*itm).process(); + delete *itm; + } + m_acceptMsg.clear(); + m_bRosters = false; + m_nMsgSequence = 0; + m_bNoSend = true; + m_bReady = false; + m_cookie.resize(0); + m_advCounter = 0; + m_info_req.clear(); + if(m_snacService) + m_snacService->clearServices(); + if (m_listener) + { + delete m_listener; + m_listener = NULL; + } + m_nFlapSequence = 8984; +} + +const char *icq_error_codes[] = {I18N_NOOP("Unknown error"), + I18N_NOOP("Invalid SNAC header"), + I18N_NOOP("Server rate limit exceeded"), + I18N_NOOP("Client rate limit exceeded"), + I18N_NOOP("Recipient is not logged in"), + I18N_NOOP("Requested service unavailable"), + I18N_NOOP("Requested service not defined"), + I18N_NOOP("We sent an obsolete SNAC"), + I18N_NOOP("Not supported by server"), + I18N_NOOP("Not supported by client"), + I18N_NOOP("Refused by client"), + I18N_NOOP("Reply too big"), + I18N_NOOP("Responses lost"), + I18N_NOOP("Request denied"), + I18N_NOOP("Incorrect SNAC format"), + I18N_NOOP("Insufficient rights"), + I18N_NOOP("Recipient blocked"), + I18N_NOOP("Sender too evil"), + I18N_NOOP("Receiver too evil"), + I18N_NOOP("User temporarily unavailable"), + I18N_NOOP("No match"), + I18N_NOOP("List overflow"), + I18N_NOOP("Request ambiguous"), + I18N_NOOP("Server queue full"), + I18N_NOOP("Not while on AOL")}; + +const char* ICQClient::error_message(unsigned short error) +{ + if (error >= 1 && error <= 0x18) + return icq_error_codes[error]; + return icq_error_codes[0]; +} + +void OscarSocket::packet_ready() +{ + unsigned short l_size = 0; + if(m_bHeader) + { + char c; + socket()->readBuffer() >> c; + if (c != 0x2A) + { + log(L_ERROR, "Server send bad packet start code: %02X", c); + socket()->error_state(I18N_NOOP("Protocol error")); + return; + } + socket()->readBuffer() >> m_nChannel; + unsigned short sequence; + socket()->readBuffer() >> sequence >> l_size; + m_bHeader = false; + if (l_size) + { + socket()->readBuffer().add(l_size); + return; + } + } + l_size = socket()->readBuffer().size() - socket()->readBuffer().readPos(); + packet(l_size); +} + +void ICQClient::packet_ready() +{ + OscarSocket::packet_ready(); +} + +void ICQClient::packet(unsigned long size) +{ + ICQPlugin *plugin = static_cast(protocol()->plugin()); + EventLog::log_packet(socket()->readBuffer(), false, plugin->OscarPacket); + if (m_nChannel == ICQ_CHNxNEW) + chn_login(); + else if (m_nChannel == ICQ_CHNxCLOSE) + chn_close(); + else if (m_nChannel == ICQ_CHNxDATA) + { + unsigned short food, type; + unsigned short flags, seq, cmd; + socket()->readBuffer() >> food >> type >> flags >> cmd >> seq; + unsigned short unknown_length = 0; + if (flags & 0x8000) + { + // some unknown data before real snac data + // just read the length and forget it ;-) + socket()->readBuffer() >> unknown_length; + socket()->readBuffer().incReadPos(unknown_length); + } + // now just take a look at the type because 0x0001 == error + // in all foodgroups + if (type == 0x0001) + { + unsigned short err_code; + socket()->readBuffer() >> err_code; + log(L_DEBUG, "Error! foodgroup: %04X reason: %s", food, error_message(err_code)); + // now decrease for icqicmb & icqvarious + socket()->readBuffer().decReadPos(sizeof(unsigned short)); + } + if (food == ICQ_SNACxFOOD_LOCATION) + snac_location(type, seq); + else if (food == ICQ_SNACxFOOD_BOS) + snac_bos(type, seq); + else if (food == ICQ_SNACxFOOD_PING) + snac_ping(type, seq); + else if (food == ICQ_SNACxFOOD_LISTS) + snac_lists(type, seq); + else if (food == ICQ_SNACxFOOD_VARIOUS) + snac_various(type, seq); + else if (food == ICQ_SNACxFOOD_LOGIN) + snac_login(type, seq); + else + { + mapSnacHandlers::iterator it = m_snacHandlers.find(food); + if (it == m_snacHandlers.end()) + log(L_WARN, "Unknown foodgroup %04X", food); + else + { + ICQBuffer b; + b.resize(size - unknown_length); + b.setReadPos(0); + b.setWritePos(size - unknown_length); + socket()->readBuffer().unpack(b.data(), size - unknown_length); + it->second->process(type, &b, seq); + } + } + } + else log(L_ERROR, "Unknown channel %u", m_nChannel & 0xFF); + socket()->readBuffer().init(6); + socket()->readBuffer().packetStart(); + m_bHeader = true; +} + +void OscarSocket::flap(char channel) +{ + socket()->writeBuffer().packetStart(); + socket()->writeBuffer() + << (char)0x2A + << channel + << 0x00000000L; +} + +void OscarSocket::snac(unsigned short food, unsigned short type, bool msgId, bool bType) +{ + flap(ICQ_CHNxDATA); + socket()->writeBuffer() + << food + << type + << 0x0000 + << (bType ? type : (unsigned short)0) + << (msgId ? ++m_nMsgSequence : 0x0000); +} + +void OscarSocket::sendPacket(bool bSend) +{ + Buffer &writeBuffer = socket()->writeBuffer(); + char *packet = writeBuffer.data(writeBuffer.packetStartPos()); + unsigned size = writeBuffer.size() - writeBuffer.packetStartPos() - 6; + packet[4] = (char)((size >> 8) & 0xFF); + packet[5] = (char)(size & 0xFF); + if (bSend) + { + packet[2] = (m_nFlapSequence >> 8); + packet[3] = m_nFlapSequence; + EventLog::log_packet(socket()->writeBuffer(), true, ICQPlugin::icq_plugin->OscarPacket); + socket()->write(); + ++m_nFlapSequence; + } +} + +void ICQClient::sendPacket(bool bSend) +{ + Buffer &writeBuffer = socket()->writeBuffer(); + unsigned char *packet = (unsigned char*)(writeBuffer.data(writeBuffer.readPos())); + unsigned long snac = 0; + if (writeBuffer.writePos() >= writeBuffer.readPos() + 10) + snac = (packet[6] << 24) + (packet[7] << 16) + (packet[8] << 8) + packet[9]; + unsigned delay = delayTime(snac); + if (m_bNoSend) + bSend = false; + else if (!bSend && (delay == 0)) + bSend = true; + RateInfo *r = rateInfo(snac); + if (!r) + bSend = true; + else if (m_bNoSend || r->delayed.size()) + bSend = false; + if (bSend) + { + if (r) + setNewLevel(*r); + OscarSocket::sendPacket(true); + return; + } + OscarSocket::sendPacket(false); + r->delayed.pack(writeBuffer.data(writeBuffer.packetStartPos()), writeBuffer.size() - writeBuffer.packetStartPos()); + writeBuffer.resize(writeBuffer.packetStartPos()); + m_processTimer->stop(); + m_processTimer->start(delay); +} + +QByteArray ICQClient::cryptPassword() +{ + unsigned char xor_table[] = + { + 0xf3, 0x26, 0x81, 0xc4, 0x39, 0x86, 0xdb, 0x92, + 0x71, 0xa3, 0xb9, 0xe6, 0x53, 0x7a, 0x95, 0x7c + }; + QByteArray pswd = getContacts()->fromUnicode(NULL, getPassword()); + char buf[8]; + int len=0; + for (int j = 0; j < 8; j++) + { + char c = pswd[j]; + if (c == 0) + break; + c = (char)(c ^ xor_table[j]); + buf[j] = c; + len++; + } + QByteArray res( buf,len ); + return res; +} +unsigned long ICQClient::getFullStatus() +{ + return fullStatus(m_status); +} + +unsigned long ICQClient::fullStatus(const SIM::IMStatusPtr& status) +{ + unsigned long code = 0; + if(status->id() == "online") + code = ICQ_STATUS_ONLINE; + else if(status->id() == "away") + code = ICQ_STATUS_AWAY; + else if(status->id() == "n/a") + code = ICQ_STATUS_AWAY | ICQ_STATUS_NA; + else if(status->id() == "occupied") + code = ICQ_STATUS_AWAY | ICQ_STATUS_OCCUPIED; + else if(status->id() == "dnd") + code = ICQ_STATUS_AWAY | ICQ_STATUS_DND | ICQ_STATUS_OCCUPIED; + else if(status->id() == "free_for_chat") + code = ICQ_STATUS_FFC; + + if(data.owner.WebAware.toBool()) + code |= ICQ_STATUS_FxWEBxPRESENCE; + if (getHideIP()) + code |= ICQ_STATUS_FxHIDExIP | ICQ_STATUS_FxDIRECTxAUTH; + else if (getDirectMode() == 1) + code |= ICQ_STATUS_FxDIRECTxLISTED; + else if (getDirectMode() == 2) + code |= ICQ_STATUS_FxDIRECTxAUTH; + + if (m_bBirthday) + code |= ICQ_STATUS_FxBIRTHDAY; + if (getInvisible()) + { + code |= ICQ_STATUS_FxPRIVATE | ICQ_STATUS_FxHIDExIP; + code &= ~(ICQ_STATUS_FxDIRECTxLISTED | ICQ_STATUS_FxDIRECTxAUTH); + } + return code; +} + +unsigned long ICQClient::fullStatus(unsigned s) +{ + unsigned long status = 0; + switch (s) + { + case STATUS_ONLINE: + status = ICQ_STATUS_ONLINE; + break; + case STATUS_AWAY: + status = ICQ_STATUS_AWAY; + break; + case STATUS_NA: + status = ICQ_STATUS_NA | ICQ_STATUS_AWAY; + break; + case STATUS_OCCUPIED: + status = ICQ_STATUS_OCCUPIED | ICQ_STATUS_AWAY; + break; + case STATUS_DND: + status = ICQ_STATUS_DND | ICQ_STATUS_OCCUPIED | ICQ_STATUS_AWAY; + break; + case STATUS_FFC: + status = ICQ_STATUS_FFC; + break; + } + if(data.owner.WebAware.toBool()) + status |= ICQ_STATUS_FxWEBxPRESENCE; + if (getHideIP()) + status |= ICQ_STATUS_FxHIDExIP | ICQ_STATUS_FxDIRECTxAUTH; + else if (getDirectMode() == 1) + status |= ICQ_STATUS_FxDIRECTxLISTED; + else if (getDirectMode() == 2) + status |= ICQ_STATUS_FxDIRECTxAUTH; + + if (m_bBirthday) + status |= ICQ_STATUS_FxBIRTHDAY; + if (getInvisible()) + { + status |= ICQ_STATUS_FxPRIVATE | ICQ_STATUS_FxHIDExIP; + status &= ~(ICQ_STATUS_FxDIRECTxLISTED | ICQ_STATUS_FxDIRECTxAUTH); + } + return status; +} + +void ICQClient::interfaceDown(QString ifname) +{ + log(L_DEBUG, "icq: interface down: %s", qPrintable(ifname)); +} + +void ICQClient::interfaceUp(QString ifname) +{ + if(getMediaSense()) + { + log(L_DEBUG, "icq: interface up: %s", qPrintable(ifname)); + if(!m_bconnectionLost) + return; + + // Try to connect + setStatus(STATUS_ONLINE, false); + } +} + +ICQUserData *ICQClient::findContact(unsigned long l, const QString *alias, bool bCreate, Contact *&contact, Group *grp, bool bJoin) +{ + return findContact(QString::number(l), alias, bCreate, contact, grp, bJoin); +} + +ICQUserData *ICQClient::findContact(const QString &screen, const QString *alias, bool bCreate, Contact *&contact, Group *grp, bool bJoin) +{ + if (screen.isEmpty()) + return NULL; + + QString s = screen.toLower(); + + ContactList::ContactIterator it; + ICQUserData *data; + unsigned long uin = screen.toULong(); + + while ((contact = ++it) != NULL) + { + ClientDataIterator it(contact->clientData, this); + while ((data = toICQUserData(++it)) != NULL) + { + if (uin && data->Uin.toULong() != uin || (uin == 0 && s != data->Screen.str())) + continue; + bool bChanged = false; + if (alias) + { + if (!alias->isEmpty()) + { + bChanged = contact->getName() != *alias; + if(bChanged) + contact->setName(*alias); + } + data->Alias.str() = *alias; + } + if (grp && contact->getGroup() != (int)grp->id()) + { + contact->setGroup(grp->id()); + bChanged = true; + } + if (bChanged) + { + EventContact e(contact, EventContact::eChanged); + e.process(); + } + return data; + } + } + if (!bCreate) + return NULL; + if (bJoin) + { + for (unsigned i = 0; i < getContacts()->nClients(); i++) + { + Client *client = getContacts()->getClient(i); + if (client == this || client->protocol() != protocol()) + continue; + ICQClient *c = static_cast(client); + it.reset(); + while ((contact = ++it) != NULL) + { + ClientDataIterator it(contact->clientData, c); + while ((data = toICQUserData(++it)) != NULL) + { + if (uin && data->Uin.toULong() != uin || (uin == 0 && s != data->Screen.str())) + continue; + data = toICQUserData((SIM::clientData*)contact->clientData.createData(this)); // FIXME unsafe type conversion + data->Uin.asULong() = uin; + if (uin == 0) + data->Screen.str() = s; + bool bChanged = false; + if(alias) + { + if(!alias->isEmpty()) + { + bChanged = contact->getName() != *alias; + if(bChanged) + contact->setName(*alias); + } + data->Alias.str() = *alias; + } + if (grp && (int)grp->id() != contact->getGroup()) + { + contact->setGroup(grp->id()); + bChanged = true; + } + if (bChanged) + { + EventContact e(contact, EventContact::eChanged); + e.process(); + updateInfo(contact, data); + } + updateInfo(contact, data); + return data; + } + } + } + if (alias && !alias->isEmpty()) + { + QString name = alias->toLower(); + it.reset(); + while ((contact = ++it) != NULL) + if (contact->getName().toLower() == name){ + ICQUserData *data = toICQUserData((SIM::clientData*) contact->clientData.createData(this)); // FIXME unsafe type conversion + data->Uin.asULong() = uin; + if (uin == 0) + data->Screen.str() = screen; + data->Alias.str() = alias ? *alias : QString::null; + EventContact e(contact, EventContact::eChanged); + e.process(); + m_bJoin = true; + updateInfo(contact, data); + return data; + } + } + } + contact = getContacts()->contact(0, true); + data = toICQUserData((SIM::clientData*) contact->clientData.createData(this)); // FIXME unsafe type conversion + data->Uin.asULong() = uin; + if (uin == 0) + data->Screen.str() = s; + QString name; + if (alias) + name = *alias; + else if (uin) + name = QString::number(uin); + else + name = screen; + if(alias) + data->Alias.str() = *alias; + contact->setName(name); + if (grp) + contact->setGroup(grp->id()); + EventContact e(contact, EventContact::eChanged); + e.process(); + updateInfo(contact, data); + return data; +} + +ICQUserData *ICQClient::findGroup(unsigned id, const QString *alias, Group *&grp) +{ + ContactList::GroupIterator it; + ICQUserData *data; + while ((grp = ++it) != NULL) + { + data = toICQUserData((SIM::clientData*)grp->clientData.getData(this)); // FIXME unsafe type conversion + if (!data || data->IcqID.toULong() != id) + continue; + + if (alias) + data->Alias.str() = *alias; + return data; + } + if (alias == NULL) + return NULL; + it.reset(); + QString name = *alias; + while ((grp = ++it) != NULL) + { + if (grp->getName() == name) + { + data = toICQUserData((SIM::clientData*)grp->clientData.createData(this)); // FIXME unsafe type conversion + data->IcqID.asULong() = id; + data->Alias.str() = *alias; + return data; + } + } + grp = getContacts()->group(0, true); + grp->setName(name); + data = toICQUserData((SIM::clientData*)grp->clientData.createData(this)); // FIXME unsafe type conversion + data->IcqID.asULong() = id; + data->Alias.str() = *alias; + EventGroup e(grp, EventGroup::eChanged); + e.process(); + return data; +} + +void ICQClient::setOffline(ICQUserData *data) +{ + QString name = dataName(data); + for (list::iterator it = m_acceptMsg.begin(); it != m_acceptMsg.end(); ) + { + Message *msg = *it; //will sometimes not work, content: it is broken then: 0xcdcdcdcd, reason seems to be Filetransfer.. however.. + + if(!msg->client().isEmpty() && name == msg->client()) + { + EventMessageDeleted(msg).process(); + delete msg; + m_acceptMsg.erase(it); + it = m_acceptMsg.begin(); + } + ++it; //FIXME: Exception: Client-Operator not incrementable, because variable "it" is broken at this position, anyhow + } + if (data->Direct.object()) + { + delete data->Direct.object(); + data->Direct.clear(); + } + if (data->DirectPluginInfo.object()) + { + delete data->DirectPluginInfo.object(); + data->DirectPluginInfo.clear(); + } + if (data->DirectPluginStatus.object()) + { + delete data->DirectPluginStatus.object(); + data->DirectPluginStatus.clear(); + } + data->bNoDirect.asBool() = false; + data->Status.asULong() = ICQ_STATUS_OFFLINE; + data->Class.asULong() = 0; + data->bTyping.asBool() = false; + data->bBadClient.asBool() = false; + data->bInvisible.asBool() = false; + data->StatusTime.asULong()= QDateTime::currentDateTime().toTime_t(); + data->AutoReply.str() = QString::null; +} + +static void addIcon(QSet *s, const QString &icon, const QString &statusIcon) +{ + if (!s || statusIcon == icon) + return; + s->insert(icon); +} + +void ICQClient::contactInfo(void *_data, unsigned long &curStatus, unsigned &style, QString &statusIcon, QSet *icons) +{ + ICQUserData *data = toICQUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + unsigned status = STATUS_ONLINE; + unsigned client_status = data->Status.toULong(); + if (client_status == ICQ_STATUS_OFFLINE) + status = STATUS_OFFLINE; + else if (client_status & ICQ_STATUS_DND) + status = STATUS_DND; + else if (client_status & ICQ_STATUS_OCCUPIED) + status = STATUS_OCCUPIED; + else if (client_status & ICQ_STATUS_NA) + status = STATUS_NA; + else if (client_status & ICQ_STATUS_AWAY) + status = STATUS_AWAY; + else if (client_status & ICQ_STATUS_FFC) + status = STATUS_FFC; + unsigned iconStatus = status; + QString dicon; + if (data->Uin.toULong()) + if (!(iconStatus == STATUS_ONLINE && client_status & ICQ_STATUS_FxPRIVATE)) + { + const CommandDef *def = ICQProtocol::_statusList(); + for (; !def->text.isEmpty(); def++) + { + if (def->id != iconStatus) + continue; + dicon = def->icon; + break; + } + } + else dicon = "ICQ_invisible"; + else + { + if (status != STATUS_OFFLINE) + { + status = STATUS_ONLINE; + dicon = "AIM_online"; + if (data->Class.toULong() & CLASS_AWAY) + { + status = STATUS_AWAY; + dicon = "AIM_away"; + } + } + else + dicon = "AIM_offline"; + } + if(dicon.isEmpty()) + return; + if (status == STATUS_OCCUPIED) + status = STATUS_DND; + if (status == STATUS_FFC) + status = STATUS_ONLINE; + if (status > curStatus) + { + curStatus = status; + if (!statusIcon.isEmpty() && icons) + icons->insert(statusIcon); + statusIcon = dicon; + } + else if (!statusIcon.isEmpty()) + addIcon(icons, dicon, statusIcon); + else + statusIcon = dicon; + if (status == STATUS_OFFLINE && data->bInvisible.toBool()) + { + status = STATUS_INVISIBLE; + if (status > curStatus) + curStatus = status; + } + if (icons) + { + if ((iconStatus != STATUS_ONLINE && iconStatus != STATUS_OFFLINE && client_status & ICQ_STATUS_FxPRIVATE) || data->bInvisible.toBool()) + addIcon(icons, "ICQ_invisible", statusIcon); + if (data->Status.toULong() & ICQ_STATUS_FxBIRTHDAY) { + QDate today=QDate::currentDate(); + if (today.day()==(int)data->BirthDay.toULong() && today.month()==(int)data->BirthMonth.toULong()) + addIcon(icons, "partytime", statusIcon); + else + addIcon(icons, "birthday", statusIcon); + } + if (data->FollowMe.toULong() == 1) + addIcon(icons, "phone", statusIcon); + if (data->FollowMe.toULong() == 2) + addIcon(icons, "nophone", statusIcon); + if (status != STATUS_OFFLINE) + { + if (data->SharedFiles.toBool()) + addIcon(icons, "sharedfiles", statusIcon); + if (data->ICQPhone.toULong() == 1) + addIcon(icons, "icqphone", statusIcon); + if (data->ICQPhone.toULong() == 2) + addIcon(icons, "icqphonebusy", statusIcon); + } + if (data->bTyping.toBool()) + addIcon(icons, "typing", statusIcon); + DirectClient *dc = dynamic_cast(data->Direct.object()); + if (dc && dc->isSecure()) + addIcon(icons, "encrypted", statusIcon); + } + if (data->InvisibleId.toULong()) + style |= CONTACT_STRIKEOUT; + if (data->VisibleId.toULong()) + style |= CONTACT_ITALIC; + if (data->WaitAuth.toBool()) + style |= CONTACT_UNDERLINE; +} + +void ICQClient::ping() +{ + if (getState() == Connected) + { + bool bBirthday = false; + if (!m_bAIM) + { + int year = data.owner.BirthYear.toULong(); + int month = data.owner.BirthMonth.toULong(); + int day = data.owner.BirthDay.toULong(); + if (day && month && year) + { + QDate tNow = QDate::currentDate(); + QDate tBirthday(tNow.year(), month, day); + // we send it two days before we've birthday + int diff = tNow.daysTo(tBirthday); + if (diff < 0 || diff > 2) + { + tBirthday = tBirthday.addYears(1); + diff = tNow.daysTo(tBirthday); + if(diff >= 0 && diff <=2) + bBirthday = true; + } + else bBirthday = true; + } + } + if (bBirthday != m_bBirthday) + { + m_bBirthday = bBirthday; + setStatus(m_status); + } + else if (getKeepAlive() || m_bHTTP) + { + bool bSend = true; + for (unsigned i = 0; i < m_rates.size(); i++) + { + if (!m_rates[i].delayed.size()) + continue; + bSend = false; + break; + } + if (bSend) + { + flap(ICQ_CHNxPING); + sendPacket(false); + } + } + snacICBM()->processSendQueue(); + checkListRequest(); + checkInfoRequest(); + QTimer::singleShot(PING_TIMEOUT * 1000, this, SLOT(ping())); + } +} + +void ICQClient::setupContact(Contact *contact, void *_data) +{ + ICQUserData *data = toICQUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + QString phones; + if (!data->HomePhone.str().isEmpty()) + { + phones += trimPhone(data->HomePhone.str()); + phones += ",Home Phone,"; + phones += QString::number(PHONE); + } + if (!data->HomeFax.str().isEmpty()) + { + if (phones.length()) + phones += ';'; + phones += trimPhone(data->HomeFax.str()); + phones += ",Home Fax,"; + phones += QString::number(FAX); + } + if (!data->WorkPhone.str().isEmpty()) + { + if (phones.length()) + phones += ';'; + phones += trimPhone(data->WorkPhone.str()); + phones += ",Work Phone,"; + phones += QString::number(PHONE); + } + if (!data->WorkFax.str().isEmpty()) + { + if (phones.length()) + phones += ';'; + phones += trimPhone(data->WorkFax.str()); + phones += ",Work Fax,"; + phones += QString::number(FAX); + } + if (!data->PrivateCellular.str().isEmpty()) + { + if (phones.length()) + phones += ';'; + phones += trimPhone(data->PrivateCellular.str()); + phones += ",Private Cellular,"; + phones += QString::number(CELLULAR); + } + if(data->PhoneBook.str().isEmpty()) + { + if (phones.length()) + phones += ';'; + phones += data->PhoneBook.str(); + } + contact->setPhones(phones, name()); + QString mails; + if (!data->EMail.str().isEmpty()) + { + mails += data->EMail.str().trimmed(); + QString emails = data->EMails.str(); + while (emails.length()) + { + QString mailItem = getToken(emails, ';', false); + QString mail = getToken(mailItem, '/').trimmed(); + if (mail.length()) + { + if (mails.length()) + mails += ';'; + mails += mail; + } + } + } + QString n = name(); + contact->setEMails(mails, n); + QString firstName = data->FirstName.str(); + if (firstName.length()) + contact->setFirstName(firstName, n); + QString lastName = data->LastName.str(); + if (lastName.length()) + contact->setLastName(lastName, n); + if (contact->getName().isEmpty()) + contact->setName(QString::number(data->Uin.toULong())); + QString nick = data->Nick.str(); + if (nick.isEmpty()) + nick = data->Alias.str(); + if (!nick.isEmpty()) + { + QString name = QString::number(data->Uin.toULong()); + if (name == contact->getName()) + contact->setName(nick); + } +} + +QString ICQClient::trimPhone(const QString &from) +{ + QString res; + if (from.isEmpty()) + return res; + res = from; + int idx = res.indexOf("SMS"); + if(idx != -1) + res = res.left(idx); + return res.trimmed(); +} + +QString ICQClient::contactTip(void *_data) +{ + ICQUserData *data = toICQUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + QString res; + QString statusText; + unsigned long status = STATUS_OFFLINE; + unsigned style = 0; + QString statusIcon; + contactInfo(data, status, style, statusIcon); + if (status == STATUS_INVISIBLE) + { + res += ""; + res += i18n("Possibly invisible"); + } + else + { + res += ""; + if (statusIcon == "ICQ_invisible") + { + res += ' '; + res += i18n("Invisible"); + } + else if (data->Uin.toULong()) + for (const CommandDef *cmd = ICQProtocol::_statusList(); !cmd->text.isEmpty(); cmd++) + { + if (cmd->icon == statusIcon) + { + res += ' '; + statusText += i18n(cmd->text); + res += statusText; + break; + } + } + else + { + if (status == STATUS_OFFLINE) + res += i18n("Offline"); + else if (status == STATUS_ONLINE) + res += i18n("Online"); + else + res += i18n("Away"); + } + } + res += "
"; + if (data->Uin.toULong()) + { + res += "UIN: "; + res += QString::number(data->Uin.toULong()); + res += ""; + }else{ + res += ""; + res += data->Screen.str(); + res += ""; + } + if (data->WarningLevel.toULong()) + { + res += "
"; + res += i18n("Warning level"); + res += ": "; + res += QString::number(warnLevel(data->WarningLevel.toULong())); + res += "%
"; + } + if (data->Status.toULong() == ICQ_STATUS_OFFLINE) + { + if (data->StatusTime.toULong()){ + res += "
"; + res += i18n("Last online"); + res += ": "; + res += formatDateTime(data->StatusTime.toULong()); + } + } + else + { + if (data->OnlineTime.toULong()) + { + res += "
"; + res += i18n("Online"); + res += ": "; + res += formatDateTime(data->OnlineTime.toULong()); + } + if (data->Status.toULong() & (ICQ_STATUS_AWAY | ICQ_STATUS_NA)){ + res += "
"; + res += statusText; + res += ": "; + res += formatDateTime(data->StatusTime.toULong()); + } + } + if (data->IP.ip()) + { + res += "
"; + res += formatAddr(data->IP, data->Port.toULong()); + } + if ((data->RealIP.ip()) && ((data->IP.ip() == NULL) || (get_ip(data->IP) != get_ip(data->RealIP)))) + { + res += "
"; + res += formatAddr(data->RealIP, data->Port.toULong()); + } + QString client_name = clientName(data); + if (client_name.length()) + { + res += "
"; + res += quoteString(client_name); + } + QString pictureFileName = pictureFile(data); + QImage img(pictureFileName); + if (!img.isNull()) + { + int w = img.width(); + int h = img.height(); + if (h > w) + { + if (h > 60) + { + w = w * 60 / h; + h = 60; + } + } + else if (w > 60) + { + h = h * 60 / w; + w = 60; + } + res += "
"; + } + if (!data->AutoReply.str().isEmpty()) + { + res += "

"; + res += quoteString(data->AutoReply.str()); + } + if (!(data->Status.toULong() & ICQ_STATUS_FxBIRTHDAY)) + return res; + + QDate today=QDate::currentDate(); + if (today.day()==(int)data->BirthDay.toULong() && today.month()==(int)data->BirthMonth.toULong()) + { + //Today is birthday! + //addIcon(icons, "partytime", statusIcon); + res += "

"+i18n("has birthday today!")+"
"; + if (!m_bBirthdayInfoDisplayed) + { + int ret=QMessageBox::question(0, + i18n("Birthday Notification"), + QString("%1 (%2 %3) %4\n\n%5").arg(data->Alias.str(), data->FirstName.str(), data->LastName.str(), i18n("has birthday today!"), i18n("Send GreetingCard?")), + QMessageBox::Yes | QMessageBox::No); + m_bBirthdayInfoDisplayed=true; + //Todo: navigate to birthday greetingcard-webpage ;) + EventGoURL e(QString("http://www.google.com/search?q=ecards")); + if (ret==QMessageBox::Yes) e.process(); + } + + } + else + { + //Birthday one or two more days. + //addIcon(icons, "birthday", statusIcon); + int nextbirthdayyear=today.year(); + if ((int)data->BirthMonth.toULong()==1 && (int)data->BirthDay.toULong()<2) //special case + nextbirthdayyear=today.year()+1; + + QDate birthday(nextbirthdayyear,(int)data->BirthMonth.toULong(),(int)data->BirthDay.toULong()); + int remainingdays=today.daysTo(birthday); + res += QString("

"+i18n("has birthday in %1 days.").arg(QString::number(remainingdays))+"
"); + } + return res; +} + +unsigned long ICQClient::warnLevel(unsigned long level) +{ + level = ((level + 5) / 10); + if (level > 100) + level = 100; + return level; +} + +bool ICQClient::hasCap(const ICQUserData *data, cap_id_t n) +{ + unsigned long val = n > 31 ? data->Caps2.toULong() : data->Caps.toULong(); + int pos = (int)n % 32; + return (val & (1 << pos)) != 0; +} + +void ICQClient::setCap(ICQUserData *data, cap_id_t n) +{ + unsigned long &val = n > 31 ? data->Caps2.asULong() : data->Caps.asULong(); + int pos = (int)n % 32; + val |= (1 << pos); +} + +static QString verString(unsigned ver) +{ + QString res; + if (ver == 0) + return res; + unsigned char v[4]; + v[0] = (unsigned char)((ver >> 24) & 0xFF); + v[1] = (unsigned char)((ver >> 16) & 0xFF); + v[2] = (unsigned char)((ver >> 8) & 0xFF); + v[3] = (unsigned char)((ver >> 0) & 0xFF); + if ((v[0] & 0x80) || (v[1] & 0x80) || (v[2] & 0x80) || (v[3] & 0x80)) + return res; + + res.sprintf(" %u.%u", v[0], v[1]); + if (v[2] || v[3]) + { + QString s; + s.sprintf(".%u", v[2]); + res += s; + } + if (v[3]) + { + QString s; + s.sprintf(".%u", v[3]); + res += s; + } + return res; +} + +QString ICQClient::clientName(ICQUserData *data) +{ + QString res; + if (data->Version.toULong()) + res.sprintf("v%lu ", data->Version.toULong()); + + if (data->InfoUpdateTime.toULong() == 0xFFFFFFFFL) + { + if (data->PluginStatusTime.toULong() == 0xFFFFFFFFL && data->PluginInfoTime.toULong() == 0xFFFFFFFFL) + { + res += "GAIM"; + return res; + } + res += "MIRANDA"; + res += hasCap(data, CAP_ICQJP) ? verString(data->Build.toULong()) : verString(data->PluginInfoTime.toULong() & 0xFFFFFF); + if (!(data->PluginInfoTime.toULong() & 0x80000000)) + return res; + + res += " alpha"; + return res; + } + if (data->InfoUpdateTime.toULong() == 0xFFFFFF8FL) + { + res += "StrICQ"; + res += verString(data->PluginInfoTime.toULong() & 0xFFFFFF); + return res; + } + else if (data->InfoUpdateTime.toULong() == 0xFFFFFF42L) + { + res += "mICQ"; + return res; + } + else if (data->InfoUpdateTime.toULong() == 0xFFFFFFBEL) + { + res += "alicq"; + res += verString(data->PluginInfoTime.toULong() & 0xFFFFFF); + return res; + } + else if (data->InfoUpdateTime.toULong() == 0xFFFFFF7FL) + { + res += "&RQ"; + res += verString(data->PluginInfoTime.toULong() & 0xFFFFFF); + return res; + } + else if (data->InfoUpdateTime.toULong() == 0xFFFFFFABL) + { + res += "YSM"; + res += verString(data->PluginInfoTime.toULong() & 0xFFFF); + return res; + } + else if (data->InfoUpdateTime.toULong() == 0x04031980L) + { + QString r; + r.sprintf("vICQ 0.43.%lu.%lu", data->PluginInfoTime.toULong() & 0xffff, data->PluginInfoTime.toULong() & (0x7fff0000) >> 16); + res += r; + return res; + } + else if (data->InfoUpdateTime.toULong() == 0x3AA773EEL && data->PluginStatusTime.toULong() == 0x3AA66380L && data->PluginInfoTime.toULong() == 0x3A877A42L) + { + res += "libicq2000"; + return res; + } + + if (hasCap(data, CAP_MIRANDA)) + { + QString r; + unsigned ver1 = (data->Build.toULong() >> 24) & 0x7F; + unsigned ver2 = (data->Build.toULong() >> 16) & 0xFF; + unsigned ver3 = (data->Build.toULong() >> 8) & 0xFF; + unsigned ver4 = (data->Build.toULong() >> 0) & 0xFF; + r.sprintf("Miranda %u.%u.%u.%u", ver1, ver2, ver3, ver4); + // highest bit set -> alpha version + if(((data->Build.toULong() >> 24) & 0x80) != 0x80) + return res + r; + + r += " (alpha)"; + return res + r; + } + if (hasCap(data, CAP_QIP)) + { + res += "QIP 2005a"; + return res; + } + if (hasCap(data, CAP_JIMM)) + { + QString r; + unsigned maj = (data->Build.toULong() >> 24) & 0xFF; + unsigned min = (data->Build.toULong() >> 16) & 0xFF; + unsigned rev = (data->Build.toULong() >> 0) & 0xFFFF; + if(rev) + r.sprintf("Jimm %d.%d.%d", maj, min, rev); + else + r.sprintf("Jimm %d.%d", maj, min); + return res + r; + } + if (hasCap(data, CAP_ICQ51)) + { + res += "ICQ 5.1"; + return res; + } + if (hasCap(data, CAP_ICQ5_1) && hasCap(data, CAP_ICQ5_3) && hasCap(data, CAP_ICQ5_4)) + { + res += "ICQ 5.0"; + return res; + } + if (hasCap(data, CAP_ICQ5_1)) + { + log( L_DEBUG, "CAP_ICQ5_1 without all others" ); + } + if (hasCap(data, CAP_ICQ5_3)) + { + log( L_DEBUG, "CAP_ICQ5_3 without all others" ); + } + if (hasCap(data, CAP_ICQ5_4)) + { + log( L_DEBUG, "CAP_ICQ5_4 without all others" ); + } + if (hasCap(data, CAP_TRIL_CRYPT) || hasCap(data, CAP_TRILLIAN)) + { + res += "Trillian"; + return res; + } + + if (hasCap(data, CAP_SIMOLD)) + { + QString r; + unsigned hiVersion = (data->Build.toULong() >> 6) - 1; + unsigned loVersion = data->Build.toULong() & 0x1F; + r.sprintf("SIM %u.%u", hiVersion, loVersion); + return res + r; + } + + if (hasCap(data, CAP_SIM)) + { + QString r; + unsigned ver1 = (data->Build.toULong() >> 24) & 0xFF; + unsigned ver2 = (data->Build.toULong() >> 16) & 0xFF; + unsigned ver3 = (data->Build.toULong() >> 8) & 0xFF; + unsigned ver4 = data->Build.toULong() & 0x0F; + if (ver4) + r.sprintf("SIM %u.%u.%u.%u", ver1, ver2, ver3, ver4); + else if (ver3) + r.sprintf("SIM %u.%u.%u", ver1, ver2, ver3); + else + r.sprintf("SIM %u.%u", ver1, ver2); + res += r; + if (data->Build.toULong() & 0x80) + res += "/win32"; + + if (data->Build.toULong() & 0x40) + res += "/MacOS X"; + return res; + } + + if (hasCap(data, CAP_LICQ)) + { + QString r; + unsigned ver1 = (data->Build.toULong() >> 24) & 0xFF; + unsigned ver2 = (data->Build.toULong() >> 16) & 0xFF; + unsigned ver3 = (data->Build.toULong() >> 8) & 0xFF; + ver2 %=100; // see licq source + r.sprintf("Licq %u.%u.%u", ver1, ver2, ver3); + res += r; + if ((data->Build.toULong() & 0xFF) == 1) + res += "/SSL"; + return res; + } + if (hasCap(data, CAP_KOPETE)) + { + // last 4 bytes determine version + // NOTE change with each Kopete Release! + // first number, major version + // second number, minor version + // third number, point version 100+ + // fourth number, point version 0-99 + QString r; + unsigned ver1 = (data->Build.toULong() >> 24) & 0xFF; // major + unsigned ver2 = (data->Build.toULong() >> 16) & 0xFF; // minor + unsigned ver3 = ((data->Build.toULong() >> 8) & 0xFF) * 100; + ver3 += (data->Build.toULong() >> 0) & 0xFF; + r.sprintf("Kopete %u.%u.%u", ver1, ver2, ver3); + res += r; + return res; + } + if (hasCap(data, CAP_XTRAZ)) + { + res += "ICQ 4.0 Lite"; + return res; + } + if (hasCap(data, CAP_MACICQ)) + { + res += "ICQ for Mac"; + return res; + } + // gaim 2.0 + if (hasCap(data, CAP_AIM_SENDFILE) && + hasCap(data, CAP_AIM_IMIMAGE) && + hasCap(data, CAP_AIM_BUDDYCON) && + hasCap(data, CAP_UTF) && + hasCap(data, CAP_AIM_CHAT)) + { + res += "gaim 2.0"; + return res; + } + if (hasCap(data, CAP_AIM_CHAT)) + { + res += "AIM"; + return res; + } + if ((data->InfoUpdateTime.toULong() & 0xFF7F0000L) == 0x7D000000L) + { + QString r; + unsigned ver = data->InfoUpdateTime.toULong() & 0xFFFF; + if (ver % 10) + r.sprintf("Licq %u.%u.%u", ver / 1000, (ver / 10) % 100, ver % 10); + else + r.sprintf("Licq %u.%u", ver / 1000, (ver / 10) % 100); + res += r; + if (data->InfoUpdateTime.toULong() & 0x00800000L) + res += "/SSL"; + return res; + } + + + if (hasCap(data, CAP_TYPING)) + { + if (data->Version.toULong() == 10) + res += "ICQ 2003b"; + else if (data->Version.toULong() == 9) + res += "ICQ Lite"; + else + res += "ICQ2go"; + return res; + } + if (data->InfoUpdateTime.toULong() && + (data->InfoUpdateTime.toULong() == data->PluginStatusTime.toULong()) && + (data->PluginStatusTime.toULong() == data->PluginInfoTime.toULong()) && + (data->Caps.toULong() == 0) && (data->Caps2.toULong() == 0)){ + res += "vICQ"; + return res; + } + if (hasCap(data, CAP_AIM_BUDDYCON)) + { + res += "gaim"; + return res; + } + if ((hasCap(data, CAP_STR_2001) || hasCap(data, CAP_SRV_RELAY)) && hasCap(data, CAP_IS_2001)) + { + res += "ICQ 2001"; + return res; + } + if ((hasCap(data, CAP_STR_2001) || hasCap(data, CAP_SRV_RELAY)) && hasCap(data, CAP_IS_2002)) + { + res += "ICQ 2002"; + return res; + } + if (hasCap(data, CAP_RTF) && hasCap(data, CAP_UTF) && + hasCap(data, CAP_SRV_RELAY) && hasCap(data, CAP_DIRECT)) + { + res += "ICQ 2003a"; + return res; + } + if (hasCap(data, CAP_SRV_RELAY) && hasCap(data, CAP_DIRECT)) + { + res += "ICQ 2001b"; + return res; + } + if ((data->Version.toULong() == 7) && hasCap(data, CAP_RTF)) + { + res += "GnomeICU"; + return res; + } + // ICQ2go doesn't use CAP_TYPING anymore + if ((data->Version.toULong() == 7) && hasCap(data, CAP_UTF)) + { + res += "ICQ2go"; + return res; + } + return res; +} + +const unsigned MAIN_INFO = 1; +const unsigned HOME_INFO = 2; +const unsigned WORK_INFO = 3; +const unsigned MORE_INFO = 4; +const unsigned ABOUT_INFO = 5; +const unsigned INTERESTS_INFO = 6; +const unsigned PAST_INFO = 7; +const unsigned PICTURE_INFO = 8; +const unsigned NETWORK = 9; +const unsigned SECURITY = 10; + +static CommandDef icqWnd[] = + { + CommandDef ( + MAIN_INFO, + " ", + "ICQ_online", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + HOME_INFO, + I18N_NOOP("Home info"), + "home", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + WORK_INFO, + I18N_NOOP("Work info"), + "work", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + MORE_INFO, + I18N_NOOP("More info"), + "more", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + ABOUT_INFO, + I18N_NOOP("About info"), + "info", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + INTERESTS_INFO, + I18N_NOOP("Interests"), + "interest", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + PAST_INFO, + I18N_NOOP("Group/Past"), + "past", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + PICTURE_INFO, + I18N_NOOP("Picture"), + "pict", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef (), + }; + +static CommandDef aimWnd[] = + { + CommandDef ( + MAIN_INFO, + " ", + "AIM_online", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + ABOUT_INFO, + I18N_NOOP("About info"), + "info", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef (), + }; + +static CommandDef icqConfigWnd[] = + { + CommandDef ( + MAIN_INFO, + " ", + "ICQ_online", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + HOME_INFO, + I18N_NOOP("Home info"), + "home", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + WORK_INFO, + I18N_NOOP("Work info"), + "work", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + MORE_INFO, + I18N_NOOP("More info"), + "more", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + ABOUT_INFO, + I18N_NOOP("About info"), + "info", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + INTERESTS_INFO, + I18N_NOOP("Interests"), + "interest", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + PAST_INFO, + I18N_NOOP("Group/Past"), + "past", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + PICTURE_INFO, + I18N_NOOP("Picture"), + "pict", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + NETWORK, + I18N_NOOP("Network"), + "network", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + SECURITY, + I18N_NOOP("Security"), + "security", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef (), + }; + +static CommandDef aimConfigWnd[] = + { + CommandDef ( + MAIN_INFO, + " ", + "AIM_online", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + ABOUT_INFO, + I18N_NOOP("About info"), + "info", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + NETWORK, + I18N_NOOP("Network"), + "network", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef (), + }; + +CommandDef *ICQClient::infoWindows(Contact*, void *_data) +{ + ICQUserData *data = toICQUserData((SIM::clientData*) _data); // FIXME unsafe type conversion + CommandDef *def = data->Uin.toULong() ? icqWnd : aimWnd; + QString name = i18n(protocol()->description()->text); + name += ' '; + if (data->Uin.toULong()) + name += QString::number(data->Uin.toULong()); + else + name += data->Screen.str(); + def->text_wrk = name; + return def; +} + +CommandDef *ICQClient::configWindows() +{ + CommandDef *def = icqConfigWnd; + QString name = i18n(protocol()->description()->text); + name += ' '; + if (m_bAIM) + { + name += data.owner.Screen.str(); + def = aimConfigWnd; + } + else name += QString::number(data.owner.Uin.toULong()); + def->text_wrk = name; + return def; +} + +QWidget *ICQClient::infoWindow(QWidget *parent, Contact *contact, void *_data, unsigned id) +{ + ICQUserData *data = toICQUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + switch (id){ + case MAIN_INFO: + if (data->Uin.toULong()) + return new ICQInfo(parent, data, contact->id(), this); + return new AIMInfo(parent, data, contact->id(), this); + case HOME_INFO: + return new HomeInfo(parent, data, contact->id(), this); + case WORK_INFO: + return new WorkInfo(parent, data, contact->id(), this); + case MORE_INFO: + return new MoreInfo(parent, data, contact->id(), this); + case ABOUT_INFO: + return new AboutInfo(parent, data, contact->id(), this); + case INTERESTS_INFO: + return new InterestsInfo(parent, data, contact->id(), this); + case PAST_INFO: + return new PastInfo(parent, data, contact->id(), this); + case PICTURE_INFO: + return new ICQPicture(parent, data, this); + } + return NULL; +} + +QWidget *ICQClient::configWindow(QWidget *parent, unsigned id) +{ + switch (id){ + case MAIN_INFO: + if (m_bAIM) + return new AIMInfo(parent, NULL, 0, this); + return new ICQInfo(parent, NULL, 0, this); + case HOME_INFO: + return new HomeInfo(parent, NULL, 0, this); + case WORK_INFO: + return new WorkInfo(parent, NULL, 0, this); + case MORE_INFO: + return new MoreInfo(parent, NULL, 0, this); + case ABOUT_INFO: + return new AboutInfo(parent, NULL, 0, this); + case INTERESTS_INFO: + return new InterestsInfo(parent, NULL, 0, this); + case PAST_INFO: + return new PastInfo(parent, NULL, 0, this); + case PICTURE_INFO: + return new ICQPicture(parent, NULL, this); + case NETWORK: + if (m_bAIM) + return new AIMConfig(parent, this, false); + return new ICQConfig(parent, this, false); + case SECURITY: + return new ICQSecure(parent, this); + } + return NULL; +} + +QWidget *ICQClient::searchWindow(QWidget *parent) +{ + if (getState() != Connected) + return NULL; + return new ICQSearch(this, parent); +} + +void ICQClient::updateInfo(Contact *contact, void *_data) +{ + ICQUserData *data = toICQUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + if (getState() != Connected) + { + Client::updateInfo(contact, _data); + return; + } + if (data == NULL) + data = &this->data.owner; + if (data->Uin.toULong()) + { + addFullInfoRequest(data->Uin.toULong()); + addPluginInfoRequest(data->Uin.toULong(), PLUGIN_QUERYxINFO); + addPluginInfoRequest(data->Uin.toULong(), PLUGIN_QUERYxSTATUS); + addPluginInfoRequest(data->Uin.toULong(), PLUGIN_AR); + } + else + fetchProfile(data); + requestBuddy(data); +} + +void ICQClient::fetchAwayMessage(ICQUserData *data) +{ + addPluginInfoRequest(data->Uin.toULong(), PLUGIN_AR); +} + +bool ICQClient::processEvent(Event *e) +{ + TCPClient::processEvent(e); + switch (e->type()) { + case eEventAddContact: { + EventAddContact *ec = static_cast(e); + EventAddContact::AddContact *ac = ec->addContact(); + if (protocol()->description()->text == ac->proto) + { + Group *grp = getContacts()->group(ac->group); + Contact *contact; + QString tmp = ac->nick; + findContact(ac->addr, &tmp, true, contact, grp); + ec->setContact(contact); + return true; + } + break; + } + case eEventDeleteContact: { + EventDeleteContact *ec = static_cast(e); + QString addr = ec->alias(); + ContactList::ContactIterator it; + Contact *contact; + while ((contact = ++it) != NULL) + { + ICQUserData *data; + ClientDataIterator itc(contact->clientData, this); + while ((data = toICQUserData(++itc)) != NULL) + { + if (data->Screen.str() != addr) + continue; + contact->clientData.freeData(data); + ClientDataIterator itc(contact->clientData); + if (++itc == NULL) + delete contact; + return true; + } + } + break; + } + case eEventGetContactIP: { + EventGetContactIP *ei = static_cast(e); + Contact *contact = ei->contact(); + ICQUserData *data; + ClientDataIterator it(contact->clientData, this); + while ((data = toICQUserData(++it)) != NULL) + { + if (data->RealIP.ip()) + { + ei->setIP(data->RealIP.ip()); + return true; + } + if (data->IP.ip()) + { + ei->setIP(data->IP.ip()); + return true; + } + } + break; + } + case eEventMessageAccept: { + EventMessageAccept *ema = static_cast(e); + for (list::iterator it = m_acceptMsg.begin(); it != m_acceptMsg.end(); ++it){ + if ((*it)->id() == ema->msg()->id()){ + Message *msg = *it; + m_acceptMsg.erase(it); + snacICBM()->accept(msg, ema->dir(), ema->mode()); + return msg; + } + } + break; + } + case eEventMessageDecline: { + EventMessageDecline *emd = static_cast(e); + for (list::iterator it = m_acceptMsg.begin(); it != m_acceptMsg.end(); ++it){ + if ((*it)->id() == emd->msg()->id()) + { + Message *msg = *it; + m_acceptMsg.erase(it); + snacICBM()->decline(msg, emd->reason()); + return msg; + } + } + break; + } + case eEventMessageRetry: { + EventMessageRetry *emr = static_cast(e); + EventMessageRetry::MsgSend *m = emr->msgRetry(); + QStringList btns; + if (m->msg->getRetryCode() == static_cast(protocol()->plugin())->RetrySendOccupied){ + btns.append(i18n("Send &urgent")); + }else if (m->msg->getRetryCode() != static_cast(protocol()->plugin())->RetrySendDND){ + return false; + } + btns.append(i18n("Send to &list")); + btns.append(i18n("&Cancel")); + QString err = i18n(m->msg->getError()); + Command cmd; + cmd->id = CmdSend; + cmd->param = m->edit; + EventCommandWidget eWidget(cmd); + eWidget.process(); + QWidget *msgWidget = eWidget.widget(); + if (msgWidget == NULL) + msgWidget = m->edit; + BalloonMsg *msg = new BalloonMsg(m, quoteString(err), btns, msgWidget, NULL, false); + connect(msg, SIGNAL(action(int, void*)), this, SLOT(retry(int, void*))); + msg->show(); + return true; + } + case eEventTemplateExpanded: { + EventTemplate *et = static_cast(e); + EventTemplate::TemplateExpand *t = et->templateExpand(); + list::iterator it; + for (it = arRequests.begin(); it != arRequests.end(); ++it) + if (&(*it) == t->param) + break; + if (it == arRequests.end()) + return false; + if (m_bAIM){ + if ((getState() == Connected) && (m_status == STATUS_AWAY)){ + if (it->bDirect){ + setAwayMessage(t->tmpl); + }else{ + sendCapability(t->tmpl); + m_snacICBM->sendICMB(1, 11); + m_snacICBM->sendICMB(2, 3); + m_snacICBM->sendICMB(4, 3); + snacICBM()->processSendQueue(); + fetchProfiles(); + } + } + return true; + } + ar_request ar = (*it); + if (ar.bDirect){ + Contact *contact; + ICQUserData *data = findContact(ar.screen, NULL, false, contact); + DirectClient *dc = dynamic_cast(data ? data->Direct.object() : 0); + if (dc){ + QByteArray answer; + if (data->Version.toULong() >= 10){ + answer = t->tmpl.toUtf8(); + }else{ + answer = getContacts()->fromUnicode(contact, t->tmpl); + } + dc->sendAck((unsigned short)(ar.id.id_l), ar.type, ar.flags, answer); + } + }else{ + ICQBuffer copy; + snacICBM()->sendAutoReply(ar.screen, ar.id, plugins[PLUGIN_NULL], + ar.id1, ar.id2, ar.type, (char)(ar.ack), 0, t->tmpl, 0, copy); + } + arRequests.erase(it); + return true; + } + case eEventContact: { + EventContact *ec = static_cast(e); + Contact *contact = ec->contact(); + switch(ec->action()) { + case EventContact::eDeleted: { + ICQUserData *data; + ClientDataIterator it(contact->clientData, this); + while ((data = toICQUserData(++it)) != NULL){ + if (data->IcqID.toULong() == 0) + continue; + list::iterator it; + for (it = listRequests.begin(); it != listRequests.end(); it++){ + if (it->type != LIST_USER_CHANGED) + continue; + if (it->screen == screen(data)) + break; + } + if (it != listRequests.end()) + listRequests.erase(it); + ListRequest lr; + lr.type = LIST_USER_DELETED; + lr.screen = screen(data); + lr.icq_id = (unsigned short)(data->IcqID.toULong()); + lr.grp_id = (unsigned short)(data->GrpId.toULong()); + lr.visible_id = (unsigned short)(data->ContactVisibleId.toULong()); + lr.invisible_id = (unsigned short)(data->ContactInvisibleId.toULong()); + lr.ignore_id = (unsigned short)(data->IgnoreId.toULong()); + listRequests.push_back(lr); + snacICBM()->processSendQueue(); + } + //m_snacBuddy->removeBuddy(contact); + break; + } + case EventContact::eChanged: { + if (getState() == Connected){ + if (!m_bAIM) + m_snacBuddy->addBuddy(contact); + if (contact == getContacts()->owner()){ + QDateTime now(QDateTime::currentDateTime()); + if (getContacts()->owner()->getPhones() != data.owner.PhoneBook.str()){ + data.owner.PhoneBook.str() = getContacts()->owner()->getPhones(); + data.owner.PluginInfoTime.asULong() = now.toTime_t(); + snacService()->sendPluginInfoUpdate(PLUGIN_PHONEBOOK); + } + /* + if (getPicture() != data.owner.Picture.str()){ + data.owner.Picture.str() = getPicture(); + data.owner.PluginInfoTime.asULong() = now; + snacService()->sendPluginInfoUpdate(PLUGIN_PICTURE); + } + */ + if (getContacts()->owner()->getPhoneStatus() != (int)data.owner.FollowMe.toULong()){ + data.owner.FollowMe.asULong() = getContacts()->owner()->getPhoneStatus(); + data.owner.PluginStatusTime.asULong() = now.toTime_t(); + snacService()->sendPluginStatusUpdate(PLUGIN_FOLLOWME, data.owner.FollowMe.toULong()); + } + return false; + } + ICQUserData *data; + ClientDataIterator it(contact->clientData, this); + while ((data = toICQUserData(++it)) != NULL){ + if (data->Uin.toULong() || data->ProfileFetch.toBool()) + continue; + fetchProfile(data); + } + } + addContactRequest(contact); + break; + } + default: + break; + } + break; + } + case eEventGroup: { + EventGroup *ev = static_cast(e); + Group *group = ev->group(); + if(!group->id()) + return false; + switch(ev->action()) { + case EventGroup::eChanged: + addGroupRequest(group); + break; + case EventGroup::eDeleted: { + ICQUserData *data = toICQUserData((SIM::clientData*)group->clientData.getData(this)); + if (data){ + ListRequest lr; + lr.type = LIST_GROUP_DELETED; + lr.icq_id = (unsigned short)(data->IcqID.toULong()); + listRequests.push_back(lr); + snacICBM()->processSendQueue(); + } + break; + } + case EventGroup::eAdded: + return false; + } + break; + } + case eEventMessageCancel: { + EventMessage *em = static_cast(e); + Message *msg = em->msg(); + return snacICBM()->cancelMessage(msg); + break; + } + case eEventCheckCommandState: { + EventCheckCommandState *ecs = static_cast(e); + CommandDef *cmd = ecs->cmd(); + if (cmd->id == CmdPhones){ + if (!m_bAIM) + return true; + return false; + } + if(cmd->id == CmdFetchAway) { + Contact *contact = getContacts()->contact((unsigned long)(cmd->param)); + if (!contact) + return false; + ClientDataIterator it(contact->clientData, this); + ICQUserData *data; + while ((data = toICQUserData(++it)) != NULL){ + unsigned long status = STATUS_OFFLINE; + unsigned style = 0; + QString statusIcon; + contactInfo(data, status, style, statusIcon); + if(status != STATUS_ONLINE && status != STATUS_OFFLINE) { + cmd->flags &= ~BTN_HIDE; + return true; + } + } + return false; + } + if ((cmd->bar_id == ToolBarContainer) || (cmd->bar_id == ToolBarHistory)){ + if (cmd->id == CmdChangeEncoding) + { + Contact *contact = getContacts()->contact((unsigned long)(cmd->param)); + if (contact == NULL) + { + cmd->flags |= BTN_HIDE; + return true; + } + for (unsigned i = 0; i < getContacts()->nClients(); i++) + { + Client *client = getContacts()->getClient(i); + if (client == this) + { + cmd->flags |= BTN_HIDE; + break; + } + if (client->protocol() == protocol()) + break; + } + ClientDataIterator it(contact->clientData, this); + if ((++it) != NULL){ + cmd->flags &= ~BTN_HIDE; + return true; + } + return false; + } + } + if (cmd->menu_id == MenuContactGroup){ + if (cmd->id == CmdVisibleList) + { + Contact *contact = getContacts()->contact((unsigned long)(cmd->param)); + if (contact == NULL) + return false; + for (unsigned i = 0; i < getContacts()->nClients(); i++) + { + Client *client = getContacts()->getClient(i); + if (client == this) + { + cmd->flags &= ~COMMAND_CHECKED; + break; + } + if (client->protocol() != protocol()) + continue; + + break; + } + ICQUserData *data; + bool bOK = false; + ClientDataIterator it(contact->clientData, this); + while ((data = toICQUserData(++it)) != NULL) + { + bOK = true; + if (data->VisibleId.toULong()) + cmd->flags |= COMMAND_CHECKED; + } + return bOK; + } + if (cmd->id == CmdInvisibleList){ + Contact *contact = getContacts()->contact((unsigned long)(cmd->param)); + if (contact == NULL) + return false; + for (unsigned i = 0; i < getContacts()->nClients(); i++) + { + Client *client = getContacts()->getClient(i); + if (client == this) + { + cmd->flags &= ~COMMAND_CHECKED; + break; + } + if (client->protocol() == protocol()) + break; + } + ICQUserData *data; + bool bOK = false; + ClientDataIterator it(contact->clientData, this); + while ((data = toICQUserData(++it)) != NULL) + { + bOK = true; + if (data->InvisibleId.toULong()) + cmd->flags |= COMMAND_CHECKED; + } + return (void*)bOK; + } + } + break; + } + case eEventCommandExec: { + EventCommandExec *ece = static_cast(e); + CommandDef *cmd = ece->cmd(); + if(cmd->id == CmdFetchAway) + { + Contact *contact = getContacts()->contact((unsigned long)(cmd->param)); + ClientDataIterator it(contact->clientData, this); + ICQUserData *data; + while ((data = toICQUserData(++it)) != NULL) + { + unsigned long status = STATUS_OFFLINE; + unsigned style = 0; + QString statusIcon; + contactInfo(data, status, style, statusIcon); + if(status != STATUS_ONLINE && status != STATUS_OFFLINE) + fetchAwayMessage(data); + } + cmd->flags &= ~COMMAND_CHECKED; + return false; + } + if (cmd->menu_id == MenuContactGroup){ + if (cmd->id == CmdVisibleList){ + Contact *contact = getContacts()->contact((unsigned long)(cmd->param)); + if (contact == NULL) + return false; + SIM::clientData *data; + ICQUserData * icq_user_data; + ClientDataIterator it(contact->clientData); + while ((data = ++it) != NULL) + { + if (data->Sign.asULong() == ICQ_SIGN) + { // Only ICQ contacts can be added to Visible list + icq_user_data=toICQUserData(data); + icq_user_data->VisibleId.asULong() = (cmd->flags & COMMAND_CHECKED) ? getListId() : 0; + EventContact eContact(contact, EventContact::eChanged); + eContact.process(); + } + } + return true; + } + if (cmd->id == CmdInvisibleList){ + Contact *contact = getContacts()->contact((unsigned long)(cmd->param)); + if (contact == NULL) + return false; + SIM::clientData *data; + ICQUserData * icq_user_data; + ClientDataIterator it(contact->clientData); + while ((data = ++it) != NULL) + { + if (data->Sign.asULong() == ICQ_SIGN) + { // Only ICQ contacts can be added to Invisible list + icq_user_data=toICQUserData(data); + icq_user_data->InvisibleId.asULong() = (cmd->flags & COMMAND_CHECKED) ? getListId() : 0; + EventContact eContact(contact, EventContact::eChanged); + eContact.process(); + } + } + return true; + } + } + break; + } + case eEventGoURL: { + EventGoURL *u = static_cast(e); + QString url = u->url(); + QString proto; + int n = url.indexOf(':'); + if (n < 0) + return false; + proto = url.left(n); + if ((proto != "icq") && (proto != "aim")) + return false; + url = url.mid(proto.length() + 1); + while (url.startsWith("/")) + url = url.mid(1); + QString s = unquoteString(url); + QString screen = getToken(s, ','); + if (!screen.isEmpty()) + { + Contact *contact; + findContact(screen, &s, true, contact); + Command cmd; + cmd->id = MessageGeneric; + cmd->menu_id = MenuMessage; + cmd->param = (void*)(contact->id()); + EventCommandExec(cmd).process(); + return true; + } + break; + } + case eEventInterfaceDown: + { + if(getMediaSense()) + { + EventInterfaceDown* ev = static_cast(e); + if (socket() != NULL && ev->getFd() == socket()->socket()->getFd()) + { + setState(Error, "Interface down"); + setStatus(STATUS_OFFLINE, false); + m_bconnectionLost = true; + } + } + break; + } + case eEventOpenMessage: { + if (getState() != Connected) + return false; + EventMessage *em = static_cast(e); + Message *msg = em->msg(); + if ((msg->type() != MessageOpenSecure) && + (msg->type() != MessageCloseSecure) && + (msg->type() != MessageWarning)) + return false; + QString client = msg->client(); + Contact *contact = getContacts()->contact(msg->contact()); + if (contact == NULL) + return false; + ICQUserData *data = NULL; + ClientDataIterator it(contact->clientData, this); + if (client.isEmpty()) + while ((data = toICQUserData(++it)) != NULL) + break; + while ((data = toICQUserData(++it)) != NULL) + if (dataName(data) == client) + break; + if (data == NULL) + return false; + if (msg->type() == MessageOpenSecure) + { + SecureDlg *dlg = NULL; + QWidgetList list = QApplication::topLevelWidgets(); + QWidget * w; + foreach(w,list) + { + if (!w->inherits("SecureDlg")) + continue; + dlg = static_cast(w); + if (dlg->m_client == this && dlg->m_contact == contact->id() && dlg->m_data == data) + break; + dlg = NULL; + } + if (dlg == NULL) + dlg = new SecureDlg(this, contact->id(), data); + raiseWindow(dlg); + return true; + } else + if (msg->type() == MessageWarning){ + if (!(data && (m_bAIM || data->Uin.toULong() == 0))) + return false; + + WarnDlg *dlg = new WarnDlg(NULL, data, this); + raiseWindow(dlg); + return true; + } + DirectClient *dc = dynamic_cast(data->Direct.object()); + if (dc && dc->isSecure()) + { + Message *m = new Message(MessageCloseSecure); + m->setContact(msg->contact()); + m->setClient(msg->client()); + m->setFlags(MESSAGE_NOHISTORY); + if (!dc->sendMessage(m)) + delete m; + return true; + } + break; + } + default: + break; + } + return false; +} + +bool ICQClient::send(Message *msg, void *_data) +{ + if (getState() != Connected) + return false; + ICQUserData *data = toICQUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + SendMsg s; + switch (msg->type()){ + case MessageSMS: + if (m_bAIM) + return false; + s.msg = static_cast(msg); + s.text = s.msg->getPlainText(); + s.flags = SEND_1STPART; + snacICBM()->sendSMS(s); + return true; + case MessageAuthRequest: + if (data && data->WaitAuth.toBool()) + return sendAuthRequest(msg, data); + return false; + case MessageAuthGranted: + if (data && data->WantAuth.toBool()) + return sendAuthGranted(msg, data); + return false; + case MessageAuthRefused: + if (data && data->WantAuth.toBool()) + return sendAuthRefused(msg, data); + return false; + case MessageFile: + if (data && ((data->Status.toULong() & 0xFFFF) != ICQ_STATUS_OFFLINE)) + { + log(L_DEBUG, "send: MessageFile"); + if (!hasCap(data, CAP_AIM_SENDFILE)) + return false; + snacICBM()->sendThruServer(msg, data); + return true; + } + return false; + case MessageTypingStop: + case MessageTypingStart: + if ((data == NULL) || getDisableTypingNotification()) + return false; + if((data->Status.toULong() & 0xFFFF) == ICQ_STATUS_OFFLINE) + return false; + if (getInvisible()){ + if (data->VisibleId.toULong() == 0) + return false; + }else{ + if (data->InvisibleId.toULong()) + return false; + } + if (!hasCap(data, CAP_TYPING) && !hasCap(data, CAP_AIM_BUDDYCON)) + return false; + snacICBM()->sendMTN(screen(data), msg->type() == MessageTypingStart ? ICQ_MTN_START : ICQ_MTN_FINISH); + delete msg; + return true; + case MessageOpenSecure: { + if (data == NULL) + return false; + DirectClient *dc = dynamic_cast(data->Direct.object()); + if (dc && dc->isSecure()) + return false; + if (!dc){ + dc = new DirectClient(data, this, PLUGIN_NULL); + data->Direct.setObject(dc); + dc->connect(); + } + return dc->sendMessage(msg); + } + case MessageCloseSecure: { + if (data == NULL) + return false; + DirectClient *dc = dynamic_cast(data->Direct.object()); + if (dc && dc->isSecure()) + return dc->sendMessage(msg); + return false; + } + case MessageWarning: + return snacICBM()->sendThruServer(msg, data); + case MessageContacts: + if ((data == NULL) || ((data->Uin.toULong() == 0) && !hasCap(data, CAP_AIM_BUDDYLIST))) + return false; + } + if (data == NULL) + return false; + if (data->Uin.toULong()){ + bool bCreateDirect = false; + DirectClient *dc = dynamic_cast(data->Direct.object()); + if ((dc == NULL) && + !data->bNoDirect.toBool() && + (data->Status.toULong() != ICQ_STATUS_OFFLINE) && + (get_ip(data->IP) == get_ip(this->data.owner.IP))) + bCreateDirect = true; + if (!bCreateDirect && + (msg->type() == MessageGeneric) && + (data->Status.toULong() != ICQ_STATUS_OFFLINE) && + (get_ip(data->IP)) && + ((unsigned)msg->getPlainText().length() >= MAX_TYPE2_MESSAGE_SIZE)) + bCreateDirect = true; + if ((getInvisible() && (data->VisibleId.toULong() == 0)) || + (!getInvisible() && data->InvisibleId.toULong())) + bCreateDirect = false; + if (bCreateDirect){ + dc = new DirectClient(data, this, PLUGIN_NULL); + data->Direct.setObject(dc); + dc->connect(); + } + if (dc) + return dc->sendMessage(msg); + } + return snacICBM()->sendThruServer(msg, data); +} + +bool ICQClient::canSend(unsigned type, void *_data) +{ + if (_data && (((clientData*)_data)->Sign.toULong() != ICQ_SIGN)) + return false; + if (getState() != Connected) + return false; + ICQUserData *data = toICQUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + switch (type){ + case MessageSMS: + return !m_bAIM; + case MessageGeneric: + case MessageUrl: + return (data != NULL); + case MessageContacts: + return (data != NULL) && (data->Uin.toULong() || hasCap(data, CAP_AIM_BUDDYLIST)); + case MessageAuthRequest: + return data && (data->WaitAuth.toBool()); + case MessageAuthGranted: + return data && (data->WantAuth.toBool()); + case MessageFile: + return data && + ((data->Status.toULong() & 0xFFFF) != ICQ_STATUS_OFFLINE) && + (data->Uin.toULong() || hasCap(data, CAP_AIM_SENDFILE)); + case MessageWarning: + return data && (data->Uin.toULong() == 0); + case MessageOpenSecure: + if ((data == NULL) || ((data->Status.toULong() & 0xFFFF) == ICQ_STATUS_OFFLINE)) + return false; + if (hasCap(data, CAP_LICQ) || + hasCap(data, CAP_SIM) || + hasCap(data, CAP_SIMOLD) || + ((data->InfoUpdateTime.toULong() & 0xFF7F0000L) == 0x7D000000L)){ + DirectClient *dc = dynamic_cast(data->Direct.object()); + if (dc) + return !(dc->isSecure()); + return get_ip(data->IP) || get_ip(data->RealIP); + } + return false; + case MessageCloseSecure: { + if(!data) + return false; + DirectClient *dc = dynamic_cast(data->Direct.object()); + return dc && dc->isSecure(); + } + } + return false; +} + +QString ICQClient::dataName(void *data) +{ + return dataName(screen(toICQUserData((SIM::clientData*)data))); // FIXME unsafe type conversion +} + +QString ICQClient::dataName(const QString &screen) +{ + return name() + '.' + screen; +} + +QString ICQClient::screen(const ICQUserData *data) +{ + if (data->Uin.toULong() == 0) + return data->Screen.str(); + return QString::number(data->Uin.toULong()); +} + +bool ICQClient::messageReceived(Message *msg, const QString &screen) +{ + msg->setFlags(msg->getFlags() | MESSAGE_RECEIVED); + if (msg->contact() == 0){ + Contact *contact; + ICQUserData *data = findContact(screen, NULL, false, contact); + if (data == NULL){ + data = findContact(screen, NULL, true, contact); + if (data == NULL){ + delete msg; + return true; + } + contact->setFlags(CONTACT_TEMP); + EventContact e(contact, EventContact::eChanged); + e.process(); + } + msg->setClient(dataName(data)); + msg->setContact(contact->id()); + if (data->bTyping.toBool()){ + data->bTyping.asBool() = false; + EventContact e(contact, EventContact::eStatus);; + e.process(); + } + } + bool bAccept = false; + switch (msg->type()){ + case MessageICQFile: + case MessageFile: + bAccept = true; + break; + } + if (bAccept) + m_acceptMsg.push_back(msg); + EventMessageReceived e(msg); + if (e.process()){ + if (bAccept){ + for (list::iterator it = m_acceptMsg.begin(); it != m_acceptMsg.end(); ++it){ + if ((*it) == msg){ + m_acceptMsg.erase(it); + break; + } + } + } + }else{ + if (!bAccept) + delete msg; + } + return !bAccept; +} + +QString ICQClient::contactName(void *clientData) +{ + QString res; + ICQUserData *data = toICQUserData((SIM::clientData*)clientData); // FIXME unsafe type conversion + res = data->Uin.toULong() ? "ICQ: " : "AIM: "; + if (!data->Nick.str().isEmpty()){ + res += data->Nick.str(); + res += " ("; + } + res += data->Uin.toULong() ? QString::number(data->Uin.toULong()) : data->Screen.str(); + if (!data->Nick.str().isEmpty()) + res += ')'; + return res; +} + +bool ICQClient::isSupportPlugins(ICQUserData *data) +{ + if (data->Version.toULong() < 7) + return false; + switch (data->InfoUpdateTime.toULong()){ + case 0xFFFFFF42: + case 0xFFFFFFFF: + case 0xFFFFFF7F: + case 0xFFFFFFBE: + case 0x3B75AC09: + case 0x3AA773EE: + case 0x3BC1252C: + case 0x3B176B57: + case 0x3BA76E2E: + case 0x3C7D8CBC: + case 0x3CFE0688: + case 0x3BFF8C98: + return false; + } + if ((data->InfoUpdateTime.toULong() & 0xFF7F0000L) == 0x7D000000L) + return false; + if (hasCap(data, CAP_TRIL_CRYPT) || hasCap(data, CAP_TRILLIAN)) + return false; + return true; +} + +void ICQClient::addPluginInfoRequest(unsigned long uin, unsigned plugin_index) +{ + log(L_DEBUG, "ICQClient::addPluginInfoRequest"); + Contact *contact; + ICQUserData *data = findContact(uin, NULL, false, contact); + if (data && !data->bNoDirect.toBool() && + get_ip(data->IP) && (get_ip(data->IP) == get_ip(this->data.owner.IP)) && + ((getInvisible() && data->VisibleId.toULong()) || + (!getInvisible() && (data->InvisibleId.toULong() == 0)))){ + switch (plugin_index){ + case PLUGIN_AR: { + DirectClient *dc = dynamic_cast(data->Direct.object()); + if ((dc == NULL) && !getHideIP()){ + dc = new DirectClient(data, this, PLUGIN_NULL); + data->Direct.setObject(dc); + dc->connect(); + } + if (dc){ + dc->addPluginInfoRequest(plugin_index); + return; + } + break; + } + case PLUGIN_QUERYxINFO: + case PLUGIN_PHONEBOOK: + case PLUGIN_PICTURE: { + if (!isSupportPlugins(data)) + return; + DirectClient *dc = dynamic_cast(data->DirectPluginInfo.object()); + if ((dc == NULL) && !getHideIP()){ + dc = new DirectClient(data, this, PLUGIN_INFOxMANAGER); + data->DirectPluginInfo.setObject(dc); + dc->connect(); + } + if (dc){ + dc->addPluginInfoRequest(plugin_index); + return; + } + break; + } + case PLUGIN_QUERYxSTATUS: + case PLUGIN_FILESERVER: + case PLUGIN_FOLLOWME: + case PLUGIN_ICQPHONE: { + if (!isSupportPlugins(data)) + return; + DirectClient *dc = dynamic_cast(data->DirectPluginStatus.object()); + if ((dc == NULL) && !getHideIP()){ + dc = new DirectClient(data, this, PLUGIN_STATUSxMANAGER); + data->DirectPluginStatus.setObject(dc); + dc->connect(); + } + if (dc){ + dc->addPluginInfoRequest(plugin_index); + return; + } + break; + } + } + } + snacICBM()->pluginInfoRequest(uin, plugin_index); +} + +void ICQClient::randomChatInfo(unsigned long uin) +{ + addPluginInfoRequest(uin, PLUGIN_RANDOMxCHAT); +} + +unsigned short ICQClient::msgStatus() +{ + return (unsigned short)(fullStatus(getStatus()) & 0xFF); +} + +static char PICT_PATH[] = "pictures/"; + +QString ICQClient::pictureFile(const ICQUserData *data) +{ + QString f = user_file(PICT_PATH); + QFileInfo fi(f); + if(!fi.exists()) + QDir().mkdir(f); + if(!fi.isDir()) + log(L_ERROR, QString("%1 is not a directory!").arg(f)); + f += "icq.avatar."; + f += data->Uin.toULong() ? QString::number(data->Uin.toULong()) : data->Screen.str(); + f += '.'; + f += QString::number(data->buddyID.toULong()); + return f; +} + +QImage ICQClient::userPicture(unsigned id) +{ + if (id==0) + return QImage(); + Contact *contact = getContacts()->contact(id); + if(!contact) + return QImage(); + ClientDataIterator it(contact->clientData, this); + + ICQUserData *d; + while ((d = toICQUserData(++it)) != NULL){ + QImage img = userPicture(d); + if(!img.isNull()) + return img; + } + return QImage(); +} + +QImage ICQClient::userPicture(ICQUserData *d) +{ + QImage img=QImage(d ? pictureFile(d) : data.owner.Picture.str()); + + if(img.isNull()) + return img; + + int w = img.width(); + int h = img.height(); + if (h > w){ + if (h > 60){ + w = w * 60 / h; + h = 60; + } + }else{ + if (w > 60){ + h = h * 60 / w; + w = 60; + } + } + + return img.scaled(w, h); +} + + +void ICQClient::retry(int n, void *p) +{ + EventMessageRetry::MsgSend *m = reinterpret_cast(p); + if (m->msg->getRetryCode() == static_cast(protocol()->plugin())->RetrySendDND){ + if (n == 0){ + m->edit->m_flags = MESSAGE_LIST; + }else{ + return; + } + }else if (m->msg->getRetryCode() == static_cast(protocol()->plugin())->RetrySendOccupied){ + switch (n){ + case 0: + m->edit->m_flags = MESSAGE_URGENT; + break; + case 1: + m->edit->m_flags = MESSAGE_LIST; + break; + default: + return; + } + }else{ + return; + } + Command cmd; + cmd->id = CmdSend; + cmd->param = m->edit; + EventCommandExec(cmd).process(); +} + +bool ICQClient::isOwnData(const QString &screen) +{ + if (screen.isEmpty()) + return false; + if(data.owner.Uin.toULong()) + return (data.owner.Uin.toULong() == screen.toULong()); + return (screen.toLower() == data.owner.Screen.str().toLower()); +} + +QString ICQClient::addCRLF(const QString &str) +{ + QString res = str; + return res.replace(QRegExp("\r?\n"), "\r\n"); +} + +Contact *ICQClient::getContact(ICQUserData *data) +{ + Contact *contact = NULL; + findContact(screen(data), NULL, false, contact); + return contact; +} + + +ICQUserData* ICQClient::toICQUserData(SIM::clientData * data) +{ + // This function is used to more safely preform type conversion from SIM::clientData* into ICQUserData* + // It will at least warn if the content of the structure is not ICQUserData + // Brave wariors may uncomment abort() function call to know for sure about wrong conversion ;-) + if (! data) return NULL; + if (data->Sign.asULong() != ICQ_SIGN) + { + QString Signs[] = { + "Unknown(0)" , // 0x0000 + "ICQ_SIGN", // 0x0001 + "JABBER_SIGN", // 0x0002 + "MSN_SIGN", // 0x0003 + "Unknown(4)" // 0x0004 + "LIVEJOURNAL_SIGN",// 0x0005 + "SMS_SIGN", // 0x0006 + "Unknown(7)", // 0x0007 + "Unknown(8)", // 0x0008 + "YAHOO_SIGN" // 0x0009 + }; + QString Sign; + if (data->Sign.toULong()<=9) // is always >=0 as it is unsigned int + Sign = Signs[data->Sign.toULong()]; + else + Sign = QString("Unknown(%1)").arg(Sign.toULong()); + + log(L_ERROR, + "ATTENTION!! Unsafly converting %s user data into ICQ_SIGN", + qPrintable(Sign)); +// abort(); + } + return (ICQUserData*) data; +} + diff --git a/plugins/icq/icqclient.h b/plugins/icq/icqclient.h new file mode 100644 index 0000000..10b6a1e --- /dev/null +++ b/plugins/icq/icqclient.h @@ -0,0 +1,987 @@ +/*************************************************************************** + icqclient.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _ICQCLIENT_H +#define _ICQCLIENT_H + +#include +#include +#include + +#include +#include +#include +#include + +#include "misc.h" +#include "snac.h" +#include "icqbuddy.h" +#include "icqservice.h" +#include "icqicmb.h" + +#include "socket/socket.h" +#include "socket/serversocketnotify.h" +#include "socket/clientsocket.h" +#include "socket/tcpclient.h" +#include "socket/interfacechecker.h" +#include "socket/sslclient.h" +#include "contacts/clientdataiterator.h" +#include "icq.h" +#include "icqbuffer.h" + +const unsigned ICQ_SIGN = 0x0001; + +const unsigned MESSAGE_DIRECT = 0x0100; + +//const unsigned STATUS_INVISIBLE = 2; //took over to contacts.h +//const unsigned STATUS_OCCUPIED = 100; //took over to contacts.h + +const unsigned char ICQ_TCP_VERSION = 0x09; + +const unsigned char MODE_DENIED = 0x01; +const unsigned char MODE_INDIRECT = 0x02; +const unsigned char MODE_DIRECT = 0x04; + +// Server channels +const unsigned char ICQ_CHNxNEW = 0x01; +const unsigned char ICQ_CHNxDATA = 0x02; +const unsigned char ICQ_CHNxERROR = 0x03; +const unsigned char ICQ_CHNxCLOSE = 0x04; +const unsigned char ICQ_CHNxPING = 0x05; + +// Server SNAC foodgroups +const unsigned short ICQ_SNACxFOOD_SERVICE = 0x0001; +const unsigned short ICQ_SNACxFOOD_LOCATION = 0x0002; +const unsigned short ICQ_SNACxFOOD_BUDDY = 0x0003; +const unsigned short ICQ_SNACxFOOD_MESSAGE = 0x0004; +const unsigned short ICQ_SNACxFOOD_AIMxINVITATION = 0x0006; +const unsigned short ICQ_SNACxFOOD_ADMINISTRATIVE = 0x0007; +const unsigned short ICQ_SNACxFOOD_BOS = 0x0009; +const unsigned short ICQ_SNACxFOOD_PING = 0x000B; +const unsigned short ICQ_SNACxFOOD_CHATxNAVIGATION = 0x000D; +const unsigned short ICQ_SNACxFOOD_CHAT = 0x000E; +const unsigned short ICQ_SNACxFOOD_SSBI = 0x0010; +const unsigned short ICQ_SNACxFOOD_LISTS = 0x0013; +const unsigned short ICQ_SNACxFOOD_VARIOUS = 0x0015; +const unsigned short ICQ_SNACxFOOD_LOGIN = 0x0017; + +#define SNAC(A, B) ((A << 16) + B) + +// Status +const unsigned short ICQ_STATUS_OFFLINE = 0xFFFF; +const unsigned short ICQ_STATUS_ONLINE = 0x0000; +const unsigned short ICQ_STATUS_AWAY = 0x0001; +const unsigned short ICQ_STATUS_DND = 0x0002; +const unsigned short ICQ_STATUS_NA = 0x0004; +const unsigned short ICQ_STATUS_OCCUPIED = 0x0010; +const unsigned short ICQ_STATUS_FFC = 0x0020; + +const unsigned long ICQ_STATUS_FxFLAGS = 0xFFFF0000; +const unsigned long ICQ_STATUS_FxUNKNOWNxFLAGS = 0xCFC0FCC8; +const unsigned long ICQ_STATUS_FxPRIVATE = 0x00000100; +const unsigned long ICQ_STATUS_FxPFMxAVAILABLE = 0x00000200; // not implemented +const unsigned long ICQ_STATUS_FxWEBxPRESENCE = 0x00010000; +const unsigned long ICQ_STATUS_FxHIDExIP = 0x00020000; +const unsigned long ICQ_STATUS_FxPFM = 0x00040000; // not implemented +const unsigned long ICQ_STATUS_FxBIRTHDAY = 0x00080000; +const unsigned long ICQ_STATUS_FxDIRECTxDISABLED = 0x00100000; +const unsigned long ICQ_STATUS_FxICQxHOMEPAGE = 0x00200000; // not implemented +const unsigned long ICQ_STATUS_FxDIRECTxAUTH = 0x10000000; // will accept connections only when authorized +const unsigned long ICQ_STATUS_FxDIRECTxLISTED = 0x20000000; // will accept connections only when listed + +const unsigned CLASS_UNCONFIRMED = 0x0001; // AOL unconfirmed user flsg +const unsigned CLASS_ADMINISTRATOR = 0x0002; // AOL administrator flag +const unsigned CLASS_AOL = 0x0004; // AOL staff user flag +const unsigned CLASS_COMMERCIAL = 0x0008; // AOL commercial account flag +const unsigned CLASS_FREE = 0x0010; // ICQ non-commercial account flag +const unsigned CLASS_AWAY = 0x0020; // Away status flag +const unsigned CLASS_ICQ = 0x0040; // ICQ user sign +const unsigned CLASS_WIRELESS = 0x0100; // AOL wireless user + +const unsigned short ICQ_MSGxMSG = 0x0001; +const unsigned short ICQ_MSGxCHAT = 0x0002; +const unsigned short ICQ_MSGxFILE = 0x0003; +const unsigned short ICQ_MSGxURL = 0x0004; +const unsigned short ICQ_MSGxAUTHxREQUEST = 0x0006; +const unsigned short ICQ_MSGxAUTHxREFUSED = 0x0007; +const unsigned short ICQ_MSGxAUTHxGRANTED = 0x0008; +const unsigned short ICQ_MSGxSERVERxMSG = 0x0009; +const unsigned short ICQ_MSGxADDEDxTOxLIST = 0x000C; +const unsigned short ICQ_MSGxWEBxPANEL = 0x000D; +const unsigned short ICQ_MSGxEMAILxPAGER = 0x000E; +const unsigned short ICQ_MSGxCONTACTxLIST = 0x0013; +const unsigned short ICQ_MSGxEXT = 0x001A; + +const unsigned short ICQ_MSGxSECURExCLOSE = 0x00EE; +const unsigned short ICQ_MSGxSECURExOPEN = 0x00EF; + +const unsigned short ICQ_MSGxAR_AWAY = 0x03E8; +const unsigned short ICQ_MSGxAR_OCCUPIED = 0x03E9; +const unsigned short ICQ_MSGxAR_NA = 0x03EA; +const unsigned short ICQ_MSGxAR_DND = 0x03EB; +const unsigned short ICQ_MSGxAR_FFC = 0x03EC; + +const unsigned short ICQ_TCPxACK_ONLINE = 0x0000; +const unsigned short ICQ_TCPxACK_AWAY = 0x0004; +const unsigned short ICQ_TCPxACK_OCCUPIED = 0x0009; +const unsigned short ICQ_TCPxACK_DND = 0x000A; +const unsigned short ICQ_TCPxACK_OCCUPIEDxCAR = 0x000B; +const unsigned short ICQ_TCPxACK_OCCUPIEDx2 = 0x000C; +const unsigned short ICQ_TCPxACK_NA = 0x000E; +const unsigned short ICQ_TCPxACK_DNDxCAR = 0x000F; +const unsigned short ICQ_TCPxACK_ACCEPT = 0x0000; +const unsigned short ICQ_TCPxACK_REFUSE = 0x0001; + +const unsigned short ICQ_TCPxMSG_AUTOxREPLY = 0x0000; +const unsigned short ICQ_TCPxMSG_NORMAL = 0x0001; +const unsigned short ICQ_TCPxMSG_URGENT = 0x0002; +const unsigned short ICQ_TCPxMSG_LIST = 0x0004; + +const unsigned short ICQ_MTN_FINISH = 0x0000; +const unsigned short ICQ_MTN_TYPED = 0x0001; +const unsigned short ICQ_MTN_START = 0x0002; + +const char DIRECT_MODE_DENIED = 0x01; +const char DIRECT_MODE_INDIRECT = 0x02; +const char DIRECT_MODE_DIRECT = 0x04; + +const unsigned MAX_PLAIN_MESSAGE_SIZE = 450; +const unsigned MAX_TYPE2_MESSAGE_SIZE = 4096; + +const unsigned PING_TIMEOUT = 60; + +const unsigned RATE_PAUSE = 3; +const unsigned RATE_LIMIT = 5; + +const unsigned short SEARCH_DONE = USHRT_MAX; + +class AIMFileTransfer; +class DirectClient; + +struct ICQUserData : public SIM::clientData +{ + SIM::Data Alias; + SIM::Data Cellular; + SIM::Data Status; + SIM::Data Class; + SIM::Data StatusTime; + SIM::Data OnlineTime; + SIM::Data WarningLevel; + SIM::Data IP; + SIM::Data RealIP; + SIM::Data Port; + SIM::Data DCcookie; + SIM::Data Caps; + SIM::Data Caps2; + SIM::Data AutoReply; + SIM::Data Uin; + SIM::Data Screen; + SIM::Data IcqID; + SIM::Data bChecked; + SIM::Data GrpId; + SIM::Data IgnoreId; + SIM::Data VisibleId; + SIM::Data ContactVisibleId; + SIM::Data InvisibleId; + SIM::Data ContactInvisibleId; + SIM::Data WaitAuth; + SIM::Data WantAuth; + SIM::Data WebAware; + SIM::Data InfoUpdateTime; + SIM::Data PluginInfoTime; + SIM::Data PluginStatusTime; + SIM::Data InfoFetchTime; + SIM::Data PluginInfoFetchTime; + SIM::Data PluginStatusFetchTime; + SIM::Data Mode; + SIM::Data Version; + SIM::Data Build; + SIM::Data Nick; + SIM::Data FirstName; + SIM::Data LastName; + SIM::Data MiddleName; + SIM::Data Maiden; + SIM::Data EMail; + SIM::Data HiddenEMail; + SIM::Data City; + SIM::Data State; + SIM::Data HomePhone; + SIM::Data HomeFax; + SIM::Data Address; + SIM::Data PrivateCellular; + SIM::Data Zip; + SIM::Data Country; + SIM::Data TimeZone; + SIM::Data Age; + SIM::Data Gender; + SIM::Data Homepage; + SIM::Data BirthYear; + SIM::Data BirthMonth; + SIM::Data BirthDay; + SIM::Data Language; + SIM::Data EMails; + SIM::Data WorkCity; + SIM::Data WorkState; + SIM::Data WorkPhone; + SIM::Data WorkFax; + SIM::Data WorkAddress; + SIM::Data WorkZip; + SIM::Data WorkCountry; + SIM::Data WorkName; + SIM::Data WorkDepartment; + SIM::Data WorkPosition; + SIM::Data Occupation; + SIM::Data WorkHomepage; + SIM::Data About; + SIM::Data Interests; + SIM::Data Backgrounds; + SIM::Data Affilations; + SIM::Data FollowMe; + SIM::Data SharedFiles; + SIM::Data ICQPhone; + SIM::Data Picture; + SIM::Data PictureWidth; + SIM::Data PictureHeight; + SIM::Data PhoneBook; + SIM::Data ProfileFetch; + SIM::Data bTyping; + SIM::Data bBadClient; + SIM::Data Direct; + SIM::Data DirectPluginInfo; + SIM::Data DirectPluginStatus; + SIM::Data bNoDirect; + SIM::Data bInvisible; + SIM::Data buddyRosterID; + SIM::Data buddyID; + SIM::Data buddyHash; + SIM::Data unknown2; + SIM::Data unknown4; + SIM::Data unknown5; +}; + +struct ICQClientData +{ + SIM::Data Server; + SIM::Data Port; + SIM::Data ContactsTime; + SIM::Data ContactsLength; + SIM::Data ContactsInvisible; + SIM::Data HideIP; + SIM::Data IgnoreAuth; + SIM::Data UseMD5; + SIM::Data DirectMode; + SIM::Data IdleTime; + SIM::Data ListRequests; + SIM::Data Picture; + SIM::Data RandomChatGroup; + SIM::Data RandomChatGroupCurrent; + SIM::Data SendFormat; + SIM::Data DisablePlugins; + SIM::Data DisableAutoUpdate; + SIM::Data DisableAutoReplyUpdate; + SIM::Data DisableTypingNotification; +// Data AutoCheckInvisible; +// Data CheckInvisibleInterval; + SIM::Data AcceptInDND; + SIM::Data AcceptInOccupied; + SIM::Data MinPort; + SIM::Data MaxPort; + SIM::Data WarnAnonimously; + SIM::Data AckMode; + SIM::Data UseHTTP; + SIM::Data AutoHTTP; + SIM::Data KeepAlive; + SIM::Data MediaSense; + ICQUserData owner; +}; + +class ICQClient; + +struct SearchResult +{ + ICQUserData data; + unsigned short id; + ICQClient *client; +}; + +class QTimer; + +typedef unsigned char capability[0x10]; +typedef unsigned char plugin[0x12]; + +enum cap_id_t { + CAP_AIM_SHORTCAPS = 0, // 0x00000001 + CAP_AIM_VOICE, // 0x00000002 + CAP_AIM_SENDFILE, // 0x00000004 + CAP_DIRECT, // 0x00000008 + CAP_AIM_IMIMAGE, // 0x00000010 + CAP_AIM_BUDDYCON, // 0x00000020 + CAP_AIM_STOCKS, // 0x00000040 + CAP_AIM_GETFILE, // 0x00000080 + CAP_SRV_RELAY, // 0x00000100 + CAP_AIM_GAMES, // 0x00000200 + CAP_AIM_BUDDYLIST, // 0x00000400 + CAP_AVATAR, // 0x00000800 + CAP_AIM_SUPPORT, // 0x00001000 + CAP_UTF, // 0x00002000 + CAP_RTF, // 0x00004000 + CAP_TYPING, // 0x00008000 + CAP_SIM, // 0x00010000 + CAP_STR_2001, // 0x00020000 + CAP_STR_2002, // 0x00040000 + CAP_IS_2001, // 0x00080000 + CAP_TRILLIAN, // 0x00100000 + CAP_TRIL_CRYPT, // 0x00200000 + CAP_MACICQ, // 0x00400000 + CAP_AIM_CHAT, // 0x00800000 + CAP_MICQ, // 0x01000000 + CAP_LICQ, // 0x02000000 + CAP_SIMOLD, // 0x04000000 + CAP_KOPETE, // 0x08000000 + CAP_XTRAZ, // 0x10000000 + CAP_IS_2002, // 0x20000000 + CAP_MIRANDA, // 0x40000000 + CAP_ANDRQ, // 0x80000000 + CAP_QIP, // 0x00000001 - Caps2 + CAP_IMSECURE, // 0x00000002 + CAP_KXICQ, // 0x00000004 + CAP_ICQ5_1, // 0x00000008 + CAP_UNKNOWN, // 0x00000010 + CAP_ICQ5_3, // 0x00000020 + CAP_ICQ5_4, // 0x00000040 + CAP_ICQ51, // 0x00000080 + CAP_JIMM, // 0x00000100 + CAP_ICQJP, // 0x00000200 + CAP_NULL, // 0x00000400 +}; + +const unsigned PLUGIN_PHONEBOOK = 0; +const unsigned PLUGIN_PICTURE = 1; +const unsigned PLUGIN_FILESERVER = 2; +const unsigned PLUGIN_FOLLOWME = 3; +const unsigned PLUGIN_ICQPHONE = 4; +const unsigned PLUGIN_QUERYxINFO = 5; +const unsigned PLUGIN_QUERYxSTATUS = 6; +const unsigned PLUGIN_INFOxMANAGER = 7; +const unsigned PLUGIN_STATUSxMANAGER = 8; +const unsigned PLUGIN_RANDOMxCHAT = 9; +const unsigned PLUGIN_VIDEO_CHAT = 10; +const unsigned PLUGIN_NULL = 11; +const unsigned PLUGIN_FILE = 12; +const unsigned PLUGIN_CHAT = 13; +const unsigned PLUGIN_AR = 14; +const unsigned PLUGIN_INVISIBLE = 15; +const unsigned PLUGIN_REVERSE = 16; +const unsigned PLUGIN_AIM_FT = 17; +const unsigned PLUGIN_AIM_FT_ACK = 18; + +class ICQClient; + +const unsigned LIST_USER_CHANGED = 0; +const unsigned LIST_USER_DELETED = 1; +const unsigned LIST_GROUP_CHANGED = 2; +const unsigned LIST_GROUP_DELETED = 3; +const unsigned LIST_BUDDY_CHECKSUM = 4; + +class ListRequest +{ +public: + ListRequest() + : type(0), icq_id(0), grp_id(0), visible_id(0), invisible_id(0), ignore_id(0), + icqUserData(NULL) {} + +public: + unsigned type; + QString screen; + unsigned short icq_id; + unsigned short grp_id; + unsigned short visible_id; + unsigned short invisible_id; + unsigned short ignore_id; + const ICQUserData *icqUserData; +}; + +class ICQListener : public SIM::ServerSocketNotify +{ +public: + ICQListener(ICQClient *client); + ~ICQListener(); +protected: + virtual bool accept(SIM::Socket *s, unsigned long ip); + virtual void bind_ready(unsigned short port); + virtual bool error(const QString &err); + ICQClient *m_client; +}; + +class DirectSocket; +class ServerRequest; +class ListServerRequest; +class QTextCodec; + +const unsigned SEND_PLAIN = 0x0001; +const unsigned SEND_UTF = 0x0002; +const unsigned SEND_RTF = 0x0003; +const unsigned SEND_TYPE2 = 0x0004; +const unsigned SEND_RAW = 0x0005; +const unsigned SEND_HTML = 0x0006; +const unsigned SEND_HTML_PLAIN = 0x0007; +const unsigned SEND_MASK = 0x000F; +const unsigned SEND_1STPART = 0x0010; + +struct ar_request +{ + unsigned short type; + unsigned short flags; + unsigned short ack; + MessageId id; + unsigned short id1; + unsigned short id2; + QString screen; + bool bDirect; +}; + +typedef std::map INFO_REQ_MAP; + +class DirectSocket; +class ServiceSocket; +class ICQClientSocket; + +class OscarSocket +{ +public: + OscarSocket(); + virtual ~OscarSocket(){}; + + void snac(unsigned short food, unsigned short type, bool msgId=false, bool bType=true); + void sendPacket(bool bSend = true); +protected: + virtual ICQClientSocket *socket() = 0; + virtual void packet(unsigned long size) = 0; + void flap(char channel); + void connect_ready(); + void packet_ready(); + bool m_bHeader; + char m_nChannel; + unsigned short m_nFlapSequence; + unsigned short m_nMsgSequence; +}; + +struct alias_group +{ + QString alias; + unsigned grp; +}; + +struct RateInfo +{ + Buffer delayed; + QDateTime m_lastSend; + unsigned m_curLevel; + unsigned m_maxLevel; + unsigned m_minLevel; + unsigned m_winSize; +}; + +struct InfoRequest +{ + unsigned uin; + unsigned request_id; + unsigned start_time; +}; + +typedef std::map CONTACTS_MAP; +typedef std::map RATE_MAP; +typedef std::map mapSnacHandlers; + +class ICQClient : public SIM::TCPClient, public OscarSocket +{ + Q_OBJECT +public: + ICQClient(SIM::Protocol*, Buffer *cfg, bool bAIM); + ~ICQClient(); + virtual QString name(); + virtual QString getScreen(); + virtual QString dataName(void*); + virtual QWidget *setupWnd(); + virtual QByteArray getConfig(); + virtual void contactsLoaded(); + void setUin(unsigned long); + void setScreen(const QString &); + unsigned long getUin(); + QString getServer() const; + void setServer(const QString &); + PROP_USHORT(Port); + PROP_ULONG(ContactsTime); + PROP_USHORT(ContactsLength); + PROP_USHORT(ContactsInvisible); + PROP_BOOL(HideIP); + PROP_BOOL(IgnoreAuth); + PROP_BOOL(UseMD5); + PROP_ULONG(DirectMode); + PROP_ULONG(IdleTime); + PROP_STR(ListRequests); + PROP_UTF8(Picture); + PROP_USHORT(RandomChatGroup); + PROP_ULONG(RandomChatGroupCurrent); + PROP_ULONG(SendFormat); + PROP_BOOL(DisablePlugins); + PROP_BOOL(DisableAutoUpdate); + PROP_BOOL(DisableAutoReplyUpdate); + PROP_BOOL(DisableTypingNotification); + PROP_BOOL(AcceptInDND); + PROP_BOOL(AcceptInOccupied); + PROP_USHORT(MinPort); + PROP_USHORT(MaxPort); + PROP_BOOL(WarnAnonimously); + PROP_USHORT(AckMode); + PROP_BOOL(UseHTTP); + PROP_BOOL(AutoHTTP); + PROP_BOOL(KeepAlive); + PROP_BOOL(MediaSense); + ICQClientData data; + // reimplement socket() to get correct Buffer + virtual ICQClientSocket *socket() { return static_cast(TCPClient::socket()); } + virtual ICQClientSocket *createClientSocket() { return new ICQClientSocket(this, createSocket()); } + // icq functions + unsigned short findByUin(unsigned long uin); + unsigned short findByMail(const QString &mail); + unsigned short findWP(const QString &first, const QString &last, const QString &nick, + const QString &email, char age, char nGender, + unsigned short nLanguage, const QString &city, const QString &szState, + unsigned short nCountryCode, + const QString &cCoName, const QString &szCoDept, const QString &szCoPos, + unsigned short nOccupation, + unsigned short nPast, const QString &szPast, + unsigned short nInterests, const QString &szInterests, + unsigned short nAffiliation, const QString &szAffiliation, + unsigned short nHomePoge, const QString &szHomePage, + const QString &sKeyWord, bool bOnlineOnly); + SIM::Contact *getContact(ICQUserData*); + ICQUserData *findContact(unsigned long uin, const QString *alias, bool bCreate, SIM::Contact *&contact, SIM::Group *grp=NULL, bool bJoin=true); + ICQUserData *findContact(const QString &screen, const QString *alias, bool bCreate, SIM::Contact *&contact, SIM::Group *grp=NULL, bool bJoin=true); + ICQUserData *findGroup(unsigned id, const QString *name, SIM::Group *&group); + void addFullInfoRequest(unsigned long uin); + ListRequest *findContactListRequest(const QString &screen); + ListRequest *findGroupListRequest(unsigned short id); + void removeListRequest(ListRequest *lr); + virtual void setupContact(SIM::Contact*, void *data); + QString clientName(ICQUserData*); + void changePassword(const QString &new_pswd); + void searchChat(unsigned short); + void randomChatInfo(unsigned long uin); + unsigned short aimEMailSearch(const QString &name); + unsigned short aimInfoSearch(const QString &first, const QString &last, const QString &middle, + const QString &maiden, const QString &country, const QString &street, + const QString &city, const QString &nick, const QString &zip, + const QString &state); + SIM::Message *parseMessage(unsigned short type, const QString &screen, + const QByteArray &p, ICQBuffer &packet, MessageId &id, unsigned cookie); + void sendPacket(bool bSend); + bool messageReceived(SIM::Message*, const QString &screen); + static bool parseRTF(const QByteArray &str, SIM::Contact *contact, QString &result); + static QString pictureFile(const ICQUserData *data); + virtual QImage userPicture(unsigned id); + QImage userPicture(ICQUserData *d); + static const capability *capabilities; + static const plugin *plugins; + static QString convert(Tlv *tlvInfo, TlvList &tlvs, unsigned n); + static QString convert(const char *text, unsigned size, TlvList &tlvs, unsigned n); + static QString screen(const ICQUserData*); + static unsigned long warnLevel(unsigned long); + static unsigned clearTags(QString &text); + bool m_bAIM; + static QString addCRLF(const QString &str); + void uploadBuddy(const ICQUserData *data); + ICQUserData * toICQUserData(SIM::clientData*); // More safely type conversion from generic SIM::clientData into ICQUserData + + virtual void changeStatus(const SIM::IMStatusPtr& status); + + unsigned long getFullStatus(); + + bool addSnacHandler(SnacHandler* handler); + void clearSnacHandlers(); + + // ICBM: + void deleteFileMessage(MessageId const& cookie); + + // SSI: + void ssiStartTransaction(); + void ssiEndTransaction(); + bool isSSITransaction(){return false;} + unsigned short ssiAddBuddy(QString& screen, unsigned short group_id, unsigned short buddy_id, unsigned short buddy_type, TlvList* tlvs); + unsigned short ssiModifyBuddy(const QString& name, unsigned short grp_id, unsigned short usr_id, unsigned short subCmd, TlvList* tlv); + unsigned short ssiDeleteBuddy(QString& screen, unsigned short group_id, unsigned short buddy_id, unsigned short buddy_type, TlvList* tlvs); + void getGroupIDs(unsigned short group_id, ICQBuffer* buf); // hack + unsigned short ssiAddToGroup(QString& groupname, unsigned short buddy_id, unsigned short group_id); + unsigned short ssiRemoveFromGroup(QString& groupname, unsigned short buddy_id, unsigned short group_id); + TlvList *createListTlv(ICQUserData *data, SIM::Contact *contact); + + // Snac handlers accessors + SnacIcqService* snacService() { return m_snacService; } + SnacIcqBuddy* snacBuddy() { return m_snacBuddy; } + SnacIcqICBM* snacICBM() { return m_snacICBM; } + +protected slots: + void ping(); + void retry(int n, void*); + void interfaceDown(QString); + void interfaceUp(QString); +protected: + void generateCookie(MessageId& id); + + virtual void setInvisible(bool bState); + virtual void setStatus(unsigned status, bool bCommon); + virtual void setStatus(unsigned status); + virtual void disconnected(); + virtual bool processEvent(SIM::Event *e); + virtual bool compareData(void*, void*); + virtual void contactInfo(void *_data, unsigned long &status, unsigned &style, QString &statusIcon, QSet *icons = NULL); + virtual bool send(SIM::Message*, void*); + virtual bool canSend(unsigned type, void*); + virtual bool isMyData(SIM::clientData*&, SIM::Contact*&); + virtual bool createData(SIM::clientData*&, SIM::Contact*); + virtual QString contactTip(void *_data); + virtual SIM::CommandDef *infoWindows(SIM::Contact *contact, void *_data); + virtual QWidget *infoWindow(QWidget *parent, SIM::Contact *contact, void *_data, unsigned id); + virtual SIM::CommandDef *configWindows(); + virtual QWidget *configWindow(QWidget *parent, unsigned id); + virtual QWidget *searchWindow(QWidget *parent); + virtual void updateInfo(SIM::Contact *contact, void *_data); + virtual void setClientInfo(void *data); + virtual SIM::Socket *createSocket(); + virtual QString contactName(void *clientData); + QString dataName(const QString &screen); + QByteArray m_cookie; + virtual void packet(unsigned long size); + void snac_location(unsigned short, unsigned short); + void snac_bos(unsigned short, unsigned short); + void snac_ping(unsigned short, unsigned short); + void snac_lists(unsigned short, unsigned short); + void snac_various(unsigned short, unsigned short); + void snac_login(unsigned short, unsigned short); + void parseRosterItem(unsigned short type, const QString &str,unsigned short grp_id, + unsigned short id, TlvList *inf, bool &bIgnoreTime); + void chn_login(); + void chn_close(); + void listsRequest(); + void locationRequest(); + void buddyRequest(); + void bosRequest(); + void addCapability(ICQBuffer &cap, cap_id_t id); // helper for sendCapability() + void sendCapability(const QString &msg=QString::null); + void sendMessageRequest(); + void serverRequest(unsigned short cmd, unsigned short seq=0); + void sendServerRequest(); + void sendInvisible(bool bState); + void sendContactList(); + void setOffline(ICQUserData*); + void removeFullInfoRequest(unsigned long uin); + class SSBISocket *getSSBISocket(); + unsigned long fullStatus(unsigned status); + unsigned long fullStatus(const SIM::IMStatusPtr& status); + QByteArray cryptPassword(); + virtual void connect_ready(); + virtual void packet_ready(); + const char* error_message(unsigned short error); + bool m_bVerifying; + ICQListener *m_listener; + QTimer *m_processTimer; + unsigned short m_sendSmsId; + unsigned short m_offlineMessagesRequestId; + ListServerRequest *m_listRequest; + bool m_bRosters; + bool m_bBirthday; + bool m_bNoSend; + std::list varRequests; + std::list infoRequests; + QStringList buddies; + std::list listRequests; + std::list arRequests; + void addGroupRequest(SIM::Group *group); + void addContactRequest(SIM::Contact *contact); + void checkListRequest(); + void checkInfoRequest(); + ServerRequest *findServerRequest(unsigned short id); + void clearServerRequests(); + void clearListServerRequest(); + void clearSMSQueue(); + unsigned processListRequest(); + unsigned processSMSQueue(); + unsigned processInfoRequest(); + static bool hasCap(const ICQUserData *data, cap_id_t fcap); + static void setCap(ICQUserData *data, cap_id_t fcap); + bool isSupportPlugins(ICQUserData *data); + QString trimPhone(const QString &phone); + unsigned short getListId(); + unsigned short sendRoster(unsigned short cmd, const QString &name, + unsigned short grp_id, unsigned short usr_id, + unsigned short subCmd=0, TlvList *tlv = NULL); + void sendRosterGrp(const QString &name, unsigned short grpId, unsigned short usrId); + bool isContactRenamed(ICQUserData *data, SIM::Contact *contact); + QString getUserCellular(SIM::Contact *contact); + void setMainInfo(ICQUserData *d); + void setAIMInfo(ICQUserData *data); + void setProfile(ICQUserData *data); + bool isOwnData(const QString &screen); + void packInfoList(const QString &str); + QString packContacts(SIM::ContactsMessage *msg, ICQUserData *data, CONTACTS_MAP &c); + QByteArray createRTF(QString &text, QString &part, unsigned long foreColor, SIM::Contact *contact, unsigned max_size); + QString removeImages(const QString &text, bool icqSmiles); + bool sendAuthRequest(SIM::Message *msg, void *data); + bool sendAuthGranted(SIM::Message *msg, void *data); + bool sendAuthRefused(SIM::Message *msg, void *data); + void parseAdvancedMessage(const QString &screen, ICQBuffer &msg, bool needAck, MessageId id); + void addPluginInfoRequest(unsigned long uin, unsigned plugin_index); + void setChatGroup(); + SIM::Message *parseExtendedMessage(const QString &screen, ICQBuffer &packet, MessageId &id, unsigned cookie); + void parsePluginPacket(ICQBuffer &b, unsigned plugin_index, ICQUserData *data, unsigned uin, bool bDirect); + void pluginAnswer(unsigned plugin_type, unsigned long uin, ICQBuffer &b); + void packMessage(ICQBuffer &b, SIM::Message *msg, ICQUserData *data, unsigned short &type, bool bDirect, unsigned short flags=ICQ_TCPxMSG_NORMAL); + void packExtendedMessage(SIM::Message *msg, ICQBuffer &buf, ICQBuffer &msgBuf, ICQUserData *data); + void fetchProfile(ICQUserData *data); + void fetchAwayMessage(ICQUserData *data); + void fetchProfiles(); + void setAwayMessage(const QString &msg = QString::null); + void encodeString(const QString &text, const QString &type, unsigned short charsetTlv, unsigned short infoTlv); + void encodeString(const QString &_str, unsigned short nTlv, bool bWide); + bool processMsg(); + void packTlv(unsigned short tlv, unsigned short code, const QString &keywords); + void packTlv(unsigned short tlv, const QString &_data); + void packTlv(unsigned short tlv, unsigned short data); + void uploadBuddyIcon(unsigned short refNumber, const QImage &img); + void requestBuddy(const ICQUserData *data); + ICQUserData *findInfoRequest(unsigned short seq, SIM::Contact *&contact); + INFO_REQ_MAP m_info_req; + unsigned short msgStatus(); + unsigned short m_advCounter; + bool m_bJoin; + bool m_bFirstTry; + bool m_bHTTP; + bool m_bReady; + std::vector m_rates; + RATE_MAP m_rate_grp; + void setNewLevel(RateInfo &r); + unsigned delayTime(unsigned snac); + unsigned delayTime(RateInfo &r); + RateInfo *rateInfo(unsigned snac); + std::list m_processMsg; + std::list m_sockets; + std::list m_acceptMsg; + std::list m_filetransfers; + SnacIcqBuddy* m_snacBuddy; + SnacIcqService* m_snacService; + SnacIcqICBM* m_snacICBM; + mapSnacHandlers m_snacHandlers; + bool m_bconnectionLost; + + friend class ListServerRequest; + friend class FullInfoRequest; + friend class SMSRequest; + friend class ServiceSocket; + friend class DirectSocket; + friend class DirectClient; + friend class ICQListener; + friend class AIMFileTransfer; + friend class ICQFileTransfer; + friend class SetBuddyRequest; + friend class SSBISocket; + + // This should be removed when refactoring is over + friend class SnacIcqBuddy; + friend class SnacIcqService; + friend class SnacIcqICBM; + +private: + SIM::PropertyHubPtr m_propertyHub; + SIM::InterfaceChecker* m_ifChecker; + bool m_bBirthdayInfoDisplayed; +}; + +class ServiceSocket : public SIM::ClientSocketNotify, public OscarSocket +{ +public: + ServiceSocket(ICQClient*, unsigned short id); + ~ServiceSocket(); + unsigned short id() const { return m_id; } + void connect(const char *addr, unsigned short port, const QByteArray &cookie); + virtual bool error_state(const QString &err, unsigned code = 0); + bool connected() const { return m_bConnected; } + void close(); +protected: + virtual const char *serviceSocketName() = 0; + virtual void connect_ready(); + virtual void packet_ready(); + virtual ICQClientSocket *socket() { return m_socket; } + virtual void packet(unsigned long size); + virtual void data(unsigned short food, unsigned short type, unsigned short seq) = 0; + unsigned short m_id; + QByteArray m_cookie; + bool m_bConnected; + ICQClientSocket *m_socket; + ICQClient *m_client; +}; + +class DirectSocket : public QObject, public SIM::ClientSocketNotify +{ + Q_OBJECT +public: + enum SocketState{ + NotConnected, + ConnectIP1, + ConnectIP2, + ConnectFail, + WaitInit, + WaitAck, + WaitReverse, + ReverseConnect, + Logged + }; + DirectSocket(SIM::Socket *s, ICQClient*, unsigned long ip); + DirectSocket(ICQUserData *data, ICQClient *client); + ~DirectSocket(); + virtual void packet_ready(); + SocketState m_state; + void connect(); + void reverseConnect(unsigned long ip, unsigned short port); + void acceptReverse(SIM::Socket *s); + virtual bool error_state(const QString &err, unsigned code = 0); + virtual void connect_ready(); + unsigned short localPort(); + unsigned short remotePort(); + unsigned long Uin(); + ICQUserData *m_data; + void setPort(unsigned short port) {m_port = port;} +protected slots: + void timeout(); +protected: + virtual void login_timeout(); + virtual void processPacket() = 0; + void init(); + void sendInit(); + void sendInitAck(); + void removeFromClient(); + bool m_bIncoming; + unsigned short m_nSequence; + unsigned short m_port; + unsigned short m_localPort; + char m_version; + bool m_bHeader; + unsigned long m_nSessionId; + ICQClientSocket *m_socket; + ICQClient *m_client; + unsigned long m_ip; + friend class AIMFileTransfer; +}; + +struct SendDirectMsg +{ + SIM::Message *msg; + unsigned type; + unsigned short seq; + unsigned short icq_type; +}; + +class DirectClient : public DirectSocket +{ +public: + DirectClient(SIM::Socket *s, ICQClient *client, unsigned long ip); + DirectClient(ICQUserData *data, ICQClient *client, unsigned channel = PLUGIN_NULL); + ~DirectClient(); + bool sendMessage(SIM::Message*); + void acceptMessage(SIM::Message*); + void declineMessage(SIM::Message*, const QString &reason); + bool cancelMessage(SIM::Message*); + void sendAck(unsigned short, unsigned short msgType, unsigned short msgFlags, + const char *message=NULL, unsigned short status=ICQ_TCPxACK_ACCEPT, SIM::Message *m=NULL); + bool isLogged() { return (m_state != None) && (m_state != WaitInit2); } + bool isSecure(); + void addPluginInfoRequest(unsigned plugin_index); +protected: + enum State{ + None, + WaitLogin, + WaitInit2, + Logged, + SSLconnect + }; + State m_state; + unsigned m_channel; + void processPacket(); + void connect_ready(); + virtual bool error_state(const QString &err, unsigned code); + void sendInit2(); + void startPacket(unsigned short cms, unsigned short seq); + void sendPacket(); + void processMsgQueue(); + bool copyQueue(DirectClient *to); + QList m_queue; + QString name(); + QString m_name; + void secureConnect(); + void secureListen(); + void secureStop(bool bShutdown); + SIM::SSLClient *m_ssl; +}; + +class ICQFileTransfer : public SIM::FileTransfer, public DirectSocket, public SIM::ServerSocketNotify +{ +public: + ICQFileTransfer(SIM::FileMessage *msg, ICQUserData *data, ICQClient *client); + ~ICQFileTransfer(); + void connect(unsigned short port); + void listen(); + void setSocket(ICQClientSocket *socket); + virtual void processPacket(); +protected: + enum State + { + None, + WaitLogin, + WaitInit, + InitSend, + InitReceive, + Send, + Receive, + Wait, + WaitReverse, + WaitReverseLogin, + Listen + }; + State m_state; + + virtual void connect_ready(); + virtual bool error_state(const QString &err, unsigned code); + virtual void write_ready(); + virtual void setSpeed(unsigned speed); + virtual void startReceive(unsigned pos); + virtual void bind_ready(unsigned short port); + virtual bool accept(SIM::Socket *s, unsigned long ip); + virtual bool error(const QString &err); + virtual void login_timeout(); + + void sendInit(); + void startPacket(char cmd); + void sendPacket(bool dump=true); + void sendFileInfo(); + void initReceive(char cmd); + + friend class ICQClient; +}; + +#endif + + diff --git a/plugins/icq/icqconfig.cpp b/plugins/icq/icqconfig.cpp new file mode 100644 index 0000000..bde04b2 --- /dev/null +++ b/plugins/icq/icqconfig.cpp @@ -0,0 +1,155 @@ +/*************************************************************************** + icqconfig.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "icqconfig.h" +#include "icq.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace SIM; + +ICQConfig::ICQConfig(QWidget *parent, ICQClient *client, bool bConfig) + : QWidget(parent) +{ + setupUi(this); + m_client = client; + m_bConfig = bConfig; + + if (m_bConfig){ + QTimer::singleShot(0, this, SLOT(changed())); + connect(chkNew, SIGNAL(toggled(bool)), this, SLOT(newToggled(bool))); + if (m_client->data.owner.Uin.toULong()){ + edtUin->setText(QString::number(m_client->data.owner.Uin.toULong())); + chkNew->setChecked(false); + edtPasswd->setText(m_client->getPassword()); +/* }else if(core->getRegNew()) { + * edtUin->setText(core->getICQUIN()); + * edtPasswd->setText(core->getICQPassword()); + */ + }else{ + chkNew->setChecked(true); + } + //FIXME: we will have to do something when UIN is greater than signed int + edtUin->setValidator(new QIntValidator(1000, 0x7FFFFFFF, edtUin)); + connect(edtUin, SIGNAL(textChanged(const QString&)), this, SLOT(changed(const QString&))); + connect(edtPasswd, SIGNAL(textChanged(const QString&)), this, SLOT(changed(const QString&))); + }else{ + tabConfig->removeTab(tabConfig->indexOf(tabICQ)); + } + edtServer->setText(m_client->getServer()); + edtPort->setValue(m_client->getPort()); + edtMinPort->setValue(m_client->getMinPort()); + edtMaxPort->setValue(m_client->getMaxPort()); + connect(edtServer, SIGNAL(textChanged(const QString&)), this, SLOT(changed(const QString&))); + connect(edtPort, SIGNAL(valueChanged(const QString&)), this, SLOT(changed(const QString&))); + cmbFormat->addItem(i18n("RTF")); + cmbFormat->addItem(i18n("UTF")); + cmbFormat->addItem(i18n("Plain text")); + cmbFormat->setCurrentIndex(client->getSendFormat()); + chkPlugins->setChecked(client->getDisablePlugins()); + chkUpdate->setChecked(client->getDisableAutoUpdate()); + chkAutoReply->setChecked(client->getDisableAutoReplyUpdate()); + chkTyping->setChecked(client->getDisableTypingNotification()); + chkInvisible->hide(); + edtInvisible->hide(); + lblInvisible->hide(); + lblInvisible2->hide(); + chkDND->setChecked(client->getAcceptInDND()); + chkOccupied->setChecked(client->getAcceptInOccupied()); + chkHTTP->setChecked(client->getUseHTTP()); + connect(chkAuto, SIGNAL(toggled(bool)), this, SLOT(autoToggled(bool))); + connect(chkInvisible, SIGNAL(toggled(bool)), this, SLOT(invisibleToggled(bool))); + chkAuto->setChecked(client->getAutoHTTP()); + chkKeepAlive->setChecked(client->getKeepAlive()); + chkMediaSense->setChecked(client->getMediaSense()); + cmbAck->setCurrentIndex(client->getAckMode()); +} + +void ICQConfig::autoToggled(bool bState) +{ + chkHTTP->setEnabled(!bState); +} + +void ICQConfig::invisibleToggled(bool bState) +{ + lblInvisible->setEnabled(bState); + lblInvisible2->setEnabled(bState); + edtInvisible->setEnabled(bState); +} + +void ICQConfig::apply(Client*, void*) +{ +} + +void ICQConfig::apply() +{ + if (m_bConfig){ + m_client->setUin(edtUin->text().toULong()); + m_client->setPassword(edtPasswd->text()); + } + m_client->setServer(edtServer->text()); + m_client->setPort(edtPort->text().toUShort()); + m_client->setMinPort(edtMinPort->text().toUShort()); + m_client->setMaxPort(edtMaxPort->text().toUShort()); + m_client->setSendFormat(cmbFormat->currentIndex()); + m_client->setDisablePlugins(chkPlugins->isChecked()); + m_client->setDisableAutoUpdate(chkUpdate->isChecked()); + m_client->setDisableAutoReplyUpdate(chkAutoReply->isChecked()); + m_client->setDisableTypingNotification(chkTyping->isChecked()); + m_client->setAcceptInDND(chkDND->isChecked()); + m_client->setAcceptInOccupied(chkOccupied->isChecked()); + m_client->setUseHTTP(chkHTTP->isChecked()); + m_client->setAutoHTTP(chkAuto->isChecked()); + m_client->setKeepAlive(chkKeepAlive->isChecked()); + m_client->setAckMode(cmbAck->currentIndex()); + m_client->setMediaSense(chkMediaSense->isChecked()); +} + +void ICQConfig::changed(const QString&) +{ + changed(); +} + +void ICQConfig::newToggled(bool bNew) +{ + if (bNew) + edtUin->setText(QString::null); + lblUin->setEnabled(!bNew); + edtUin->setEnabled(!bNew); +} + +void ICQConfig::changed() +{ + bool bOK = true; + if (!chkNew->isChecked()) + bOK = (edtUin->text().toLong() > 1000); + bOK = bOK && !edtPasswd->text().isEmpty() && + !edtServer->text().isEmpty() && + edtPort->text().toUShort(); + emit okEnabled(bOK); +} + +// vim: set expandtab: + + diff --git a/plugins/icq/icqconfig.h b/plugins/icq/icqconfig.h new file mode 100644 index 0000000..566905f --- /dev/null +++ b/plugins/icq/icqconfig.h @@ -0,0 +1,47 @@ +/*************************************************************************** + icqconfig.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _ICQCONFIG_H +#define _ICQCONFIG_H + +#include "ui_icqconfigbase.h" +#include "icqclient.h" + +class ICQConfig : public QWidget, public Ui::ICQConfigBase +{ + Q_OBJECT +public: + ICQConfig(QWidget *parent, ICQClient *client, bool bConfig); + CorePlugin *core; +signals: + void okEnabled(bool); +public slots: + void apply(); + void apply(SIM::Client*, void*); +protected slots: + void changed(); + void changed(const QString&); + void newToggled(bool); + void autoToggled(bool); + void invisibleToggled(bool); +protected: + bool m_bConfig; + ICQClient *m_client; +}; + +#endif + diff --git a/plugins/icq/icqconfigbase.ui b/plugins/icq/icqconfigbase.ui new file mode 100644 index 0000000..42fbd48 --- /dev/null +++ b/plugins/icq/icqconfigbase.ui @@ -0,0 +1,509 @@ + + + ICQConfigBase + + + + 0 + 0 + 461 + 349 + + + + Form1 + + + + 11 + + + + + 0 + + + + &ICQ + + + + 11 + + + + + Password: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + QLineEdit::Password + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + &Register new UIN + + + + + + + UIN: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + + &Network + + + + 11 + + + + + 1 + + + 65535 + + + + + + + &Automatically use HTTP polling if proxy required + + + + + + + Use &HTTP polling + + + + + + + QFrame::HLine + + + QFrame::Sunken + + + + + + + Server: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Port: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + + + 0 + 0 + + + + Port range for direct connections: + + + false + + + + + + + 1024 + + + 65534 + + + + + + + 1024 + + + 65534 + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + + + 0 + 0 + + + + Note: For HTTP-polling using proxy settings for HTTP + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + false + + + + + + + &Keep-alive connection + + + + + + + Activate Network &Media Sense + + + + + + + + &Options + + + + 11 + + + + + Automatically check &invisible + + + + + + + Send format: + + + false + + + + + + + + 0 + 0 + + + + + + + + + + Send message: + + + false + + + + + + + + 0 + 0 + + + + + No wait ack + + + + + Wait ack from server + + + + + Wait ack from client + + + + + + + + + + Accept in &occupied mode + + + + + + + Accept in &DND mode + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + For decrease traffic you can: + + + false + + + + + + + Disable answer on phonebook and &picture requests + + + + + + + Disable automatically &request autoreply on change status + + + + + + + Disable automatically &update user info + + + + + + + Disable &typing notification + + + + + + + + + Check invisible every + + + false + + + + + + + 5 + + + 999 + + + + + + + minutes + + + false + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + + + + + + chkNew + edtUin + edtPasswd + edtServer + edtPort + chkHTTP + chkAuto + chkKeepAlive + edtMaxPort + cmbFormat + cmbAck + chkDND + chkOccupied + chkInvisible + edtInvisible + chkPlugins + chkAutoReply + chkUpdate + chkTyping + + + + diff --git a/plugins/icq/icqdirect.cpp b/plugins/icq/icqdirect.cpp new file mode 100644 index 0000000..dbd6283 --- /dev/null +++ b/plugins/icq/icqdirect.cpp @@ -0,0 +1,3039 @@ +/*************************************************************************** + icqdirect.cpp - description + ------------------- + begin : Sun Mar 10 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + + +#include "icqclient.h" +#include "icqmessage.h" +#include "icqdirect.h" +#include "contacts/contact.h" + +#include "core_events.h" + +#ifdef WIN32 +#include +#else +#include +#include +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" + +using namespace std; +using namespace SIM; + +const unsigned short TCP_START = 0x07EE; +const unsigned short TCP_ACK = 0x07DA; +const unsigned short TCP_CANCEL = 0x07D0; + +const char FT_INIT = 0; +const char FT_INIT_ACK = 1; +const char FT_FILEINFO = 2; +const char FT_START = 3; +const char FT_SPEED = 5; +const char FT_DATA = 6; + +const unsigned DIRECT_TIMEOUT = 10; + +ICQListener::ICQListener(ICQClient *client) +{ + m_client = client; +} + +ICQListener::~ICQListener() +{ + if (m_client == NULL) + return; + m_client->m_listener = NULL; + m_client->data.owner.Port.asULong() = 0; +} + +bool ICQListener::accept(Socket *s, unsigned long ip) +{ + log(L_DEBUG, "Accept direct connection %s", qPrintable(QHostAddress(ip).toString())); + m_client->m_sockets.push_back(new DirectClient(s, m_client, ip)); + return false; +} + +void ICQListener::bind_ready(unsigned short port) +{ + m_client->data.owner.Port.asULong() = port; +} + +bool ICQListener::error(const QString &err) +{ + log(L_WARN, "ICQListener error: %s", qPrintable(err)); + m_client->m_listener = NULL; + m_client->data.owner.Port.asULong() = 0; + m_client = NULL; + return true; +} + +// ___________________________________________________________________________________________ + +DirectSocket::DirectSocket(Socket *s, ICQClient *client, unsigned long ip) +{ + m_socket = new ICQClientSocket(this); + m_socket->setSocket(s); + m_bIncoming = true; + m_client = client; + m_state = WaitInit; + m_version = 0; + m_data = NULL; + m_port = 0; + m_ip = ip; + init(); +} + +DirectSocket::DirectSocket(ICQUserData *data, ICQClient *client) +{ + m_socket = new ICQClientSocket(this); + m_bIncoming = false; + m_version = (char)(data->Version.toULong()); + m_client = client; + m_state = NotConnected; + m_data = data; + m_port = 0; + m_localPort = 0; + m_ip = 0; + init(); +} + +DirectSocket::~DirectSocket() +{ + if (m_socket) + delete m_socket; + removeFromClient(); +} + +void DirectSocket::timeout() +{ + if ((m_state != Logged) && m_socket) + login_timeout(); +} + +void DirectSocket::login_timeout() +{ + m_socket->error_state("Timeout direct connection"); + if (m_data) + m_data->bNoDirect.asBool() = true; +} + +void DirectSocket::removeFromClient() +{ + for (list::iterator it = m_client->m_sockets.begin(); it != m_client->m_sockets.end(); ++it){ + if (*it == this){ + m_client->m_sockets.erase(it); + break; + } + } +} + +void DirectSocket::init() +{ + if (!m_socket->created()) + m_socket->error_state("Connect error"); + m_nSequence = 0xFFFF; + m_socket->writeBuffer().init(0); + m_socket->readBuffer().init(2); + m_socket->readBuffer().packetStart(); + m_bHeader = true; +} + +unsigned long DirectSocket::Uin() +{ + if (m_data) + return m_data->Uin.toULong(); + return 0; +} + +unsigned short DirectSocket::localPort() +{ + return m_localPort; +} + +unsigned short DirectSocket::remotePort() +{ + return m_port; +} + +bool DirectSocket::error_state(const QString &error, unsigned) +{ + if ((m_state == ConnectIP1) || (m_state == ConnectIP2)){ + connect(); + return false; + } + if (!error.isEmpty()) + log(L_WARN, "Direct socket error %s", qPrintable(error)); + return true; +} + +void DirectSocket::connect() +{ + log(L_DEBUG, "DirectSocket::connect()"); + m_socket->writeBuffer().init(0); + m_socket->readBuffer().init(2); + m_socket->readBuffer().packetStart(); + m_bHeader = true; + if (m_port == 0){ + m_state = ConnectFail; + m_socket->error_state(I18N_NOOP("Connect to unknown port")); + return; + } + if (m_state == NotConnected){ + m_state = ConnectIP1; + unsigned long ip = get_ip(m_data->RealIP); + if (get_ip(m_data->IP) != get_ip(m_client->data.owner.IP)) + ip = 0; + if (ip){ + m_socket->connect(QHostAddress(ip).toString(), m_port, NULL); + return; + } + } + if (m_state == ConnectIP1){ + m_state = ConnectIP2; + unsigned long ip = get_ip(m_data->IP); + if ((ip == get_ip(m_client->data.owner.IP)) && (ip == get_ip(m_data->RealIP))) + ip = 0; + if (ip){ + m_socket->connect(QHostAddress(ip).toString(), m_port, m_client); + return; + } + } + m_state = ConnectFail; + m_socket->error_state(I18N_NOOP("Can't established direct connection")); +} + +void DirectSocket::reverseConnect(unsigned long ip, unsigned short port) +{ + if (m_state != NotConnected){ + log(L_WARN, "Bad state for reverse connect"); + return; + } + m_bIncoming = true; + m_state = ReverseConnect; + m_socket->connect(QHostAddress(ip).toString(), port, NULL); +} + +void DirectSocket::acceptReverse(Socket *s) +{ + if (m_state != WaitReverse){ + log(L_WARN, "Accept reverse in bad state"); + if (s) + delete s; + return; + } + if (s == NULL){ + m_socket->error_state("Reverse fail"); + return; + } + delete m_socket->socket(); + m_socket->setSocket(s); + m_socket->readBuffer().init(2); + m_socket->readBuffer().packetStart(); + m_bHeader = true; + m_state = WaitInit; + m_bIncoming = true; +} + +void DirectSocket::packet_ready() +{ + log(L_DEBUG, "DirectSocket::packet_ready()"); + if (m_bHeader){ + unsigned short size; + m_socket->readBuffer().unpack(size); + if (size){ + m_socket->readBuffer().add(size); + m_bHeader = false; + return; + } + } + if (m_state != Logged){ + ICQPlugin *plugin = static_cast(m_client->protocol()->plugin()); + EventLog::log_packet(m_socket->readBuffer(), false, plugin->ICQDirectPacket, QString::number((unsigned long)this)); + } + switch (m_state){ + case Logged:{ + processPacket(); + break; + } + case WaitAck:{ + unsigned short s1, s2; + m_socket->readBuffer().unpack(s1); + m_socket->readBuffer().unpack(s2); + if (s2 != 0){ + m_socket->error_state("Bad ack"); + return; + } + if (m_bIncoming){ + m_state = Logged; + connect_ready(); + }else{ + m_state = WaitInit; + } + break; + } + case WaitInit:{ + char cmd; + m_socket->readBuffer().unpack(cmd); + if ((unsigned char)cmd != 0xFF){ + m_socket->error_state("Bad direct init command"); + return; + } + m_socket->readBuffer().unpack(m_version); + if (m_version < 6){ + m_socket->error_state("Use old protocol"); + return; + } + m_socket->readBuffer().incReadPos(3); + unsigned long my_uin; + m_socket->readBuffer().unpack(my_uin); + if (my_uin != m_client->data.owner.Uin.toULong()){ + m_socket->error_state("Bad owner UIN"); + return; + } + m_socket->readBuffer().incReadPos(6); + unsigned long p_uin; + m_socket->readBuffer().unpack(p_uin); + if (m_data == NULL){ + Contact *contact; + m_data = m_client->findContact(p_uin, NULL, false, contact); + if ((m_data == NULL) || contact->getIgnore()){ + m_socket->error_state("User not found"); + return; + } + if ((m_client->getInvisible() && (m_data->VisibleId.toULong() == 0)) || + (!m_client->getInvisible() && m_data->InvisibleId.toULong())){ + m_socket->error_state("User not found"); + return; + } + } + if (p_uin != m_data->Uin.toULong()){ + m_socket->error_state("Bad sender UIN"); + return; + } + if (get_ip(m_data->RealIP) == 0) + set_ip(&m_data->RealIP, m_ip); + m_socket->readBuffer().incReadPos(13); + unsigned long sessionId; + m_socket->readBuffer().unpack(sessionId); + if (m_bIncoming){ + m_nSessionId = sessionId; + sendInitAck(); + sendInit(); + m_state = WaitAck; + }else{ + if (sessionId != m_nSessionId){ + m_socket->error_state("Bad session ID"); + return; + } + sendInitAck(); + m_state = Logged; + connect_ready(); + } + break; + } + default: + m_socket->error_state("Bad session ID"); + return; + } + if (m_socket == NULL){ + delete this; + return; + } + m_socket->readBuffer().init(2); + m_socket->readBuffer().packetStart(); + m_bHeader = true; +} + +void DirectSocket::sendInit() +{ + log(L_DEBUG, "DirectSocket::sendInit()"); + if (!m_bIncoming && (m_state != ReverseConnect)){ + if (m_data->DCcookie.toULong() == 0){ + m_socket->error_state("No direct info"); + return; + } + m_nSessionId = m_data->DCcookie.toULong(); + } + + m_socket->writeBuffer().packetStart(); + m_socket->writeBuffer().pack((unsigned short)((m_version >= 7) ? 0x0030 : 0x002c)); + m_socket->writeBuffer().pack('\xFF'); + m_socket->writeBuffer().pack((unsigned short)m_version); + m_socket->writeBuffer().pack((unsigned short)((m_version >= 7) ? 0x002b : 0x0027)); + m_socket->writeBuffer().pack(m_data->Uin.toULong()); + m_socket->writeBuffer().pack((unsigned short)0x0000); + m_socket->writeBuffer().pack(m_data->Port.toULong()); + m_socket->writeBuffer().pack(m_client->data.owner.Uin.toULong()); + m_socket->writeBuffer().pack(get_ip(m_client->data.owner.IP)); + m_socket->writeBuffer().pack(get_ip(m_client->data.owner.RealIP)); + m_socket->writeBuffer().pack((char)0x04); + m_socket->writeBuffer().pack(m_data->Port.toULong()); + m_socket->writeBuffer().pack(m_nSessionId); + m_socket->writeBuffer().pack(0x00000050L); + m_socket->writeBuffer().pack(0x00000003L); + if (m_version >= 7) + m_socket->writeBuffer().pack(0x00000000L); + ICQPlugin *plugin = static_cast(m_client->protocol()->plugin()); + EventLog::log_packet(m_socket->writeBuffer(), true, plugin->ICQDirectPacket, QString::number((unsigned long)this)); + m_socket->write(); +} + +void DirectSocket::sendInitAck() +{ + log(L_DEBUG, "DirectSocket::sendInitAck()"); + m_socket->writeBuffer().packetStart(); + m_socket->writeBuffer().pack((unsigned short)0x0004); + m_socket->writeBuffer().pack((unsigned short)0x0001); + m_socket->writeBuffer().pack((unsigned short)0x0000); + ICQPlugin *plugin = static_cast(m_client->protocol()->plugin()); + EventLog::log_packet(m_socket->writeBuffer(), true, plugin->ICQDirectPacket, QString::number((unsigned long)this)); + m_socket->write(); +} + +void DirectSocket::connect_ready() +{ + log(L_DEBUG, "DirectSocket::connect_ready()"); + QTimer::singleShot(DIRECT_TIMEOUT * 1000, this, SLOT(timeout())); + if (m_bIncoming){ + if (m_state == ReverseConnect) + m_state = WaitInit; + }else{ + sendInit(); + m_state = WaitAck; + } + m_socket->readBuffer().init(2); + m_socket->readBuffer().packetStart(); + m_bHeader = true; +} + +// ___________________________________________________________________________________________ + +static unsigned char client_check_data[] = + { + "As part of this software beta version Mirabilis is " + "granting a limited access to the ICQ network, " + "servers, directories, listings, information and databases (\"" + "ICQ Services and Information\"). The " + "ICQ Service and Information may databases (\"" + "ICQ Services and Information\"). The " + "ICQ Service and Information may\0" + }; + +DirectClient::DirectClient(Socket *s, ICQClient *client, unsigned long ip) + : DirectSocket(s, client, ip) +{ + m_channel = PLUGIN_NULL; + m_state = WaitLogin; + m_ssl = NULL; +} + +DirectClient::DirectClient(ICQUserData *data, ICQClient *client, unsigned channel) + : DirectSocket(data, client) +{ + m_state = None; + m_channel = channel; + m_port = (unsigned short)(data->Port.toULong()); + m_ssl = NULL; +} + +DirectClient::~DirectClient() +{ + error_state(QString::null, 0); + switch (m_channel){ + case PLUGIN_NULL: + if (m_data && (m_data->Direct.object() == this)) + m_data->Direct.clear(); + break; + case PLUGIN_INFOxMANAGER: + if (m_data && (m_data->DirectPluginInfo.object() == this)) + m_data->DirectPluginInfo.clear(); + break; + case PLUGIN_STATUSxMANAGER: + if (m_data && (m_data->DirectPluginStatus.object() == this)) + m_data->DirectPluginStatus.clear(); + break; + } + secureStop(false); +} + +bool DirectClient::isSecure() +{ + return m_ssl && m_ssl->connected(); +} + +void DirectClient::processPacket() +{ + log(L_DEBUG, "DirectSocket::processPacket()"); + switch (m_state){ + case None: + m_socket->error_state("Bad state process packet"); + return; + case WaitInit2: + if (m_bIncoming){ + ICQPlugin *plugin = static_cast(m_client->protocol()->plugin()); + EventLog::log_packet(m_socket->readBuffer(), false, plugin->ICQDirectPacket, QString::number((unsigned long)this)); + if (m_version < 8){ + if (m_data->Direct.object()){ + m_socket->error_state("Direct connection already established"); + return; + } + m_state = Logged; + processMsgQueue(); + break; + } + plugin = static_cast(m_client->protocol()->plugin()); + EventLog::log_packet(m_socket->readBuffer(), false, plugin->ICQDirectPacket, QString::number((unsigned long)this)); + m_socket->readBuffer().incReadPos(13); + char p[16]; + m_socket->readBuffer().unpack(p, 16); + for (m_channel = 0; m_channel <= PLUGIN_NULL; m_channel++){ + if (!memcmp(m_client->plugins[m_channel], p, 16)) + break; + } + removeFromClient(); + switch (m_channel){ + case PLUGIN_INFOxMANAGER: { + DirectClient *dc = dynamic_cast(m_data->DirectPluginInfo.object()); + if (dc){ + if (dc->copyQueue(this)){ + delete dc; + m_data->DirectPluginInfo.setObject(this); + }else{ + m_socket->error_state("Plugin info connection already established"); + } + }else{ + m_data->DirectPluginInfo.setObject(this); + } + break; + } + case PLUGIN_STATUSxMANAGER: { + DirectClient *dc = dynamic_cast(m_data->DirectPluginStatus.object()); + if (dc){ + if (dc->copyQueue(this)){ + delete dc; + m_data->DirectPluginStatus.setObject(this); + }else{ + m_socket->error_state("Plugin status connection already established"); + } + }else{ + m_data->DirectPluginStatus.setObject(this); + } + break; + } + case PLUGIN_NULL: { + DirectClient *dc = dynamic_cast(m_data->Direct.object()); + if (dc){ + if (dc->copyQueue(this)){ + delete dc; + m_data->Direct.setObject(this); + }else{ + m_socket->error_state("Direct connection already established"); + } + }else{ + m_data->Direct.setObject(this); + } + break; + } + default: + m_socket->error_state("Unknown direct channel"); + return; + } + sendInit2(); + } + m_state = Logged; + processMsgQueue(); + return; + default: + break; + } + unsigned long hex, key, B1, M1; + unsigned int i; + unsigned char X1, X2, X3; + + unsigned int correction = 2; + if (m_version >= 7) + correction++; + + unsigned int size = m_socket->readBuffer().size() - correction; + if (m_version >= 7) m_socket->readBuffer().incReadPos(1); + + unsigned long check; + m_socket->readBuffer().unpack(check); + + // main XOR key + key = 0x67657268 * size + check; + + unsigned char *p = (unsigned char*)m_socket->readBuffer().data(m_socket->readBuffer().readPos()-4); + for(i=4; i<(size+3)/4; i+=4) { + hex = key + client_check_data[i&0xFF]; + p[i] ^= hex&0xFF; + p[i+1] ^= (hex>>8) & 0xFF; + p[i+2] ^= (hex>>16) & 0xFF; + p[i+3] ^= (hex>>24) & 0xFF; + } + + B1 = (p[4] << 24) | (p[6] << 16) | (p[4] <<8) | (p[6]<<0); + + // special decryption + B1 ^= check; + + // validate packet + M1 = (B1 >> 24) & 0xFF; + if(M1 < 10 || M1 >= size){ + m_socket->error_state("Decrypt packet failed"); + return; + } + + X1 = (unsigned char)(p[M1] ^ 0xFF); + if(((B1 >> 16) & 0xFF) != X1){ + m_socket->error_state("Decrypt packet failed"); + return; + } + + X2 = (unsigned char)((B1 >> 8) & 0xFF); + if(X2 < 220) { + X3 = (unsigned char)(client_check_data[X2] ^ 0xFF); + if((B1 & 0xFF) != X3){ + m_socket->error_state("Decrypt packet failed"); + return; + } + } + ICQPlugin *icq_plugin = static_cast(m_client->protocol()->plugin()); + EventLog::log_packet(m_socket->readBuffer(), false, icq_plugin->ICQDirectPacket, name()); + + m_socket->readBuffer().setReadPos(2); + if (m_version >= 7){ + char startByte; + m_socket->readBuffer().unpack(startByte); + if (startByte != 0x02){ + m_socket->error_state("Bad start byte"); + return; + } + } + unsigned long checksum; + m_socket->readBuffer().unpack(checksum); + unsigned short command; + m_socket->readBuffer().unpack(command); + m_socket->readBuffer().incReadPos(2); + unsigned short seq; + m_socket->readBuffer().unpack(seq); + m_socket->readBuffer().incReadPos(12); + + unsigned short type, ackFlags, msgFlags; + m_socket->readBuffer().unpack(type); + m_socket->readBuffer().unpack(ackFlags); + m_socket->readBuffer().unpack(msgFlags); + QByteArray msg_str; + m_socket->readBuffer() >> msg_str; + Message *m; + switch (command){ + case TCP_START: + switch (type){ + case ICQ_MSGxAR_AWAY: + case ICQ_MSGxAR_OCCUPIED: + case ICQ_MSGxAR_NA: + case ICQ_MSGxAR_DND: + case ICQ_MSGxAR_FFC:{ + unsigned req_status = STATUS_AWAY; + switch (type){ + case ICQ_MSGxAR_OCCUPIED: + req_status = STATUS_OCCUPIED; + break; + case ICQ_MSGxAR_NA: + req_status = STATUS_NA; + break; + case ICQ_MSGxAR_DND: + req_status = STATUS_DND; + break; + case ICQ_MSGxAR_FFC: + req_status = STATUS_FFC; + break; + } + ar_request req; + req.screen = m_client->screen(m_data); + req.type = type; + req.flags = msgFlags; + req.id.id_l = seq; + req.id1 = 0; + req.id2 = 0; + req.bDirect = true; + m_client->arRequests.push_back(req); + + Contact *contact = NULL; + m_client->findContact(m_client->screen(m_data), NULL, false, contact); + ARRequest ar; + ar.contact = contact; + ar.param = &m_client->arRequests.back(); + ar.receiver = m_client; + ar.status = req_status; + EventARRequest(&ar).process(); + return; + } + case ICQ_MSGxSECURExOPEN: + case ICQ_MSGxSECURExCLOSE: + msg_str = NULL; + msg_str = "1"; + sendAck(seq, type, msgFlags, msg_str); + if (type == ICQ_MSGxSECURExOPEN){ + secureListen(); + }else{ + secureStop(true); + } + return; + } + if (m_channel == PLUGIN_NULL){ + MessageId id; + id.id_l = seq; + m = m_client->parseMessage(type, m_client->screen(m_data), msg_str, m_socket->readBuffer(), id, 0); + if (m == NULL){ + m_socket->error_state("Start without message"); + return; + } + unsigned flags = m->getFlags() | MESSAGE_RECEIVED | MESSAGE_DIRECT; + if (isSecure()) + flags |= MESSAGE_SECURE; + m->setFlags(flags); + bool bAccept = true; + switch (m_client->getStatus()){ + case STATUS_DND: + if (!m_client->getAcceptInDND()) + bAccept = false; + break; + case STATUS_OCCUPIED: + if (!m_client->getAcceptInOccupied()) + bAccept = false; + break; + } + if (msgFlags & (ICQ_TCPxMSG_URGENT | ICQ_TCPxMSG_LIST)) + bAccept = true; + if (bAccept){ + if (msgFlags & ICQ_TCPxMSG_URGENT) + m->setFlags(m->getFlags() | MESSAGE_URGENT); + if (msgFlags & ICQ_TCPxMSG_LIST) + m->setFlags(m->getFlags() | MESSAGE_LIST); + if (m_client->messageReceived(m, m_client->screen(m_data))) + sendAck(seq, type, msgFlags); + }else{ + sendAck(seq, type, ICQ_TCPxMSG_AUTOxREPLY); + delete m; + } + }else{ + plugin p; //Fixme: Local declaration of 'p' hides declaration of the same name in outer scope, see previous declaration at line '609' + m_socket->readBuffer().unpack((char*)p, sizeof(p)); + unsigned plugin_index; + for (plugin_index = 0; plugin_index < PLUGIN_NULL; plugin_index++){ + if (!memcmp(p, m_client->plugins[plugin_index], sizeof(p))) + break; + } + ICQBuffer info; + unsigned short type = 1; //Fixme: Local declaration of 'type' hides declaration of the same name in outer scope, see previous declaration at line '665' + switch (plugin_index){ + case PLUGIN_FILESERVER: + case PLUGIN_FOLLOWME: + case PLUGIN_ICQPHONE: + type = 2; + case PLUGIN_PHONEBOOK: + case PLUGIN_PICTURE: + case PLUGIN_QUERYxINFO: + case PLUGIN_QUERYxSTATUS: + m_client->pluginAnswer(plugin_index, m_data->Uin.toULong(), info); + startPacket(TCP_ACK, seq); + m_socket->writeBuffer().pack(type); + m_socket->writeBuffer() << 0x00000000L + << (char)1 + << type; + m_socket->writeBuffer().pack(info.data(0), info.size()); + sendPacket(); + break; + default: + log(L_WARN, "Unknwon direct plugin request %u", plugin_index); + break; + } + } + break; + case TCP_CANCEL: + case TCP_ACK: { + log(L_DEBUG, "Ack %X %X", ackFlags, msgFlags); + bool itDeleted = false; + QList::iterator it; + for (it = m_queue.begin(); it != m_queue.end(); ++it){ + if (it->seq != seq) + continue; + if (it->msg == NULL){ + if (it->type == PLUGIN_AR){ + Contact *contact = NULL; + m_client->findContact(m_client->screen(m_data), NULL, false, contact); + m_data->AutoReply.str() = getContacts()->toUnicode(contact,msg_str); + m_queue.erase(it); + itDeleted = true; + break; + } + unsigned plugin_index = it->type; + switch (plugin_index){ + case PLUGIN_FILESERVER: + case PLUGIN_FOLLOWME: + case PLUGIN_ICQPHONE: + m_socket->readBuffer().incReadPos(-3); + break; + case PLUGIN_QUERYxSTATUS: + m_socket->readBuffer().incReadPos(9); + break; + } + m_client->parsePluginPacket(m_socket->readBuffer(), plugin_index, m_data, m_data->Uin.toULong(), true); + m_queue.erase(it); + itDeleted = true; + break; + } + Message *msg = it->msg; + if (command == TCP_CANCEL){ + EventMessageCancel(msg).process(); + delete msg; + break; + } + MessageId id; + id.id_l = seq; + Message *m = m_client->parseMessage(type, m_client->screen(m_data), msg_str, m_socket->readBuffer(), id, 0); //Fixme: Local declaration of 'm' hides declaration of the same name in outer scope, see previous declaration at line '671' + switch (msg->type()){ + case MessageCloseSecure: + secureStop(true); + break; + case MessageOpenSecure: + if (msg_str.isEmpty()){ + msg->setError(I18N_NOOP("Other side does not support the secure connection")); + }else{ + secureConnect(); + } + return; + case MessageFile: + if (m == NULL){ + m_socket->error_state("Ack without message"); + return; + } + if (ackFlags){ + if (msg_str.isEmpty()){ + msg->setError(I18N_NOOP("Send message fail")); + }else{ + QString err = getContacts()->toUnicode(m_client->getContact(m_data), msg_str); + msg->setError(err); + } + EventMessageSent(msg).process(); + m_queue.erase(it); + delete msg; + }else{ + if (m->type() != MessageICQFile){ + m_socket->error_state("Bad message type in ack file"); + return; + } + ICQFileTransfer *ft = new ICQFileTransfer(static_cast(msg), m_data, m_client); + EventMessageAcked(msg).process(); + m_queue.erase(it); + m_client->m_processMsg.push_back(msg); + ft->connect(static_cast(m)->getPort()); + } + return; + } + unsigned flags = msg->getFlags() | MESSAGE_DIRECT; + if (isSecure()) + flags |= MESSAGE_SECURE; + if (m_client->snacICBM()->ackMessage(msg, ackFlags, msg_str)){ + if ((msg->getFlags() & MESSAGE_NOHISTORY) == 0){ + if (msg->type() == MessageGeneric){ + Message m; //Fixme: Local declaration of 'm' hides declaration of the same name in outer scope, see previous declaration at line '842' + m.setContact(msg->contact()); + m.setClient(msg->client()); + if (it->type == CAP_RTF){ + m.setText(m_client->removeImages(msg->getRichText(), true)); + flags |= MESSAGE_RICHTEXT; + }else{ + m.setText(msg->getPlainText()); + } + m.setFlags(flags); + if (msg->getBackground() != msg->getForeground()){ + m.setForeground(msg->getForeground()); + m.setBackground(msg->getBackground()); + } + EventSent(&m).process(); + }else if ((msg->type() != MessageOpenSecure) && (msg->type() != MessageCloseSecure)){ + msg->setFlags(flags); + EventSent(msg).process(); + } + } + } + EventMessageSent(msg).process(); + m_queue.erase(it); + delete msg; + break; + } + if (!itDeleted && (m_queue.size() == 0 || it == m_queue.end())){ + list::iterator it; //Fixme: Local declaration of 'it' hides declaration of the same name in outer scope, see previous declaration at line '805' + for (it = m_client->m_acceptMsg.begin(); it != m_client->m_acceptMsg.end(); ++it){ + QString name = m_client->dataName(m_data); + Message *msg = *it; + if ((msg->getFlags() & MESSAGE_DIRECT) && (!msg->client().isEmpty()) && (name == msg->client())){ + bool bFound = false; + switch (msg->type()){ + case MessageICQFile: + if (static_cast(msg)->getID_L() == seq) + bFound = true; + break; + } + if (bFound){ + m_client->m_acceptMsg.erase(it); + EventMessageDeleted(msg).process(); + delete msg; + break; + } + } + if (it == m_client->m_acceptMsg.end()) + log(L_WARN, "Message for ACK not found??"); + } + } + break; + } + default: + m_socket->error_state("Unknown TCP command"); + } +} + +bool DirectClient::copyQueue(DirectClient *to) +{ + if (m_state == Logged) + return false; + to->m_queue = m_queue; + m_queue.clear(); + return true; +} + +void DirectClient::connect_ready() +{ + log(L_DEBUG, "DirectSocket::connect_ready()"); + if (m_state == None){ + m_state = WaitLogin; + DirectSocket::connect_ready(); + return; + } + if (m_state == SSLconnect){ + for (QList::iterator it = m_queue.begin(); it != m_queue.end(); ++it){ + SendDirectMsg &sm = *it; + if ((sm.msg == NULL) || (sm.msg->type() != MessageOpenSecure)) + continue; + EventMessageSent(sm.msg).process(); + delete sm.msg; + m_queue.erase(it); + break; + } + m_state = Logged; + Contact *contact; + if (m_client->findContact(m_client->screen(m_data), NULL, false, contact)){ + EventContact e(contact, EventContact::eStatus);; + e.process(); + } + return; + } + if (m_state == SSLconnect){ + for (QList::iterator it = m_queue.begin(); it != m_queue.end(); ++it){ + SendDirectMsg &sm = *it; + if ((sm.msg == NULL) || (sm.msg->type() != MessageOpenSecure)) + continue; + EventMessageSent(sm.msg).process(); + delete sm.msg; + m_queue.erase(it); + break; + } + m_state = Logged; + Contact *contact; + if (m_client->findContact(m_client->screen(m_data), NULL, false, contact)){ + EventContact e(contact, EventContact::eStatus);; + e.process(); + } + return; + } + if (m_bIncoming){ + Contact *contact; + m_data = m_client->findContact(m_client->screen(m_data), NULL, false, contact); + if ((m_data == NULL) || contact->getIgnore()){ + m_socket->error_state("Connection from unknown user"); + return; + } + m_state = WaitInit2; + }else{ + if (m_version >= 7){ + sendInit2(); + m_state = WaitInit2; + }else{ + m_state = Logged; + processMsgQueue(); + } + } +} + +void DirectClient::sendInit2() +{ + log(L_DEBUG, "DirectSocket::sendInit2()"); + m_socket->writeBuffer().packetStart(); + m_socket->writeBuffer().pack((unsigned short)0x0021); + m_socket->writeBuffer().pack((char) 0x03); + m_socket->writeBuffer().pack(0x0000000AL); + m_socket->writeBuffer().pack(0x00000001L); + m_socket->writeBuffer().pack(m_bIncoming ? 0x00000001L : 0x00000000L); + const plugin &p = m_client->plugins[m_channel]; + m_socket->writeBuffer().pack((const char*)p, 8); + if (m_bIncoming) { + m_socket->writeBuffer().pack(0x00040001L); + m_socket->writeBuffer().pack((const char*)p + 8, 8); + } else { + m_socket->writeBuffer().pack((const char*)p + 8, 8); + m_socket->writeBuffer().pack(0x00040001L); + } + ICQPlugin *plugin = static_cast(m_client->protocol()->plugin()); + EventLog::log_packet(m_socket->writeBuffer(), true, plugin->ICQDirectPacket, name()); + m_socket->write(); +} + +bool DirectClient::error_state(const QString &_err, unsigned code) +{ + //Fixme: Dereferencing NULL pointer 'm_data': Lines: 1045, 1046, 1048, 1058, 1059, 1060, 1061, 1062, 1069 + QString err = _err; + if (!err.isEmpty() && !DirectSocket::error_state(err, code)) + return false; + if (m_data && (m_port == m_data->Port.toULong())){ + switch (m_state){ + case ConnectIP1: + case ConnectIP2: + m_data->bNoDirect.asBool() = true; + break; + default: + break; + } + } + if (err.isEmpty()) + err = I18N_NOOP("Send message fail"); + for (QList::iterator it = m_queue.begin(); it != m_queue.end(); ++it){ + SendDirectMsg &sm = *it; + if (sm.msg){ + if (!m_client->snacICBM()->sendThruServer(sm.msg, m_data)){ + sm.msg->setError(err); + EventMessageSent(sm.msg).process(); + delete sm.msg; + } + }else{ + m_client->addPluginInfoRequest(m_data->Uin.toULong(), sm.type); + } + } + m_queue.clear(); + return true; +} + +void DirectClient::sendAck(unsigned short seq, unsigned short type, unsigned short flags, + const char *msg, unsigned short status, Message *m) +{ + log(L_DEBUG, "DirectSocket::sendAck()"); + bool bAccept = true; + if (status == ICQ_TCPxACK_ACCEPT){ + switch (m_client->getStatus()){ + case STATUS_AWAY: + status = ICQ_TCPxACK_AWAY; + break; + case STATUS_OCCUPIED: + bAccept = false; + status = ICQ_TCPxACK_OCCUPIED; + if (type == ICQ_MSGxAR_OCCUPIED){ + status = ICQ_TCPxACK_OCCUPIEDxCAR; + bAccept = true; + } + break; + case STATUS_NA: + status = ICQ_TCPxACK_NA; + break; + case STATUS_DND: + status = ICQ_TCPxACK_DND; + bAccept = false; + if (type == ICQ_MSGxAR_DND){ + status = ICQ_TCPxACK_DNDxCAR; + bAccept = true; + } + break; + default: + break; + } + } + if (!bAccept && (msg == NULL)){ + ar_request req; + req.screen = m_client->screen(m_data); + req.type = type; + req.ack = 0; + req.flags = flags; + req.id.id_l = seq; + req.id1 = 0; + req.id2 = 0; + req.bDirect = true; + m_client->arRequests.push_back(req); + + unsigned short req_status = STATUS_ONLINE; + if (m_data->Status.toULong() & ICQ_STATUS_DND){ + req_status = STATUS_DND; + }else if (m_data->Status.toULong() & ICQ_STATUS_OCCUPIED){ + req_status = STATUS_OCCUPIED; + }else if (m_data->Status.toULong() & ICQ_STATUS_NA){ + req_status = STATUS_NA; + }else if (m_data->Status.toULong() & ICQ_STATUS_AWAY){ + req_status = STATUS_AWAY; + }else if (m_data->Status.toULong() & ICQ_STATUS_FFC){ + req_status = STATUS_FFC; + } + + Contact *contact = NULL; + m_client->findContact(m_client->screen(m_data), NULL, false, contact); + ARRequest ar; + ar.contact = contact; + ar.param = &m_client->arRequests.back(); + ar.receiver = m_client; + ar.status = req_status; + EventARRequest(&ar).process(); + return; + } + + QByteArray message; + if (msg) + message = msg; + + startPacket(TCP_ACK, seq); + m_socket->writeBuffer().pack(type); + m_socket->writeBuffer().pack(status); + m_socket->writeBuffer().pack(flags); + m_socket->writeBuffer() << message; + bool bExt = false; + if (m){ + switch (m->type()){ + case MessageICQFile: + if (static_cast(m)->getExtended()){ + bExt = true; + ICQBuffer buf, msgBuf; + ICQBuffer b; + m_client->packExtendedMessage(m, buf, msgBuf, m_data); + b.pack((unsigned short)buf.size()); + b.pack(buf.data(0), buf.size()); + b.pack32(msgBuf); + m_socket->writeBuffer().pack(b.data(), b.size()); + } + break; + } + } + if (!bExt){ + m_socket->writeBuffer() + << 0x00000000L + << 0xFFFFFFFFL; + } + sendPacket(); +} + +void DirectClient::startPacket(unsigned short cmd, unsigned short seq) +{ + log(L_DEBUG, "DirectSocket::startPacket()"); + m_socket->writeBuffer().packetStart(); + m_socket->writeBuffer() + << (unsigned short)0; // size + if (m_version >= 7) + m_socket->writeBuffer() << (char)0x02; + if (seq == 0) + seq = --m_nSequence; + m_socket->writeBuffer() + << (unsigned long)0; // checkSum + m_socket->writeBuffer().pack(cmd); + m_socket->writeBuffer() + << (char) ((m_channel == PLUGIN_NULL) ? 0x0E : 0x12) + << (char) 0; + m_socket->writeBuffer().pack(seq); + m_socket->writeBuffer() + << (unsigned long)0 + << (unsigned long)0 + << (unsigned long)0; +} + +void DirectClient::sendPacket() +{ + log(L_DEBUG, "DirectSocket::sendPacket()"); + unsigned size = m_socket->writeBuffer().size() - m_socket->writeBuffer().packetStartPos() - 2; + unsigned char *p = (unsigned char*)(m_socket->writeBuffer().data(m_socket->writeBuffer().packetStartPos())); + p[0] = (unsigned char)(size & 0xFF); + p[1] = (unsigned char)((size >> 8) & 0xFF); + + ICQPlugin *plugin = static_cast(m_client->protocol()->plugin()); + EventLog::log_packet(m_socket->writeBuffer(), true, plugin->ICQDirectPacket, name()); + + unsigned long hex, key, B1, M1; + unsigned long i, check; + unsigned char X1, X2, X3; + + p += 2; + if (m_version >= 7){ + size--; + p++; + } + + // calculate verification data + M1 = (rand() % ((size < 255 ? size : 255)-10))+10; + X1 = (unsigned char)(p[M1] ^ 0xFF); + X2 = (unsigned char)(rand() % 220); + X3 = (unsigned char)(client_check_data[X2] ^ 0xFF); + + B1 = (p[4] << 24) | (p[6]<<16) | (p[4]<<8) | (p[6]); + + // calculate checkcode + check = (M1 << 24) | (X1 << 16) | (X2 << 8) | X3; + check ^= B1; + + *((unsigned long*)p) = check; + // main XOR key + key = 0x67657268 * size + check; + + // XORing the actual data + for(i=4; i<(size+3)/4; i+=4){ + hex = key + client_check_data[i & 0xFF]; + p[i] ^= hex & 0xFF; + p[i+1] ^= (hex>>8) & 0xFF; + p[i+2] ^= (hex>>16) & 0xFF; + p[i+3] ^= (hex>>24) & 0xFF; + } + m_socket->write(); +} + +void DirectClient::acceptMessage(Message *msg) +{ + log(L_DEBUG, "DirectSocket::acceptMessage()"); + unsigned short seq = 0; + switch (msg->type()){ + case MessageICQFile: + seq = (unsigned short)(static_cast(msg)->getID_L()); + sendAck(seq, static_cast(msg)->getExtended() ? ICQ_MSGxEXT : ICQ_MSGxFILE, 0, NULL, ICQ_TCPxACK_ACCEPT, msg); + break; + default: + log(L_WARN, "Unknown type for direct decline"); + } +} + +void DirectClient::declineMessage(Message *msg, const QString &reason) +{ + QByteArray r; + r = getContacts()->fromUnicode(m_client->getContact(m_data), reason); + unsigned short seq = 0; + switch (msg->type()){ + case MessageICQFile: + seq = (unsigned short)(static_cast(msg)->getID_L()); + sendAck(seq, static_cast(msg)->getExtended() ? ICQ_MSGxEXT : ICQ_MSGxFILE, 0, r, ICQ_TCPxACK_REFUSE, msg); + break; + default: + log(L_WARN, "Unknown type for direct decline"); + } +} + +bool DirectClient::sendMessage(Message *msg) +{ + SendDirectMsg sm; + sm.msg = msg; + sm.seq = 0; + sm.type = 0; + sm.icq_type = 0; + m_queue.push_back(sm); + processMsgQueue(); + return true; +} + +void packCap(ICQBuffer &b, const capability &c); + +void DirectClient::processMsgQueue() +{ + if (m_state != Logged) + return; + for (QList::iterator it = m_queue.begin(); it != m_queue.end();){ + SendDirectMsg &sm = *it; + if (sm.seq){ + ++it; + continue; + } + if (sm.msg){ + QByteArray message; + ICQBuffer &mb = m_socket->writeBuffer(); + unsigned short flags = ICQ_TCPxMSG_NORMAL; + if (sm.msg->getFlags() & MESSAGE_URGENT) + flags = ICQ_TCPxMSG_URGENT; + if (sm.msg->getFlags() & MESSAGE_LIST) + flags = ICQ_TCPxMSG_LIST; + switch (sm.msg->type()){ + case MessageGeneric: + startPacket(TCP_START, 0); + mb.pack((unsigned short)ICQ_MSGxMSG); + mb.pack(m_client->msgStatus()); + mb.pack(flags); + if ((sm.msg->getFlags() & MESSAGE_RICHTEXT) && + (m_client->getSendFormat() == 0) && + (m_client->hasCap(m_data, CAP_RTF))){ + QString text = sm.msg->getRichText(); + QString part; + message = m_client->createRTF(text, part, sm.msg->getForeground(), m_client->getContact(m_data), 0xFFFFFFFF); + sm.type = CAP_RTF; + }else if (m_client->hasCap(m_data, CAP_UTF) && + (m_client->getSendFormat() <= 1) && + ((sm.msg->getFlags() & MESSAGE_SECURE) == 0)){ + message = ICQClient::addCRLF(sm.msg->getPlainText()).toUtf8(); + sm.type = CAP_UTF; + }else{ + message = getContacts()->fromUnicode(m_client->getContact(m_data), sm.msg->getPlainText()); + EventSend e(sm.msg, message); + e.process(); + message = e.localeText(); + } + mb << message; + if (sm.msg->getBackground() == sm.msg->getForeground()){ + mb << 0x00000000L << 0xFFFFFF00L; + }else{ + mb << (sm.msg->getForeground() << 8) << (sm.msg->getBackground() << 8); + } + if (sm.type){ + mb << 0x26000000L; + packCap(mb, ICQClient::capabilities[sm.type]); + } + sendPacket(); + sm.seq = m_nSequence; + sm.icq_type = ICQ_MSGxMSG; + break; + case MessageFile: + case MessageUrl: + case MessageContacts: + case MessageOpenSecure: + case MessageCloseSecure: + startPacket(TCP_START, 0); + m_client->packMessage(mb, sm.msg, m_data, sm.icq_type, true); + sendPacket(); + sm.seq = m_nSequence; + break; + default: + sm.msg->setError(I18N_NOOP("Unknown message type")); + EventMessageSent(sm.msg).process(); + delete sm.msg; + m_queue.erase(it); + it = m_queue.begin(); + continue; + } + }else{ + if (sm.type == PLUGIN_AR){ + sm.icq_type = 0; + unsigned s = m_data->Status.toULong(); + if (s != ICQ_STATUS_OFFLINE){ + if (s & ICQ_STATUS_DND){ + sm.icq_type = ICQ_MSGxAR_DND; + }else if (s & ICQ_STATUS_OCCUPIED){ + sm.icq_type = ICQ_MSGxAR_OCCUPIED; + }else if (s & ICQ_STATUS_NA){ + sm.icq_type = ICQ_MSGxAR_NA; + }else if (s & ICQ_STATUS_AWAY){ + sm.icq_type = ICQ_MSGxAR_AWAY; + }else if (s & ICQ_STATUS_FFC){ + sm.icq_type = ICQ_MSGxAR_FFC; + } + } + if (sm.type == 0){ + m_queue.erase(it); + it = m_queue.begin(); + continue; + } + ICQBuffer &mb = m_socket->writeBuffer(); + startPacket(TCP_START, 0); + mb.pack(sm.icq_type); + mb.pack(m_client->msgStatus()); + mb.pack(ICQ_TCPxMSG_AUTOxREPLY); + mb << (char)1 << (unsigned short)0; + sendPacket(); + sm.seq = m_nSequence; + }else{ + ICQBuffer &mb = m_socket->writeBuffer(); + startPacket(TCP_START, 0); + mb.pack((unsigned short)ICQ_MSGxMSG); + mb.pack(m_client->msgStatus()); + mb.pack(ICQ_TCPxMSG_AUTOxREPLY); + mb.pack((unsigned short)1); + mb.pack((char)0); + mb.pack((char*)m_client->plugins[sm.type], sizeof(plugin)); + mb.pack((unsigned long)0); + sendPacket(); + sm.seq = m_nSequence; + } + } + ++it; + } +} + +bool DirectClient::cancelMessage(Message *msg) +{ + for (QList::iterator it = m_queue.begin(); it != m_queue.end(); ++it){ + if (it->msg == msg){ + if (it->seq){ + ICQBuffer &mb = m_socket->writeBuffer(); + startPacket(TCP_CANCEL, it->seq); + mb.pack((unsigned short)it->icq_type); + mb.pack((unsigned short)0); + mb.pack((unsigned short)0); + QByteArray message; + mb << message; + sendPacket(); + } + m_queue.erase(it); + return true; + } + } + return false; +} + +void DirectClient::addPluginInfoRequest(unsigned plugin_index) +{ + QList::ConstIterator it; + for (it = m_queue.constBegin(); it != m_queue.constEnd(); ++it){ + const SendDirectMsg &sm = *it; + if (sm.msg) + continue; + if (sm.type == plugin_index) + return; + } + SendDirectMsg sm; + sm.msg = NULL; + sm.seq = 0; + sm.type = plugin_index; + sm.icq_type = 0; + m_queue.push_back(sm); + processMsgQueue(); +} + +class ICQ_SSLClient : public SSLClient +{ +public: + ICQ_SSLClient(Socket *s) : SSLClient(s) {} +}; + + +void DirectClient::secureConnect() +{ + if (m_ssl != NULL) return; + m_ssl = new ICQ_SSLClient(m_socket->socket()); + m_socket->setSocket(m_ssl); + m_state = SSLconnect; + m_ssl->startEncryption(); +} + +void DirectClient::secureListen() +{ + if (m_ssl != NULL) + return; + m_ssl = new ICQ_SSLClient(m_socket->socket()); + m_socket->setSocket(m_ssl); + m_state = SSLconnect; +// m_ssl->accept(); +} + +void DirectClient::secureStop(bool bShutdown) +{ + if (m_ssl){ + if (bShutdown){ + m_ssl->close(); + } + m_socket->setSocket(m_ssl->socket(), false); + m_ssl->setSocket(NULL); + delete m_ssl; + m_ssl = NULL; + Contact *contact; + if (m_client->findContact(m_client->screen(m_data), NULL, false, contact)){ + EventContact e(contact, EventContact::eStatus);; + e.process(); + } + } +} + +QString DirectClient::name() +{ + if (m_data == NULL) + return QString::null; + m_name = QString::null; + switch (m_channel){ + case PLUGIN_NULL: + break; + case PLUGIN_INFOxMANAGER: + m_name = "Info."; + break; + case PLUGIN_STATUSxMANAGER: + m_name = "Status."; + break; + default: + m_name = "Unknown."; + } + m_name += QString::number(m_data->Uin.toULong()); + m_name += '.'; + m_name += QString::number((unsigned long)this); + return m_name; +} + +ICQFileTransfer::ICQFileTransfer(FileMessage *msg, ICQUserData *data, ICQClient *client) + : FileTransfer(msg), DirectSocket(data, client) +{ + m_state = None; + FileMessage::Iterator it(*msg); + m_nFiles = it.count(); + m_totalSize = msg->getSize(); +} + +ICQFileTransfer::~ICQFileTransfer() +{ +} + +void ICQFileTransfer::connect(unsigned short port) +{ + log(L_DEBUG, "ICQFileTransfer::connect()"); + m_port = port; + FileTransfer::m_state = FileTransfer::Connect; + if (m_notify) + m_notify->process(); + DirectSocket::connect(); +} + +void ICQFileTransfer::listen() +{ + FileTransfer::m_state = FileTransfer::Listen; + if (m_notify) + m_notify->process(); + bind(m_client->getMinPort(), m_client->getMaxPort(), m_client); +} + +void ICQFileTransfer::processPacket() +{ + log(L_DEBUG, "ICQFileTransfer::processPacket()"); + char cmd; + m_socket->readBuffer() >> cmd; + if (cmd != FT_DATA){ + ICQPlugin *plugin = static_cast(m_client->protocol()->plugin()); + EventLog::log_packet(m_socket->readBuffer(), false, plugin->ICQDirectPacket, QByteArray("File transfer")); + } + if (cmd == FT_SPEED){ + char speed; + m_socket->readBuffer().unpack(speed); + m_speed = speed; + return; + } + switch (m_state){ + case InitSend: + switch (cmd){ + case FT_INIT_ACK: + sendFileInfo(); + break; + case FT_START:{ + unsigned long pos, empty, speed, curFile; + m_socket->readBuffer().unpack(pos); + m_socket->readBuffer().unpack(empty); + m_socket->readBuffer().unpack(speed); + m_socket->readBuffer().unpack(curFile); + curFile--; + log(L_DEBUG, "Start send at %lu %lu", pos, curFile); + FileMessage::Iterator it(*m_msg); + if (curFile >= it.count()){ + m_socket->error_state("Bad file index"); + return; + } + while (curFile != m_nFile){ + if (!openFile()){ + m_socket->error_state("Can't open file"); + return; + } + } + if (m_file && !m_file->seek(pos)){ + m_socket->error_state("Can't set transfer position"); + return; + } + m_totalBytes += pos; + m_bytes = pos; + m_state = Send; + FileTransfer::m_state = FileTransfer::Write; + if (m_notify){ + m_notify->process(); + m_notify->transfer(true); + } + write_ready(); + break; + } + default: + log(L_WARN, "Bad init client command %X", cmd); + m_socket->error_state("Bad packet"); + } + break; + case WaitInit:{ + if (cmd != FT_INIT){ + m_socket->error_state("No init command"); + return; + } + unsigned long n; + m_socket->readBuffer().unpack(n); + m_socket->readBuffer().unpack(n); + m_nFiles = n; + m_socket->readBuffer().unpack(n); + m_totalSize = n; + m_msg->setSize(m_totalSize); + m_state = InitReceive; + setSpeed(m_speed); + startPacket(FT_INIT_ACK); + m_socket->writeBuffer().pack((unsigned long)m_speed); + QString uin = m_client->screen(&m_client->data.owner); + m_socket->writeBuffer() << uin; + sendPacket(); + FileTransfer::m_state = Negotiation; + if (m_notify) + m_notify->process(); + } + break; + case InitReceive:{ + initReceive(cmd); + break; + } + case Receive:{ + if (m_bytes < m_fileSize){ + if (cmd != FT_DATA){ + m_socket->error_state("Bad data command"); + return; + } + unsigned short size = (unsigned short)(m_socket->readBuffer().size() - m_socket->readBuffer().readPos()); + m_bytes += size; + m_totalBytes += size; + m_transferBytes += size; + if (size){ + if (m_file == NULL){ + m_socket->error_state("Write without file"); + return; + } + if (m_file->write(m_socket->readBuffer().data(m_socket->readBuffer().readPos()), size) != size){ + m_socket->error_state("Error write file"); + return; + } + } + } + if (m_bytes >= m_fileSize){ + if (m_nFile + 1 >= m_nFiles){ + log(L_DEBUG, "File transfer OK"); + FileTransfer::m_state = FileTransfer::Done; + if (m_notify) + m_notify->process(); + m_socket->error_state(QString::null); + return; + } + m_state = InitReceive; + } + if (m_notify) + m_notify->process(); + if (cmd != FT_DATA) + initReceive(cmd); + break; + } + + default: + log(L_WARN, "Bad state in process packet %u", m_state); + } +} + +void ICQFileTransfer::initReceive(char cmd) +{ + if (cmd != FT_FILEINFO){ + m_socket->error_state("Bad command in init receive"); + return; + } + string stdStrFileName; + char isDir; + m_socket->readBuffer() >> isDir >> stdStrFileName; + QByteArray qcfilename(stdStrFileName.c_str()); + QString fName = getContacts()->toUnicode(m_client->getContact(m_data), qcfilename); + + string stdStrDir; + unsigned long n; + m_socket->readBuffer() >> stdStrDir; + QByteArray dir(stdStrDir.c_str()); + m_socket->readBuffer().unpack(n); + if (m_notify) + m_notify->transfer(false); + if (!dir.isEmpty()) + fName = getContacts()->toUnicode(m_client->getContact(m_data), dir) + '/' + fName; + if (isDir) + fName += '/'; + m_state = Wait; + FileTransfer::m_state = FileTransfer::Read; + if (m_notify) + m_notify->createFile(fName, n, true); +} + +bool ICQFileTransfer::error(const QString &err) +{ + return error_state(err, 0); +} + +bool ICQFileTransfer::accept(Socket *s, unsigned long) +{ + log(L_DEBUG, "Accept file transfer"); + if (m_state == WaitReverse){ + acceptReverse(s); + }else{ + m_socket->setSocket(s); + m_bIncoming = true; + DirectSocket::m_state = DirectSocket::WaitInit; + init(); + } + return true; +} + +void ICQFileTransfer::bind_ready(unsigned short port) +{ + m_localPort = port; + if (m_state == WaitReverse){ + m_client->snacICBM()->requestReverseConnection(m_client->screen(m_data), this); + return; + } + m_state = Listen; + static_cast(m_msg)->setPort(port); + m_client->snacICBM()->accept(m_msg, m_data); +} + +void ICQFileTransfer::login_timeout() +{ + if (ICQClient::hasCap(m_data, CAP_DIRECT)){ + DirectSocket::m_state = DirectSocket::WaitReverse; + m_state = WaitReverse; + bind(m_client->getMinPort(), m_client->getMaxPort(), m_client); + return; + } + DirectSocket::login_timeout(); +} + +bool ICQFileTransfer::error_state(const QString &err, unsigned code) +{ + if (DirectSocket::m_state == DirectSocket::ConnectFail){ + if (ICQClient::hasCap(m_data, CAP_DIRECT)){ + login_timeout(); + return false; + } + } + if (!DirectSocket::error_state(err, code)) + return false; + if (FileTransfer::m_state != FileTransfer::Done){ + m_state = None; + FileTransfer::m_state = FileTransfer::Error; + m_msg->setError(err); + } + m_msg->m_transfer = NULL; + m_msg->setFlags(m_msg->getFlags() & ~MESSAGE_TEMP); + EventMessageSent(m_msg).process(); + return true; +} + +void ICQFileTransfer::connect_ready() +{ + log(L_DEBUG, "ICQFileTransfer::connect_ready()"); + if (m_state == None){ + m_state = WaitLogin; + DirectSocket::connect_ready(); + return; + } + if (m_state == WaitReverse){ + m_bIncoming = false; + m_state = WaitReverseLogin; + DirectSocket::connect_ready(); + return; + } + if (m_state == WaitReverseLogin) + m_bIncoming = true; + m_file = 0; + FileTransfer::m_state = FileTransfer::Negotiation; + if (m_notify) + m_notify->process(); + if (m_bIncoming){ + m_state = WaitInit; + }else{ + m_state = InitSend; + startPacket(FT_SPEED); + m_socket->writeBuffer().pack((unsigned long)m_speed); + sendPacket(true); + sendInit(); + } +} + +void ICQFileTransfer::sendInit() +{ + startPacket(FT_INIT); + m_socket->writeBuffer().pack((unsigned long)0); + m_socket->writeBuffer().pack((unsigned long)m_nFiles); // nFiles + m_socket->writeBuffer().pack((unsigned long)m_totalSize); // Total size + m_socket->writeBuffer().pack((unsigned long)m_speed); // speed + m_socket->writeBuffer() << QString::number(m_client->data.owner.Uin.toULong()).data(); + sendPacket(); + if ((m_nFiles == 0) || (m_totalSize == 0)) + m_socket->error_state(I18N_NOOP("No files for transfer")); +} + +void ICQFileTransfer::startPacket(char cmd) +{ + m_socket->writeBuffer().packetStart(); + m_socket->writeBuffer() << (unsigned short)0; + m_socket->writeBuffer() << cmd; +} + +void ICQFileTransfer::sendPacket(bool dump) +{ + unsigned long start_pos = m_socket->writeBuffer().packetStartPos(); + unsigned size = m_socket->writeBuffer().size() - start_pos - 2; + unsigned char *p = (unsigned char*)(m_socket->writeBuffer().data(start_pos)); + p[0] = (unsigned char)(size & 0xFF); + p[1] = (unsigned char)((size >> 8) & 0xFF); + if (dump){ + ICQPlugin *plugin = static_cast(m_client->protocol()->plugin()); + QString name = "FileTranfer"; + if (m_data){ + name += '.'; + name += QString::number(m_data->Uin.toULong()); + } + EventLog::log_packet(m_socket->writeBuffer(), true, plugin->ICQDirectPacket, name); + } + m_socket->write(); +} + +void ICQFileTransfer::setSpeed(unsigned speed) +{ + FileTransfer::setSpeed(speed); + switch (m_state){ + case InitSend: + case InitReceive: + case Send: + case Receive: + case Wait: + startPacket(FT_SPEED); + m_socket->writeBuffer().pack((unsigned long)m_speed); + sendPacket(true); + break; + default: + break; + } +} + +void ICQFileTransfer::write_ready() +{ + if (m_state != Send){ + DirectSocket::write_ready(); + return; + } + if (m_transfer){ + m_transferBytes += m_transfer; + m_transfer = 0; + if (m_notify) + m_notify->process(); + } + if (m_bytes >= m_fileSize){ + m_state = None; + m_state = InitSend; + sendFileInfo(); + if (m_notify) + m_notify->process(); + return; + } + QDateTime now(QDateTime::currentDateTime()); + if (now != m_sendTime){ + m_sendTime = now; + m_sendSize = 0; + } + if (m_sendSize > (m_speed << 18)){ + m_socket->pause(1); + return; + } + unsigned long tail = m_fileSize - m_bytes; + if (tail > 2048) tail = 2048; + startPacket(FT_DATA); + char buf[2048]; + int readn = m_file->read(buf, tail); + if (readn <= 0){ + m_socket->error_state("Read file error"); + return; + } + m_transfer = readn; + m_bytes += readn; + m_totalBytes += readn; + m_sendSize += readn; + m_socket->writeBuffer().pack(buf, readn); + sendPacket(false); +} + +void ICQFileTransfer::sendFileInfo() +{ + if (!openFile()){ + if (FileTransfer::m_state == FileTransfer::Done) + m_socket->error_state(QString::null); + if (m_notify) + m_notify->transfer(false); + return; + } + if (m_notify) + m_notify->transfer(false); + startPacket(FT_FILEINFO); + m_socket->writeBuffer().pack((char)(isDirectory() ? 1 : 0)); + QString fn = filename(); + QString dir; + int n = fn.lastIndexOf('/'); + if (n >= 0){ + dir = fn.left(n); + dir = dir.replace('/', '\\'); + fn = fn.mid(n); + } + QByteArray s1 = getContacts()->fromUnicode(m_client->getContact(m_data), fn); + QByteArray s2=""; + if (!dir.isEmpty()) + s2 = getContacts()->fromUnicode(m_client->getContact(m_data), dir); + string ssc1 = s1.data(); + string ssc2 = s2.data(); +//#ifdef __OS2__ // to make it compileable under OS/2 (gcc 3.3.5) + m_socket->writeBuffer() << ssc1.c_str() << ssc2.c_str(); +//#else +// m_socket->writeBuffer() << QString(ssc1) << QString(ssc2); +//#endif + m_socket->writeBuffer().pack((unsigned long)m_fileSize); + m_socket->writeBuffer().pack((unsigned long)0); + m_socket->writeBuffer().pack((unsigned long)m_speed); + sendPacket(); + if (m_notify) + m_notify->process(); +} + +void ICQFileTransfer::setSocket(ICQClientSocket *socket) +{ + if (m_socket) + delete m_socket; + m_socket = socket; + m_socket->setNotify(this); + m_state = WaitInit; + processPacket(); + if ((m_msg->getFlags() & MESSAGE_RECEIVED) == 0){ + m_state = InitSend; + sendInit(); + } + m_socket->readBuffer().init(2); + m_socket->readBuffer().packetStart(); + m_bHeader = true; + DirectSocket::m_state = DirectSocket::Logged; +} + +void ICQFileTransfer::startReceive(unsigned pos) +{ + if (m_state != Wait){ + log(L_WARN, "Start receive in bad state"); + return; + } + startPacket(FT_START); + if (pos > m_fileSize) + pos = m_fileSize; + m_bytes = pos; + m_totalBytes += pos; + m_socket->writeBuffer().pack((unsigned long)pos); + m_socket->writeBuffer().pack((unsigned long)0); + m_socket->writeBuffer().pack((unsigned long)m_speed); + m_socket->writeBuffer().pack((unsigned long)(m_nFile + 1)); + sendPacket(); + m_state = Receive; + if (m_notify) + m_notify->transfer(true); +} + +/////////////////////////////////////////// +// + +AIMFileTransfer::AIMFileTransfer(FileMessage *msg, ICQUserData *data, ICQClient *client) + : FileTransfer(msg) +{ + m_msg = msg; + m_client = client; + m_data = data; + m_ip = 0; + m_proxy = false; + m_proxyActive = true; + m_packetLength = 1000; + m_socket = new ICQClientSocket(this); + client->m_filetransfers.push_back(this); + log(L_DEBUG, "AIMFileTransfer::AIMFileTransfer: %p", this); +} + +AIMFileTransfer::~AIMFileTransfer() +{ + if(m_client) + { + for(std::list::iterator it = m_client->m_filetransfers.begin(); it != m_client->m_filetransfers.end(); ++it) + { + if((*it) == this) // FIXME make comparison by cookie + { + m_client->m_filetransfers.erase(it); + break; + } + } + } + delete m_socket; + log(L_DEBUG, "AIMFileTransfer::~AIMFileTransfer"); +} + +void AIMFileTransfer::requestFT() +{ + log(L_DEBUG, "AIMFileTransfer::requestFT m_stage = %d", m_stage); + log(L_DEBUG, "Description: %s", qPrintable(m_msg->getDescription())); + log(L_DEBUG, "filename: %s", qPrintable(filename())); + ICQBuffer b; + bool bWide = false; + for(int i = 0; i < (int)(filename().length()); i++) + { + if (filename()[i].unicode() > 0x7F) + { + bWide = true; + break; + } + } + QString charset = bWide ? "utf-8" : "us-ascii"; + + unsigned short this_port = (unsigned short)(m_proxy ? m_cookie2 : m_port); + + b << (unsigned short)0; + b << m_cookie.id_l << m_cookie.id_h; + b.pack((char*)m_client->capabilities[CAP_AIM_SENDFILE], sizeof(capability)); + b.tlv(0x0A, (unsigned short)m_stage); + b.tlv(0x0F); + b.tlv(0x03, (unsigned long)htonl(get_ip(m_client->data.owner.RealIP))); + b.tlv(0x04, (unsigned long)htonl(get_ip(m_client->data.owner.IP))); + b.tlv(0x05, this_port); + + this_port = ~(htons(m_port)); + b.tlv(0x17, this_port); + + unsigned long this_ip = m_ip; + if(m_ip == 0) + this_ip = htonl(get_ip(m_client->data.owner.RealIP)); + + b.tlv(0x02, this_ip); + this_ip = ~this_ip; + b.tlv(0x16, this_ip); + + if(m_proxy) + { + b.tlv(0x10); + } + ICQBuffer buf; + if(m_stage == 1) + { + if(files() == 1) + { + buf << ((unsigned short)0x0001) << ((unsigned short)0x0001); + } + else + { + buf << ((unsigned short)0x0002) << ((unsigned short)files()); + } + buf << ((unsigned long)totalSize()); + + if(!m_proxy && (files() == 1)) + { + if(bWide) + { + QByteArray decodedfname = filename().toUtf8(); + buf.pack(decodedfname.data(), decodedfname.length() + 1); + } + else + { + // FIXME: this does not compile and is wrong ! + //buf.pack(filename(), filename().length() + 1); + // maybe this was meant? + buf.pack((const char*)filename().utf16(), filename().length() * 2 + 2); + } + } + else + { + buf.pack((unsigned char)0); + } + } + b.tlv(0x2711, buf); + if(m_stage == 1) + { + b.tlv(0x2712, charset.toAscii(), charset.length()); + } + m_client->snacICBM()->sendThroughServer(m_client->screen(m_data), 2, b, m_cookie, false, true); +} + +void AIMFileTransfer::accept() +{ +} + +unsigned short AIMFileTransfer::remotePort() +{ + return m_port; +} + +void AIMFileTransfer::processPacket() +{ + log(L_DEBUG, "AIMFileTransfer::processPacket"); +} + +void AIMFileTransfer::setICBMCookie(MessageId const& cookie) +{ + m_cookie = cookie; +} + +void AIMFileTransfer::setICBMCookie2(unsigned short cookie2) +{ + m_cookie2 = cookie2; +} + + + +bool AIMFileTransfer::readOFT(OftData* oft) +{ + log(L_DEBUG, "reading OFT"); + m_socket->readBuffer().unpack(oft->magic); + + if(oft->magic != OFT_magic) + { + log(L_DEBUG, "Invalid magic for OFT in stream %08x", (unsigned int)oft->magic); + return false; + } + + m_socket->readBuffer().unpack(oft->unknown); + m_socket->readBuffer().unpack(oft->type); + m_socket->readBuffer().unpack(oft->cookie, 8); + m_socket->readBuffer().unpack(oft->encrypt); + m_socket->readBuffer().unpack(oft->compress); + + m_socket->readBuffer().unpack(oft->total_files); + oft->total_files = ntohs(oft->total_files); + m_socket->readBuffer().unpack(oft->files_left); + oft->files_left = ntohs(oft->files_left); + m_socket->readBuffer().unpack(oft->total_parts); + oft->total_parts = ntohs(oft->total_parts); + m_socket->readBuffer().unpack(oft->parts_left); + oft->parts_left = ntohs(oft->parts_left); + m_socket->readBuffer().unpack(oft->total_size); + oft->total_size = ntohl(oft->total_size); + m_socket->readBuffer().unpack(oft->size); + oft->size = ntohl(oft->size); + + m_socket->readBuffer().unpack(oft->mod_time); + m_socket->readBuffer().unpack(oft->checksum); + m_socket->readBuffer().unpack(oft->rfrcsum); + m_socket->readBuffer().unpack(oft->rfsize); + m_socket->readBuffer().unpack(oft->cretime); + m_socket->readBuffer().unpack(oft->rfcsum); + m_socket->readBuffer().unpack(oft->nrecvd); + m_socket->readBuffer().unpack(oft->recvcsum); + m_socket->readBuffer().unpack(oft->idstring, 32); + m_socket->readBuffer().unpack(oft->flags); + m_socket->readBuffer().unpack(oft->lnameoffset); + m_socket->readBuffer().unpack(oft->lsizeoffset); + m_socket->readBuffer().unpack(oft->dummy, 69); + m_socket->readBuffer().unpack(oft->macfileinfo, 16); + m_socket->readBuffer().unpack(oft->nencode); + m_socket->readBuffer().unpack(oft->nlanguage); + + m_socket->readBuffer().unpack(oft->name, m_socket->readBuffer().size() - m_socket->readBuffer().readPos()); + + if(oft->nencode == 0x0200) // Hack + { + for(unsigned int i = 0; i < (unsigned)oft->name.size() ; i++) + { + unsigned char tmp = oft->name.data()[i + 1]; + oft->name.data()[i + 1] = oft->name.data()[i]; + oft->name.data()[i] = tmp; + } + } + oft->name.detach(); + return true; +} + +bool AIMFileTransfer::writeOFT(OftData* oft) +{ + log(L_DEBUG, "writing OFT"); + m_socket->writeBuffer().pack(oft->magic); + m_socket->writeBuffer().pack(oft->unknown); + m_socket->writeBuffer().pack(oft->type); + m_socket->writeBuffer().pack(oft->cookie, 8); + m_socket->writeBuffer().pack(oft->encrypt); + m_socket->writeBuffer().pack(oft->compress); + m_socket->writeBuffer().pack((unsigned short)htons(oft->total_files)); + m_socket->writeBuffer().pack((unsigned short)htons(oft->files_left)); + m_socket->writeBuffer().pack((unsigned short)htons(oft->total_parts)); + m_socket->writeBuffer().pack((unsigned short)htons(oft->parts_left)); + m_socket->writeBuffer().pack((unsigned long)htonl(oft->total_size)); + m_socket->writeBuffer().pack((unsigned long)htonl(oft->size)); + m_socket->writeBuffer().pack(oft->mod_time); + m_socket->writeBuffer().pack(oft->checksum); + m_socket->writeBuffer().pack(oft->rfrcsum); + m_socket->writeBuffer().pack(oft->rfsize); + m_socket->writeBuffer().pack(oft->cretime); + m_socket->writeBuffer().pack(oft->rfcsum); + m_socket->writeBuffer().pack(oft->nrecvd); + m_socket->writeBuffer().pack(oft->recvcsum); + m_socket->writeBuffer().pack(oft->idstring, 32); + m_socket->writeBuffer().pack(oft->flags); + m_socket->writeBuffer().pack(oft->lnameoffset); + m_socket->writeBuffer().pack(oft->lsizeoffset); + m_socket->writeBuffer().pack(oft->dummy, 69); + m_socket->writeBuffer().pack(oft->macfileinfo, 16); + m_socket->writeBuffer().pack(oft->nencode); + m_socket->writeBuffer().pack(oft->nlanguage); + m_socket->writeBuffer().pack(oft->name.data(), oft->name.size() - 1); + if(oft->name.size() - 1 <= 0x40) + { + for(unsigned int i = 0; i < 0x40 - (unsigned)oft->name.size() + 1; i++) + { + m_socket->writeBuffer().pack((unsigned char)0); + } + } + else + { + m_socket->writeBuffer().pack((unsigned char)0); + } + return true; +} + +unsigned long AIMFileTransfer::calculateChecksum() +{ + if(!m_file) + { + log(L_WARN, "No file for checksum calculation"); + return 0; + } + unsigned long checksum = 0xFFFF; + //bool high = true; + QByteArray chunk(1024, '\0'); + ulong bytesread = 0; + long streamposition = 0; + m_file->reset(); + do + { + bytesread = m_file->read(chunk.data(), chunk.size()); + checksum = checksumChunk(&chunk, (unsigned int)bytesread, checksum); + streamposition += bytesread; + + } + while (bytesread == (unsigned)chunk.size()); + + checksum = ((checksum & 0x0000ffff) + (checksum >> 16)); + checksum = ((checksum & 0x0000ffff) + (checksum >> 16)); + + log(L_WARN, "Calculating checksum: %s (%08x)", qPrintable(m_file->fileName()), (unsigned int)checksum); + return checksum; +} + +unsigned long AIMFileTransfer::checksumChunk(QByteArray* filechunk, unsigned int chunklength, unsigned int start) +{ + uint32_t checksum = start, prevchecksum; + bool high = false; + for (unsigned long i = 0; i < (unsigned long)filechunk->size() && i < (unsigned long)chunklength; i++) + { + prevchecksum = checksum; + + if(high) + { + checksum -= (((uint32_t)(filechunk->at(i)) & 0xff) << 8); + } + else + { + checksum -= ((uint32_t)(filechunk->at(i)) & 0xff); + } + high = !high; + + if(checksum > prevchecksum) + checksum--; + } + + return checksum; +} + +void AIMFileTransfer::connectThroughProxy(const QString& host, uint16_t port, uint16_t cookie2) +{ + log(L_DEBUG, "Proxy connection, host = %s, port = %d", host.toLatin1().data(), port); + m_proxy = true; + m_port = port; + m_cookie2 = cookie2; + + FileTransfer::m_state = FileTransfer::Connect; + if (m_notify) + m_notify->process(); + + m_socket->connect(host, port, NULL); + m_socket->writeBuffer().init(0); + m_socket->readBuffer().init(0); + m_socket->readBuffer().packetStart(); + m_socket->setRaw(true); + +} + +void AIMFileTransfer::negotiateWithProxy() +{ + if(m_proxyActive) // We initiated proxy transfer + { + unsigned char uin_length = m_client->getScreen().length(); + unsigned short packet_length = 0x26 + 1 + uin_length; + m_socket->writeBuffer() << packet_length; + m_socket->writeBuffer() << Chunk_status; + // Status chunk is made of 6 bytes, first 2 are actually status and other 4 are zeroes + m_socket->writeBuffer() << (unsigned short)0x0002 << (unsigned long) 0x00000000; // 0x0002 means FT request to send + // Then, UIN chunk goes. First byte is length. + m_socket->writeBuffer() << Chunk_uin << uin_length; + m_socket->writeBuffer().pack(m_client->getScreen().toAscii(), uin_length); + // Next chunk is cookie chunk + m_socket->writeBuffer() << m_cookie.id_l << m_cookie.id_h; + // And the last one is magic caps chunk + m_socket->writeBuffer() << Chunk_cap << (unsigned short)0x0010; + m_socket->writeBuffer().pack(m_client->capabilities[CAP_AIM_SENDFILE], 0x10); + //EventLog::log_packet(m_socket->writeBuffer(), true, ICQPlugin::icq_plugin->AIMDirectPacket); //commented out due to problems with netmon while transfer + m_socket->write(); + } + else // Remote host initiated proxy transfer + { + unsigned char uin_length = m_client->getScreen().length(); + unsigned short packet_length = 0x28 + 1 + uin_length; + m_socket->writeBuffer() << packet_length; + m_socket->writeBuffer() << Chunk_status; + // Status chunk is made of 6 bytes, first 2 are actually status and other 4 are zeroes + m_socket->writeBuffer() << (unsigned short)0x0004 << (unsigned long) 0x00000000; // 0x0004 means FT request to receive + // Then, UIN chunk goes. First byte is length. + m_socket->writeBuffer() << Chunk_uin << uin_length; + m_socket->writeBuffer().pack(m_client->getScreen().toAscii(), uin_length); + // Next chunk is cookie chunk + m_socket->writeBuffer() << (unsigned short)m_cookie2 << m_cookie.id_l << m_cookie.id_h; + // And the last one is magic caps chunk + m_socket->writeBuffer() << Chunk_cap << (unsigned short)0x0010; + m_socket->writeBuffer().pack(m_client->capabilities[CAP_AIM_SENDFILE], 0x10); + //EventLog::log_packet(m_socket->writeBuffer(), true, ICQPlugin::icq_plugin->AIMDirectPacket); //commented out due to problems with netmon while transfer + m_socket->write(); + } +} + +void AIMFileTransfer::resolve_ready(QHostAddress ip) +{ + m_ip = ip.toIPv4Address(); +} + +bool AIMFileTransfer::error_state(const QString &err, unsigned) +{ + m_msg->setError(err); + EventMessageSent(m_msg).process(); + return true; +} + + +void AIMFileTransfer::startReceive(unsigned) +{ + log(L_DEBUG, "AIMFileTransfer::startReceive"); +} + +void AIMFileTransfer::bind_ready(unsigned short port) +{ + log(L_DEBUG, "AIMFileTransfer::bind_ready(%d)", port); + for (list::iterator it = m_client->m_processMsg.begin(); it != m_client->m_processMsg.end(); ++it){ + if ((*it) == m_msg){ + m_client->m_processMsg.erase(it); + break; + } + } + m_port = port; +} + +bool AIMFileTransfer::error(const QString &err) +{ + error_state(err, 0); + return true; +} + +void AIMFileTransfer::connect(unsigned long ip, unsigned short port) +{ + log(L_DEBUG, "AIMFileTransfer::connect"); + + m_socket->connect(ip, port, NULL); + m_socket->writeBuffer().init(0); + m_socket->readBuffer().init(0); + m_socket->readBuffer().packetStart(); + m_socket->setRaw(true); +} + + +AIMIncomingFileTransfer::AIMIncomingFileTransfer(SIM::FileMessage *msg, ICQUserData *data, ICQClient *client) + : QObject(), + AIMFileTransfer(msg, data, client), + m_connectTimer(this) +{ + QObject::connect(&m_connectTimer, SIGNAL(timeout()), this, SLOT(connect_timeout())); + m_totalBytes = 0; +} + +AIMIncomingFileTransfer::~AIMIncomingFileTransfer() +{ + //m_client->deleteFileMessage(m_cookie); +} + +bool AIMIncomingFileTransfer::error_state(const QString &err, unsigned code) +{ + log(L_DEBUG, "AIMFileTransfer::error_state: %s, %d", qPrintable(err), code); + if(m_stage == 1) + { + // Well, this is hack, but, i think, it is not so ugly as it seems :) + connect_timeout(); + return false; + } + else if(m_stage == 2) + { + // It can occur, so skip this stage, and wait for proxy FT request from the other peer + return false; + } + return true; +} + +bool AIMIncomingFileTransfer::accept(SIM::Socket* /*s*/, unsigned long /*ip*/) +{ + // TODO + return false; +} + +void AIMIncomingFileTransfer::accept() +{ + log(L_DEBUG, "AIMIncomingFileTransfer::accept"); + m_state = Connecting; + m_connectTimer.setSingleShot( true ); + m_connectTimer.start( DIRECT_TIMEOUT * 1000 ); + FileTransfer::m_state = FileTransfer::Connect; + if(m_notify) + m_notify->process(); + + unsigned long ip = get_ip(m_data->RealIP); + if(!ip) + { + ip = get_ip(m_data->IP); + } + m_socket->connect(ip, m_port, NULL); +} + +void AIMIncomingFileTransfer::connect_timeout() +{ + if(m_state == Connecting) + { + log(L_DEBUG, "Connecting timeout, trying reverse connection"); + FileMessage* msg = static_cast(m_msg); + QString filename = msg->getDescription(); + m_stage++; + requestFT(); + m_state = ProxyConnection; + // TODO Here we should really open the socket and wait for incoming connection, + // but we'll cheat for now - skip this step and wait for request for proxy transfer + } +} + +void AIMIncomingFileTransfer::connect_ready() +{ + log(L_DEBUG, "AIMIncomingFileTransfer::connect_ready()"); + m_connectTimer.stop(); + m_socket->writeBuffer().init(0); + m_socket->readBuffer().init(0); + m_socket->writeBuffer().packetStart(); + m_socket->readBuffer().packetStart(); + + if(!m_proxy) + { + m_state = OFTNegotiation; + + ICQBuffer buf; + buf << 0x0002 << m_cookie.id_l << m_cookie.id_h; + buf.pack(m_client->capabilities[CAP_AIM_SENDFILE], 0x10); + m_client->snacICBM()->sendThroughServer(m_client->screen(m_data), 0x0002, buf, m_cookie, false, true); + + FileTransfer::m_state = FileTransfer::Negotiation; + if(m_notify) + m_notify->process(); + } + else + { + m_state = ProxyNegotiation; + negotiateWithProxy(); + } + m_socket->setRaw(true); +} +void AIMIncomingFileTransfer::packet_ready() +{ + ICQPlugin *plugin = static_cast(m_client->protocol()->plugin()); + EventLog::log_packet(m_socket->readBuffer(), false, plugin->AIMDirectPacket); + long size = (unsigned long)(m_socket->readBuffer().size() - m_socket->readBuffer().readPos()); + if(size <= 0) + { + log(L_DEBUG, "size <= 0"); + return; + } + switch(m_state) + { + case ProxyNegotiation: + { + unsigned short packet_length, chunk_id, status; + m_socket->readBuffer() >> packet_length; + m_socket->readBuffer() >> chunk_id; + log(L_DEBUG, "[Input]Proxy packet, length = %d, chunk_id = %04x",packet_length, chunk_id); + if(chunk_id == Chunk_status) + { + m_socket->readBuffer() >> status; + log(L_DEBUG, "status = %04x", status); + // TODO Handle errors + if(status == 0x0003) + { + m_socket->readBuffer().incReadPos(6); + m_socket->readBuffer() >> m_cookie2; + m_socket->readBuffer() >> m_ip; + FileMessage* msg = static_cast(m_msg); + QString filename = msg->getDescription(); + m_stage++; + requestFT(); + } + if(status == 0x0005) // Everything is allright + { + log(L_DEBUG, "Connection accepted"); + // Read the rest of a packet: + m_socket->readBuffer().incReadPos(packet_length - 4); + ICQBuffer buf; + buf << (unsigned short) 0x0002 << m_cookie.id_l << m_cookie.id_h; + buf.pack(m_client->capabilities[CAP_AIM_SENDFILE], 0x10); + + m_client->snacICBM()->sendThroughServer(m_client->screen(m_data), 0x0002, buf, m_cookie, false, true); + FileTransfer::m_state = FileTransfer::Negotiation; + if(m_notify) + m_notify->process(); + m_state = OFTNegotiation; + } + } + return; + } + break; + case OFTNegotiation: + if(readOFT(&m_oft)) + { + if(m_oft.type == OFT_fileInfo) + ackOFT(); + FileTransfer::m_state = FileTransfer::Read; + if(m_notify) + { + m_notify->transfer(true); + m_notify->process(); + } + m_state = Reading; + } + break; + + case Reading: + { + if(m_bytes < m_fileSize) + { + long recvd_size = (unsigned long)(m_socket->readBuffer().size() - m_socket->readBuffer().readPos()); + if(size < 0) + { + return; + } + receiveNextBlock(recvd_size); + } + if(m_bytes >= m_fileSize) + { + /// TODO Calculate and verify checksum + m_oft.type = OFT_success; + writeOFT(&m_oft); + //EventLog::log_packet(m_socket->writeBuffer(), true, ICQPlugin::icq_plugin->AIMDirectPacket); //commented out due to problems with netmon while transfer + m_socket->write(); + + if(m_totalBytes >= m_totalSize) + { + if(m_notify) + m_notify->transfer(false); + ICQBuffer buf; + buf << (unsigned short) 0x0002 << m_cookie.id_l << m_cookie.id_h; + buf.pack(m_client->capabilities[CAP_AIM_SENDFILE], 0x10); + if(m_file) + m_file->flush(); + + m_client->snacICBM()->sendThroughServer(m_client->screen(m_data), 0x0002, buf, m_cookie, false, true); + m_state = Done; + } + else + { + m_state = OFTNegotiation; + } + return; + } + } + break; + default: + break; + } +} +void AIMIncomingFileTransfer::startReceive(unsigned /*pos*/) +{ + m_oft.type = OFT_answer; + *((unsigned long*)&m_oft.cookie[0]) = htonl(m_cookie.id_l); + *((unsigned long*)&m_oft.cookie[4]) = htonl(m_cookie.id_h); + writeOFT(&m_oft); + //EventLog::log_packet(m_socket->writeBuffer(), true, ICQPlugin::icq_plugin->AIMDirectPacket); //commented out due to problems with netmon while transfer + m_socket->write(); + m_nFile = m_oft.total_files - m_oft.files_left + 1; + m_nFiles = m_oft.total_files; + m_fileSize = m_oft.size; + m_totalSize = m_oft.total_size; +} + +void AIMIncomingFileTransfer::ackOFT() +{ + log(L_DEBUG, "Sending file ack"); + if(m_notify) + { + m_notify->transfer(false); + if(m_oft.nencode == 0x0200) // this is ucs2 + { + m_notify->createFile(QString::fromUtf16((unsigned short*)m_oft.name.data()), m_fileSize, true); + } + else + { + m_notify->createFile(QString(m_oft.name), m_fileSize, true); + } + } +} + +void AIMIncomingFileTransfer::receiveNextBlock(long size) +{ + m_totalBytes += size; + m_bytes += size; + m_transferBytes += size; + if(size) + { + if(!m_file) + { + log(L_DEBUG, "Write without file"); + return; + } + long hret = m_file->write(m_socket->readBuffer().data(m_socket->readBuffer().readPos()), size); + if(hret != size) + { + log(L_DEBUG, "Error while writing to file: %d", (int)hret); + m_socket->error_state("Error write file"); + return; + } + } + if (m_notify) + m_notify->process(); + m_socket->readBuffer().incReadPos(size); +} + +void AIMIncomingFileTransfer::write_ready() +{ + log(L_DEBUG, "AIMIncomingFileTransfer::write_ready()"); + if(m_state == Done) + { + FileTransfer::m_state = FileTransfer::Done; + //m_client->deleteFileMessage(m_cookie); + if(m_notify) + m_notify->process(); + // I'm not sure who is responsible for connection closing in this case. + // If sender is icq6, it closes this socket itself. Pidgin, however, does not. + m_socket->close(); + } +} + +void AIMIncomingFileTransfer::connectThroughProxy(const QString& host, uint16_t port, uint16_t cookie2) +{ + m_state = ProxyConnection; + AIMFileTransfer::connectThroughProxy(host, port, cookie2); +} + +AIMFileTransfer::tTransferDirection AIMIncomingFileTransfer::getDirection() +{ + return tdInput; +} + + +AIMOutcomingFileTransfer::AIMOutcomingFileTransfer(SIM::FileMessage *msg, ICQUserData *data, ICQClient *client) : AIMFileTransfer(msg, data, client), m_connectTimer(this) +{ + QObject::connect(&m_connectTimer, SIGNAL(timeout()), this, SLOT(connect_timeout())); + openFile(); + m_totalBytes = 0; + EventMessageAcked(m_msg).process(); +} + +AIMOutcomingFileTransfer::~AIMOutcomingFileTransfer() +{ +} + +void AIMOutcomingFileTransfer::listen() +{ + log(L_DEBUG, "AIMFileTransfer::listen"); + m_state = Listen; + bind(m_client->getMinPort(), m_client->getMaxPort(), m_client); + FileTransfer::m_state = FileTransfer::Connect; + if(m_notify) + m_notify->process(); +} + +bool AIMOutcomingFileTransfer::accept(Socket *s, unsigned long) +{ + log(L_DEBUG, "Accept AIM file transfer"); + m_state = OFTNegotiation; + + m_socket->setSocket(s); + m_socket->readBuffer().init(0); + m_socket->readBuffer().packetStart(); + + FileTransfer::m_state = FileTransfer::Negotiation; + if (m_notify) + m_notify->process(); + + m_socket->setRaw(true); + initOFTSending(); + + return true; +} + +void AIMOutcomingFileTransfer::initOFTSending() +{ + int delta_length = filename().length() - 0x40; + if(delta_length < 0) + delta_length = 0; + + m_oft.magic = OFT_magic; + m_oft.unknown = htons(256 + delta_length); + m_oft.type = OFT_fileInfo; + + *((unsigned long*)&m_oft.cookie[0]) = htonl(m_cookie.id_l); + *((unsigned long*)&m_oft.cookie[4]) = htonl(m_cookie.id_h); + + m_oft.encrypt = 0; + m_oft.compress = 0; + m_oft.total_files = files(); + m_oft.files_left = files() - file(); + m_oft.total_parts = 1; //FIXME if needed + m_oft.parts_left = 1; + m_oft.total_size = totalSize(); + m_oft.size = fileSize(); + m_oft.mod_time = QDateTime::currentDateTime().toTime_t(); //FIXME + m_oft.checksum = calculateChecksum(); + m_oft.rfrcsum = 0x0000ffff; + m_oft.rfsize = 0x0; + m_oft.cretime = 0x0; + m_oft.rfcsum = 0x0000ffff; + m_oft.nrecvd = 0; + m_oft.recvcsum = 0x0000ffff; + memset(m_oft.idstring, 0, 32); + strncpy((char*)m_oft.idstring, "Cool FileXfer", 31); + m_oft.flags = 0x20; //FIXME magic + m_oft.lnameoffset = 0x1c; // ??? + m_oft.lsizeoffset = 0x11; + memset(m_oft.dummy, 0, 69); + memset(m_oft.macfileinfo, 0, 16); + //FileMessage* msg = static_cast(m_msg); //Fixme: msg is initialized, but not used. + +// QString filename = filename(); + bool bWide = false; + for(int i = 0; i < (int)(filename().length() + 1); i++) + { + if (filename()[i].unicode() > 0x7F) + { + bWide = true; + break; + } + } + + if(bWide) + { + m_oft.nencode = 0x0200; + m_oft.nlanguage = 0; + m_oft.name.resize((filename().length() + 1) * 2); + for(int i = 0; i < (int)(filename().length() + 1); i++) + { + *((unsigned short*)(&m_oft.name.data()[i * 2])) = htons(filename()[i].unicode()); + } + } + else + { + m_oft.nencode = 0x0; + m_oft.nlanguage = 0; + m_oft.name = QByteArray( filename().toUtf8().data(), filename().length() + 1 ); + } + writeOFT(&m_oft); + //EventLog::log_packet(m_socket->writeBuffer(), true, ICQPlugin::icq_plugin->AIMDirectPacket); //commented out due to problems with netmon while transfer + m_socket->write(); +} + +void AIMOutcomingFileTransfer::packet_ready() +{ + log(L_DEBUG, "AIMOutcomingFileTransfer::packet_ready %d", m_state); + //ICQPlugin *plugin = static_cast(m_client->protocol()->plugin()); //commented out due to problems with netmon while transfer + //EventLog::log_packet(m_socket->readBuffer(), false, plugin->AIMDirectPacket, m_client->screen(m_data)); //commented out due to problems with netmon while transfer + switch(m_state) + { + case ProxyNegotiation: + { + unsigned short packet_length, chunk_id, status; + m_socket->readBuffer() >> packet_length; + m_socket->readBuffer() >> chunk_id; + log(L_DEBUG, "[Output]Proxy packet, length = %d, chunk_id = %04x",packet_length, chunk_id); + if(chunk_id == Chunk_status) + { + m_socket->readBuffer() >> status; + log(L_DEBUG, "status = %04x", status); + // TODO Handle errors + if(status == 0x0003) + { + m_socket->readBuffer().incReadPos(6); + m_socket->readBuffer() >> m_cookie2; + m_socket->readBuffer() >> m_ip; + FileMessage* msg = static_cast(m_msg); + QString filename = msg->getDescription(); + m_stage++; + requestFT(); + } + if(status == 0x0005) // Everything is allright + { + log(L_DEBUG, "Connection accepted"); + // Read the rest of a packet: + if(!m_proxyActive) + { + ICQBuffer buf; + buf << (unsigned short) 0x0002 << m_cookie.id_l << m_cookie.id_h; + buf.pack(m_client->capabilities[CAP_AIM_SENDFILE], 0x10); + + m_client->snacICBM()->sendThroughServer(m_client->screen(m_data), 0x0002, buf, m_cookie, false, true); + } + m_socket->readBuffer().incReadPos(packet_length - 4); + FileTransfer::m_state = FileTransfer::Negotiation; + if(m_notify) + m_notify->process(); + m_state = OFTNegotiation; + + initOFTSending(); + } + } + return; + } + break; + case OFTNegotiation: + { + log(L_DEBUG, "Output, negotiation"); + if(!m_notify) + { + log(L_DEBUG, "m_notify == NULL!!! Achtung!! Alarm!!11"); + } + OftData this_oft; + readOFT(&this_oft); + if(this_oft.magic != OFT_magic) + { + log(L_WARN, "Invalid magic in OFT"); + // TODO cleanup + return; + } + if(this_oft.type == OFT_success) + { + log(L_DEBUG, "File transfer OK(3)"); + FileTransfer::m_state = FileTransfer::Done; + m_socket->close(); + if (m_notify) + m_notify->process(); + m_socket->error_state(QString::null); + return; + } + if(this_oft.type != OFT_answer) + { + log(L_WARN, "Error in OFT"); + // TODO cleanup + return; + } + m_file->reset(); + m_state = Writing; + // TODO Check other fields in this_oft + FileTransfer::m_state = FileTransfer::Write; + + if(m_notify) + { + m_notify->transfer(true); + m_notify->process(); + } + + log(L_DEBUG, "m_nFile = %d", file()); + sendNextBlock(); + } + break; + case Writing: + { + log(L_DEBUG, "Output, write"); + OftData this_oft; + readOFT(&this_oft); + if(this_oft.magic != OFT_magic) + { + log(L_WARN, "Invalid magic in OFT"); + // TODO cleanup + return; + } + if(this_oft.type == OFT_success) + { + log(L_DEBUG, "File transfer OK(4)"); + if(totalBytes() >= totalSize()) + { + FileTransfer::m_state = FileTransfer::Done; + m_socket->close(); + m_socket->error_state(QString::null); + EventSent(m_msg).process(); + if(m_notify) + { + m_notify->transfer(false); + m_notify->process(); + } + } + else + { + m_state = OFTNegotiation; + openFile(); + log(L_DEBUG, "m_nFile = %d", file()); + if(m_notify) + m_notify->process(); + initOFTSending(); + } + return; + } + } + break; + default: + break; + } + if (m_socket->readBuffer().readPos() <= m_socket->readBuffer().writePos()) + { + return; + } + //ICQPlugin *plugin = static_cast(m_client->protocol()->plugin()); //commented out due to problems with netmon while transfer + //EventLog::log_packet(m_socket->readBuffer(), false, plugin->AIMDirectPacket, m_client->screen(m_data)); //commented out due to problems with netmon while transfer + m_socket->readBuffer().init(0); +} + +bool AIMOutcomingFileTransfer::sendNextBlock() +{ + if(!m_file) + { + log(L_DEBUG, "Read without file"); + m_socket->error_state("Read without file"); + return false; + } + + char* buffer = new char[m_packetLength + 1]; // FIXME replace it with QByteArray + + int bytes_read = m_file->read(buffer, m_packetLength); + if(bytes_read < 0) + { + log(L_DEBUG, "Error while reading file"); + m_socket->error_state("Error while reading file"); + delete [] buffer; + return false; + } + if(bytes_read == 0) + { + delete [] buffer; + return true; + } + m_socket->writeBuffer().pack(buffer, bytes_read); + m_socket->write(); + m_totalBytes += bytes_read; + m_bytes += bytes_read; + m_transferBytes += bytes_read; + + if(m_notify) + m_notify->process(); + + delete [] buffer; + return true; +} + +void AIMOutcomingFileTransfer::connect_ready() +{ + log(L_DEBUG, "AIMOutcomingFileTransfer::connect_ready() %d %d", m_state, m_proxyActive); + if(m_state == ProxyConnection) + { + negotiateWithProxy(); + m_state = ProxyNegotiation; + } +} + +void AIMOutcomingFileTransfer::write_ready() +{ + if(FileTransfer::m_state != FileTransfer::Connect) + { + if(totalBytes() < totalSize()) + { + if(FileTransfer::m_state == FileTransfer::Write) + sendNextBlock(); + } + else + { + /// TODO Calculate and verify checksum + log(L_DEBUG, "File transfer OK(6)"); + } + } +} + +void AIMOutcomingFileTransfer::connect_timeout() +{ + if(m_state == ReverseConnection) + { + FileMessage* msg = static_cast(m_msg); + QString filename = msg->getDescription(); + } +} + +AIMFileTransfer::tTransferDirection AIMOutcomingFileTransfer::getDirection() +{ + return tdOutput; +} + +void AIMOutcomingFileTransfer::connectThroughProxy(const QString& host, uint16_t port, uint16_t cookie2) +{ + m_state = ProxyConnection; + AIMFileTransfer::connectThroughProxy(host, port, cookie2); +} + +void AIMOutcomingFileTransfer::connect(unsigned long ip, unsigned short port) +{ + log(L_DEBUG, "AIMOutcomingFileTransfer::connect"); + + if(m_stage == 2) + { + m_port = port; + FileTransfer::m_state = FileTransfer::Connect; + if (m_notify) + m_notify->process(); + + m_state = ProxyConnection; + connectThroughProxy(AOL_PROXY_HOST, AOL_PROXY_PORT, 0); + } + else + { + AIMFileTransfer::connect(ip, port); + } +} + diff --git a/plugins/icq/icqdirect.h b/plugins/icq/icqdirect.h new file mode 100644 index 0000000..e711fca --- /dev/null +++ b/plugins/icq/icqdirect.h @@ -0,0 +1,199 @@ + +#ifndef _ICQDIRECT_H_ +#define _ICQDIRECT_H_ + +#include +#include +#include + +#include "message.h" +#include "socket/socket.h" +#include "icqclient.h" +#include "icqicmb.h" + +#define AOL_PROXY_HOST "ars.oscar.aol.com" +#define AOL_PROXY_PORT 5190 + +struct ICQUserData; +class ICQClient; +struct OftData +{ + unsigned long magic; + unsigned short unknown; + unsigned short type; + char cookie[8]; + unsigned short encrypt; + unsigned short compress; + unsigned short total_files; + unsigned short files_left; + unsigned short total_parts; + unsigned short parts_left; + unsigned long total_size; + unsigned long size; + unsigned long mod_time; + unsigned long checksum; + unsigned long rfrcsum; + unsigned long rfsize; + unsigned long cretime; + unsigned long rfcsum; + unsigned long nrecvd; + unsigned long recvcsum; + char idstring[32]; + unsigned char flags; + unsigned char lnameoffset; + unsigned char lsizeoffset; + char dummy[69]; + char macfileinfo[16]; + unsigned short nencode; + unsigned short nlanguage; + QByteArray name; +}; + +class AIMFileTransfer : public SIM::FileTransfer, public SIM::ClientSocketNotify, public SIM::ServerSocketNotify +{ +public: + typedef enum + { + tdInput, + tdOutput + } tTransferDirection; + + AIMFileTransfer(SIM::FileMessage *msg, ICQUserData *data, ICQClient *client); + ~AIMFileTransfer(); + virtual void accept(); + void setPort(unsigned short port) {m_port = port;} + unsigned short remotePort(); + void setICBMCookie(MessageId const& cookie); + void setICBMCookie2(unsigned short cookie2); + MessageId& getICBMCookie() {return m_cookie; } + void setProxyActive(bool proxyActive) { m_proxyActive = proxyActive; } + virtual void connect(unsigned long ip, unsigned short port); + void setStage(int stage) { m_stage = stage; } + void forceProxyConnection() { m_proxy = true;} + void requestFT(); + + virtual void connectThroughProxy(const QString& host, uint16_t port, uint16_t cookie2); + virtual tTransferDirection getDirection() = 0; + + static const unsigned long OFT_magic = 0x3254464f; + static const int OFT_fileInfo = 0x0101; + static const int OFT_answer = 0x0202; + static const int OFT_success = 0x0402; + static const int OFT_continue = 0x0502; + + static const unsigned short Chunk_status = 0x044a; + static const unsigned short Chunk_uin = 0x0000; + static const unsigned short Chunk_cap = 0x0001; + +protected: + + virtual void processPacket(); + virtual bool error_state(const QString &err, unsigned code); + virtual void resolve_ready(QHostAddress ip); + virtual void startReceive(unsigned pos); + virtual void bind_ready(unsigned short port); + virtual bool error(const QString &err); + void negotiateWithProxy(); + + bool readOFT(OftData* oft); + bool writeOFT(OftData* oft); + unsigned long calculateChecksum(); + unsigned long checksumChunk(QByteArray* filechunk, unsigned int chunklength, unsigned int start); + + int m_stage; + bool m_proxy; + bool m_proxyActive; + MessageId m_cookie; + uint16_t m_cookie2; + OftData m_oft; + unsigned long m_packetLength; + bool bcontinue; + ICQUserData *m_data; + ICQClient *m_client; + ICQClientSocket *m_socket; + unsigned short m_port; + unsigned long m_ip; + + friend class ICQClient; +}; + +class AIMIncomingFileTransfer : public QObject, public AIMFileTransfer +{ + Q_OBJECT +public: + AIMIncomingFileTransfer(SIM::FileMessage *msg, ICQUserData *data, ICQClient *client); + virtual ~AIMIncomingFileTransfer(); + virtual void accept(); + virtual void connect_ready(); + virtual void packet_ready(); + virtual void write_ready(); + virtual bool accept(SIM::Socket *s, unsigned long ip); + + void receiveNextBlock(long size); + void ackOFT(); + virtual void connectThroughProxy(const QString& host, uint16_t port, uint16_t cookie2); + virtual tTransferDirection getDirection(); + +protected slots: + virtual void connect_timeout(); +protected: + virtual void startReceive(unsigned pos); + virtual bool error_state(const QString &err, unsigned code); + enum State + { + None, + Connecting, + ReverseConnection, + ProxyConnection, + ProxyNegotiation, + OFTNegotiation, + Reading, + Done + }; + State m_state; + QTimer m_connectTimer; +}; + +class AIMOutcomingFileTransfer : public QObject, public AIMFileTransfer +{ + Q_OBJECT +public: + AIMOutcomingFileTransfer(SIM::FileMessage *msg, ICQUserData *data, ICQClient *client); + virtual ~AIMOutcomingFileTransfer(); + + void listen(); + virtual void connect(unsigned long ip, unsigned short port); + //void connect(unsigned short port); + virtual tTransferDirection getDirection(); + virtual void connectThroughProxy(const QString& host, uint16_t port, uint16_t cookie2); +protected slots: + virtual void connect_timeout(); +protected: + enum State + { + None, + Listen, + ReverseConnection, + ProxyConnection, + ProxyNegotiation, + OFTNegotiation, + Writing, + Done + }; + virtual bool accept(SIM::Socket *s, unsigned long ip); + virtual void write_ready(); + virtual void packet_ready(); + virtual void connect_ready(); + + //void read_ready(); + bool sendNextBlock(); + + void initOFTSending(); + + State m_state; + QTimer m_connectTimer; +}; + + +#endif + diff --git a/plugins/icq/icqicmb.cpp b/plugins/icq/icqicmb.cpp new file mode 100644 index 0000000..806cf28 --- /dev/null +++ b/plugins/icq/icqicmb.cpp @@ -0,0 +1,2575 @@ +/*************************************************************************** + icqicmb.cpp - description + ------------------- + begin : Sun Mar 10 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#ifdef WIN32 +#include +#else +#include +#include +#include +#include +#include +#include +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "contacts.h" +#include "html.h" +#include "unquot.h" +#include "log.h" +#include "core_events.h" +#include "misc.h" + +#include "icqclient.h" +#include "icqmessage.h" +#include "icqdirect.h" +#include "icq.h" +#include "contacts/contact.h" +#include "contacts/group.h" + +using namespace std; +using namespace SIM; + +const unsigned MAX_TYPE2_SIZE = 0x1800; +const unsigned SEND_TIMEOUT = 50000; + +bool operator < (const alias_group &s1, const alias_group &s2) +{ + return s1.grp < s2.grp; +} + +const unsigned short ICQ_SNACxMSG_ERROR = 0x0001; +const unsigned short ICQ_SNACxMSG_SETxICQxMODE = 0x0002; +const unsigned short ICQ_SNACxMSG_RESETxICQxMODE = 0x0003; // not implemented +const unsigned short ICQ_SNACxMSG_REQUESTxRIGHTS = 0x0004; +const unsigned short ICQ_SNACxMSG_RIGHTSxGRANTED = 0x0005; +const unsigned short ICQ_SNACxMSG_SENDxSERVER = 0x0006; +const unsigned short ICQ_SNACxMSG_SERVERxMESSAGE = 0x0007; +const unsigned short ICQ_SNACxMSG_BLAMExUSER = 0x0008; +const unsigned short ICQ_SNACxMSG_BLAMExSRVxACK = 0x0009; +const unsigned short ICQ_SNACxMSG_SRV_MISSED_MSG = 0x000A; +const unsigned short ICQ_SNACxMSG_AUTOREPLY = 0x000B; +const unsigned short ICQ_SNACxMSG_ACK = 0x000C; +const unsigned short ICQ_SNACxMSG_MTN = 0x0014; + +static void copyTlv(ICQBuffer &b, TlvList *tlvs, unsigned nTlv) +{ + if (tlvs == NULL) + return; + Tlv *tlv = (*tlvs)(nTlv); + if (tlv == NULL) + return; + b.tlv(nTlv, *tlv, tlv->Size()); +} + +static char c2h(char c) +{ + c = (char)(c & 0xF); + if (c < 10) + return (char)('0' + c); + return (char)('A' + c - 10); +} + +static void b2h(char *&p, char c) +{ + *(p++) = c2h((char)(c >> 4)); + *(p++) = c2h(c); +} + +void packCap(ICQBuffer &b, const capability &c) +{ + char pack_cap[0x27]; + char *p = pack_cap; + *(p++) = '{'; + b2h(p, c[0]); b2h(p, c[1]); b2h(p, c[2]); b2h(p, c[3]); + *(p++) = '-'; + b2h(p, c[4]); b2h(p, c[5]); + *(p++) = '-'; + b2h(p, c[6]); b2h(p, c[7]); + *(p++) = '-'; + b2h(p, c[8]); b2h(p, c[9]); + *(p++) = '-'; + b2h(p, c[10]); b2h(p, c[11]); + b2h(p, c[12]); b2h(p, c[13]); b2h(p, c[14]); b2h(p, c[15]); + *(p++) = '}'; + *p = 0; + b << pack_cap; +} + +SnacIcqICBM::SnacIcqICBM(ICQClient* client) : QObject(NULL), SnacHandler(client, 0x0004) +{ + m_sendTimer = new QTimer(this); + connect(m_sendTimer, SIGNAL(timeout()), this, SLOT(sendTimeout())); +} + +SnacIcqICBM::~SnacIcqICBM() +{ +} + +void SnacIcqICBM::rightsRequest() +{ + client()->snac(ICQ_SNACxFOOD_MESSAGE, ICQ_SNACxMSG_REQUESTxRIGHTS); + client()->sendPacket(true); +} + +void SnacIcqICBM::sendICMB(unsigned short channel, unsigned long flags) +{ + client()->snac(ICQ_SNACxFOOD_MESSAGE, ICQ_SNACxMSG_SETxICQxMODE); + client()->socket()->writeBuffer() + << channel << flags + << (unsigned short)0x1f40 + << (unsigned short)0x30e7 + << (unsigned short)0x30e7 + << (unsigned short)0x0000 + << (unsigned short)0x0000; + client()->sendPacket(true); +} + +void SnacIcqICBM::sendThroughServer(const QString &screen, unsigned short channel, ICQBuffer &b, const MessageId &id, bool bOffline, bool bReqAck) +{ + // we need informations about channel 2 tlvs ! + unsigned short tlv_type = 5; + client()->snac(ICQ_SNACxFOOD_MESSAGE, ICQ_SNACxMSG_SENDxSERVER, true, true); + socket()->writeBuffer() << id.id_l << id.id_h; + socket()->writeBuffer() << channel; + socket()->writeBuffer().packScreen(screen); + if (channel == 1) + tlv_type = 2; + if (b.size()) + socket()->writeBuffer().tlv(tlv_type, b); + if (bReqAck) + socket()->writeBuffer().tlv(3); // req. ack from server + if (bOffline) + socket()->writeBuffer().tlv(6); // store if user is offline + client()->sendPacket(true); +} + +bool SnacIcqICBM::ackMessage(Message *msg, unsigned short ackFlags, const QByteArray &msg_str) +{ + switch (ackFlags){ + case ICQ_TCPxACK_OCCUPIED: + case ICQ_TCPxACK_DND: + case ICQ_TCPxACK_REFUSE: + if (msg_str.isEmpty()) + msg->setError(I18N_NOOP("Message declined")); + else + msg->setError(msg_str); + switch (ackFlags){ + case ICQ_TCPxACK_OCCUPIED: + msg->setRetryCode(static_cast(client()->protocol()->plugin())->RetrySendOccupied); + break; + case ICQ_TCPxACK_DND: + msg->setRetryCode(static_cast(client()->protocol()->plugin())->RetrySendDND); + break; + } + return false; + } + return true; +} + +void SnacIcqICBM::sendType1(const QString &text, bool bWide, ICQUserData *data) +{ + ICQBuffer msgBuf; + const ENCODING *encoding = getContacts()->getEncoding(client()->getContact(data)); + unsigned short usLang = 0; + if( ( NULL == encoding ) || !strcmp( encoding->codec, "UTF-8" ) ) { + bWide = true; + } + else { + usLang = encoding->cp_code; + } + + if (bWide) + { + QTextCodec *codec = QTextCodec::codecForName("UTF-16BE"); + Q_ASSERT(codec); + msgBuf << (unsigned short)0x0002L; + msgBuf << (unsigned short)0x0000L; + QByteArray ba = codec->fromUnicode( text ); + msgBuf.pack(ba, ba.size() ); + } + else + { + log(L_DEBUG, "%s", qPrintable(client()->getContact(data)->getEncoding())); + QByteArray msg_text = getContacts()->fromUnicode(client()->getContact(data), text); + EventSend e(m_send.msg, msg_text); + e.process(); + msg_text = e.localeText(); + msgBuf << (unsigned short)0x0000L; + msgBuf << (unsigned short)usLang; + msgBuf << msg_text.data(); + } + ICQBuffer b; + b.tlv(0x0501, "\x01", 1); + b.tlv(0x0101, msgBuf); + sendThroughServer(m_send.screen, 1, b, m_send.id, true, true); + if ((data->Status.toULong() != ICQ_STATUS_OFFLINE) || (client()->getAckMode() == 0)) + ackMessage(m_send); +} + +void SnacIcqICBM::sendType2(const QString &screen, ICQBuffer &msgBuf, const MessageId &id, unsigned cap, bool bOffline, unsigned short port, TlvList *tlvs, unsigned short type) +{ + ICQBuffer b; + b << (unsigned short)0; + b << id.id_l << id.id_h; + b.pack((char*)client()->capabilities[cap], sizeof(capability)); + b.tlv(0x0A, (unsigned short)type); + if(type != 4) + b.tlv(0x0F); + copyTlv(b, tlvs, 0x14); + if(port) + { + if(type != 4) + { + b.tlv(0x03, (unsigned long)htonl(get_ip(client()->data.owner.RealIP))); + if(type != 3) + { + b.tlv(0x04, (unsigned long)htonl(get_ip(client()->data.owner.IP))); + } + } + b.tlv(0x05, port); + log(L_DEBUG, "RealIP = %08x, IP = %08x, port = %04x", (unsigned int)(get_ip(client()->data.owner.RealIP)), (unsigned int)(get_ip(client()->data.owner.IP)), port); + } + copyTlv(b, tlvs, 0x17); + copyTlv(b, tlvs, 0x0E); + copyTlv(b, tlvs, 0x0D); + copyTlv(b, tlvs, 0x0C); + copyTlv(b, tlvs, 0x10); + copyTlv(b, tlvs, 0x02); + copyTlv(b, tlvs, 0x16); + if(type != 4) + b.tlv(0x2711, msgBuf); + copyTlv(b, tlvs, 0x2712); + copyTlv(b, tlvs, 0x03); + sendThroughServer(screen, 2, b, id, bOffline, true); +} + +ICQClientSocket* SnacIcqICBM::socket() +{ + return client()->socket(); +} + +void SnacIcqICBM::sendAdvMessage(const QString &screen, ICQBuffer &msgText, unsigned plugin_index, const MessageId &id, bool bOffline, bool bDirect, unsigned short cookie1, unsigned short cookie2, unsigned short type) +{ + if (cookie1 == 0) + { + client()->m_advCounter--; + cookie1 = client()->m_advCounter; + cookie2 = (plugin_index == PLUGIN_NULL) ? 0x0E : 0x12; + } + ICQBuffer msgBuf; + msgBuf.pack((unsigned short)0x1B); + msgBuf.pack((unsigned short)0x08); + msgBuf.pack((char*)client()->plugins[plugin_index], sizeof(plugin)); + msgBuf.pack(0x00000003L); + msgBuf.pack((char)(type ? 4 : 0)); + msgBuf.pack(cookie1); + msgBuf.pack(cookie2); + msgBuf.pack(cookie1); + msgBuf.pack(0x00000000L); + msgBuf.pack(0x00000000L); + msgBuf.pack(0x00000000L); + msgBuf.pack(msgText.data(0), msgText.size()); + sendType2(screen, msgBuf, id, CAP_SRV_RELAY, bOffline, bDirect ? client()->data.owner.Port.toULong() : 0, NULL, type); +} + +void SnacIcqICBM::ackMessage(SendMsg &s) +{ + if (s.flags == PLUGIN_AIM_FT){ + s.msg->setError(I18N_NOOP("File transfer declined")); + EventMessageSent(s.msg).process(); + delete s.msg; + s.msg = NULL; + s.screen = QString::null; + m_sendTimer->stop(); + processSendQueue(); + return; + } + if ((s.msg->getFlags() & MESSAGE_NOHISTORY) == 0){ + if ((s.flags & SEND_MASK) == SEND_RAW){ + s.msg->setClient(client()->dataName(m_send.screen)); + EventSent(s.msg).process(); + }else if (!s.part.isEmpty()){ + Message m(MessageGeneric); + m.setContact(s.msg->contact()); + m.setBackground(s.msg->getBackground()); + m.setForeground(s.msg->getForeground()); + unsigned flags = s.msg->getFlags() & (~MESSAGE_RICHTEXT); + if ((s.flags & SEND_MASK) == SEND_RTF){ + flags |= MESSAGE_RICHTEXT; + m.setText(client()->removeImages(s.part, true)); + }else if ((s.flags & SEND_MASK) == SEND_HTML){ + flags |= MESSAGE_RICHTEXT; + m.setText(client()->removeImages(s.part, false)); + }else{ + m.setText(s.part); + } + m.setFlags(flags); + m.setClient(client()->dataName(s.screen)); + EventSent(&m).process(); + } + } + if ((s.text.length() == 0) || (s.msg->type() == MessageWarning)){ + EventMessageSent(s.msg).process(); + delete s.msg; + s.msg = NULL; + s.screen = QString::null; + } + else + { + sendFgQueue.push_front(s); + } + m_sendTimer->stop(); + processSendQueue(); +} + +bool SnacIcqICBM::sendThruServer(Message *msg, void *_data) +{ + ICQUserData *data = client()->toICQUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + Contact *contact = getContacts()->contact(msg->contact()); + if ((contact == NULL) || (data == NULL)) + return false; + SendMsg s; + switch (msg->type()){ + case MessageGeneric: + if ((data->Status.toULong() != ICQ_STATUS_OFFLINE) && (client()->getSendFormat() == 0) && + client()->hasCap(data, CAP_RTF) && (msg->getFlags() & MESSAGE_RICHTEXT) && + !data->bBadClient.toBool()){ + s.flags = SEND_RTF; + s.msg = msg; + s.text = msg->getRichText(); + s.screen = client()->screen(data); + sendFgQueue.push_back(s); + processSendQueue(); + return true; + } + if ((data->Status.toULong() != ICQ_STATUS_OFFLINE) && + (client()->getSendFormat() <= 1) && + client()->hasCap(data, CAP_UTF) && + ((msg->getFlags() & MESSAGE_SECURE) == 0) && + (data->Version.toULong() >= 8) && !data->bBadClient.toBool()){ + s.flags = SEND_UTF; + s.msg = msg; + s.text = client()->addCRLF(msg->getPlainText()); + s.screen = client()->screen(data); + sendFgQueue.push_back(s); + processSendQueue(); + return true; + } + if ((data->Status.toULong() != ICQ_STATUS_OFFLINE) && + (data->Version.toULong() >= 8) && + !data->bBadClient.toBool() && + ((unsigned)msg->getPlainText().length() >= MAX_PLAIN_MESSAGE_SIZE)){ + s.flags = SEND_TYPE2; + s.msg = msg; + s.text = msg->getPlainText(); + s.screen = client()->screen(data); + sendFgQueue.push_back(s); + processSendQueue(); + return true; + } + if ((data->Uin.toULong() == 0) || client()->m_bAIM){ + s.msg = msg; + if (msg->getFlags() & MESSAGE_RICHTEXT){ + s.flags = SEND_HTML; + s.text = client()->removeImages(msg->getRichText(), false); + }else{ + s.flags = SEND_HTML_PLAIN; + s.text = msg->getPlainText(); + } + s.screen = client()->screen(data); + sendFgQueue.push_back(s); + processSendQueue(); + return true; + } + s.flags = SEND_PLAIN; + s.msg = msg; + s.text = client()->addCRLF(msg->getPlainText()); + s.screen = client()->screen(data); + sendFgQueue.push_back(s); + processSendQueue(); + return true; + case MessageUrl: + if ((data->Uin.toULong() == 0) || client()->m_bAIM){ + UrlMessage *m = static_cast(msg); + QString text = "getUrl(); + text += "\">"; + text += m->getUrl(); + text += "
"; + text += client()->removeImages(msg->getRichText(), false); + s.flags = SEND_HTML; + s.msg = msg; + s.text = text; + s.screen = client()->screen(data); + sendFgQueue.push_back(s); + processSendQueue(); + return true; + } + case MessageContacts: + case MessageFile: + case MessageWarning: + s.flags = SEND_RAW; + s.msg = msg; + s.screen = client()->screen(data); + sendFgQueue.push_back(s); + processSendQueue(); + return true; + } + return false; +} + +void SnacIcqICBM::clearMsgQueue() +{ + list::iterator it; + for (it = sendFgQueue.begin(); it != sendFgQueue.end(); ++it){ + if (it->socket){ + // dunno know if this is ok - vladimir please take a look + it->socket->acceptReverse(NULL); + continue; + } + if (it->msg) + { + it->msg->setError(I18N_NOOP("Client go offline")); + EventMessageSent(it->msg).process(); + if (it->msg == m_send.msg) + m_send.msg = NULL; + delete it->msg; + } + } + sendFgQueue.clear(); + for (it = sendBgQueue.begin(); it != sendBgQueue.end(); ++it){ + if (it->socket){ + // dunno know if this is ok - vladimir please take a look + it->socket->acceptReverse(NULL); + continue; + } + if(it->msg) + { + it->msg->setError(I18N_NOOP("Client go offline")); + EventMessageSent(it->msg).process(); + if (it->msg == m_send.msg) + m_send.msg = NULL; + delete it->msg; + } + } + sendBgQueue.clear(); + if (m_send.msg) + { + m_send.msg->setError(I18N_NOOP("Client go offline")); + EventMessageSent(m_send.msg).process(); + delete m_send.msg; + } + m_send.msg = NULL; + m_send.screen = QString::null; +} + +void SnacIcqICBM::sendFile(TlvList& tlv, unsigned long primary_ip, unsigned long secondary_ip, unsigned short port,const QString &screen, MessageId const& id) +{ + log(L_DEBUG, "ICQClient::icbmSendFile()"); + Tlv *desc = tlv(0x0A); + Tlv *info = tlv(0x2711); + QString d; + unsigned short type; + unsigned short nFiles; + unsigned long size; + bool is_proxy = tlv(0x10); + log(L_DEBUG, "Desc = %d", (uint16_t)(*desc)); + + // First, let's find our filetransfer + AIMFileTransfer* ft = NULL; + for(list::iterator it = client()->m_filetransfers.begin(); it != client()->m_filetransfers.end(); ++it) + { + if((*it)->getICBMCookie() == id) + { + ft = (*it); + break; + } + } + if(ft == NULL) + { + log(L_DEBUG, "ft == NULL"); + // Incoming file + if(info == NULL) + { + // This is baaad + log(L_WARN, "No info tlv in send file"); + return; + } + ICQBuffer b(*info); + b >> type >> nFiles >> size; + QString name = client()->convert(b.data(8), b.size() - 8, tlv, 0x2712); + AIMFileMessage *msg = new AIMFileMessage; + msg->setPort(port); + msg->setBackground(client()->clearTags(d)); + //msg->setText(d); + msg->setSize(size); + msg->setID_L(id.id_l); + msg->setID_H(id.id_h); + if(is_proxy) + { + msg->isProxy = true; + } + if(tlv(5)) + { + msg->cookie2 = *tlv(5); + } + if(type == 2) + { + d = i18n("Directory"); + d += ' '; + d += name; + d += " ("; + d += i18n("%n file", "%n files", nFiles); + d += ')'; + } + else + { + if (nFiles == 1) + { + d = name; + } + else + { + d = i18n("%n file", "%n files", nFiles); + } + } + msg->setDescription(d); + msg->setFlags(MESSAGE_RECEIVED | MESSAGE_RICHTEXT | MESSAGE_TEMP); + client()->m_processMsg.push_back(msg); + client()->messageReceived(msg, screen); + return; + } + AIMFileMessage* afm = NULL; + for(list::iterator it = client()->m_processMsg.begin(); it != client()->m_processMsg.end(); ++it) + { + if ((*it)->type() == MessageFile) + { + afm = static_cast((*it)); + MessageId this_id; + this_id.id_l = afm->getID_L(); + this_id.id_h = afm->getID_H(); + if(this_id == id) + { + afm->setPort(port); + } + } + } + + unsigned short ft_type = *desc; + ft->setStage(ft_type); + log(L_DEBUG, "stage = %d", ft_type); + if(is_proxy) // Connection through proxy + { + log(L_DEBUG, "Proxy request"); + for(list::iterator it = client()->m_filetransfers.begin(); it != client()->m_filetransfers.end(); ++it) + { + if((*it)->getICBMCookie() == id) + { + Contact *contact; + ICQUserData *data = client()->findContact(screen, NULL, false, contact); + if(data) + { + if(primary_ip) + set_ip(&data->RealIP, primary_ip); + AIMFileTransfer *ft = (*it); //Fixme:Local declaration of 'ft' hides declaration from line: 857 + + ft->setProxyActive(false); + unsigned short cookie2 = 0; + if(tlv(5)) + { + cookie2 = *tlv(5); + }; + if(primary_ip) + ft->connectThroughProxy(QHostAddress(primary_ip).toString(), AOL_PROXY_PORT, cookie2); + else + { + ft->setProxyActive(true); + ft->connectThroughProxy(AOL_PROXY_HOST, AOL_PROXY_PORT, cookie2); + } + + return; + } + } + } + } + else + { + log(L_DEBUG, "No Proxy request: %d", ft_type); + if(ft_type == 3) + { + ft->setProxyActive(true); + ft->connectThroughProxy(AOL_PROXY_HOST, AOL_PROXY_PORT, 0); + } + if(ft_type == 2) + { + for(list::iterator it = client()->m_filetransfers.begin(); it != m_client->m_filetransfers.end(); ++it) + { + AIMFileTransfer *ft = (*it); //Fixme:Local declaration of 'ft' hides declaration from line: 857 + if(ft->getICBMCookie() == id) + { + if(primary_ip) + ft->connect(primary_ip, port); + else + ft->connect(secondary_ip, port); + } + } + } + return; + } + if(info == NULL && afm) + { + afm->setPort(port); + return; + } +} + +void SnacIcqICBM::sendAutoReply(const QString &screen, MessageId id, + const plugin p, unsigned short cookie1, unsigned short cookie2, + unsigned short msgType, char msgFlags, unsigned short msgState, + const QString &response, unsigned short response_type, ICQBuffer ©) +{ + client()->snac(ICQ_SNACxFOOD_MESSAGE, ICQ_SNACxMSG_AUTOREPLY); + socket()->writeBuffer() << id.id_l << id.id_h << 0x0002; + socket()->writeBuffer().packScreen(screen); + socket()->writeBuffer() << 0x0003 << 0x1B00 << 0x0800; + socket()->writeBuffer().pack((char*)p, sizeof(plugin)); + socket()->writeBuffer() << 0x03000000L << (char)0; + socket()->writeBuffer().pack(cookie1); + socket()->writeBuffer().pack(cookie2); + socket()->writeBuffer().pack(cookie1); + socket()->writeBuffer() << 0x00000000L << 0x00000000L << 0x00000000L; + socket()->writeBuffer().pack(msgType); + socket()->writeBuffer() << msgFlags << msgState << (char)0; + if (!response.isEmpty()){ + Contact *contact = NULL; + client()->findContact(screen, NULL, false, contact); + QByteArray r = getContacts()->fromUnicode(contact, response); + unsigned short size = (unsigned short)(r.length() + 1); + socket()->writeBuffer().pack(size); + socket()->writeBuffer().pack(r.data(), size); + }else{ + socket()->writeBuffer() << (char)0x01 << response_type; + } + if (response_type != 3){ + if (copy.size()){ + socket()->writeBuffer().pack(copy.data(0), copy.writePos()); + }else{ + socket()->writeBuffer() << 0x00000000L << 0xFFFFFF00L; + } + } + client()->sendPacket(false); +} + +void SnacIcqICBM::sendMTN(const QString &screen, unsigned short type) +{ + if (client()->getDisableTypingNotification()) + return; + client()->snac(ICQ_SNACxFOOD_MESSAGE, ICQ_SNACxMSG_MTN); + socket()->writeBuffer() << 0x00000000L << 0x00000000L << (unsigned short)0x0001; + socket()->writeBuffer().packScreen(screen); + socket()->writeBuffer() << type; + client()->sendPacket(true); +} + +void SnacIcqICBM::sendTimeout() +{ + m_sendTimer->stop(); + if (m_send.screen.length()){ + log(L_WARN, "Send timeout"); + if (m_send.msg){ + m_send.msg->setError(I18N_NOOP("Send timeout")); + EventMessageSent(m_send.msg).process(); + delete m_send.msg; + } + m_send.msg = NULL; + m_send.screen = QString::null; + } + processSendQueue(); +} + +void SnacIcqICBM::accept(Message *msg, ICQUserData *data) +{ + MessageId id; + if (msg->getFlags() & MESSAGE_DIRECT){ + Contact *contact = getContacts()->contact(msg->contact()); + ICQUserData *data = NULL; //Fixme: Local declaration of 'data' hides declaration of the same name in outer scope, see previous declaration at line '2163' + if (contact){ + ClientDataIterator it(contact->clientData, client()); + while ((data = (client()->toICQUserData(++it))) != NULL){ + if (!msg->client().isEmpty() && (client()->dataName(data) == msg->client())) + break; + data = NULL; + } + } + if (data == NULL){ + log(L_WARN, "Data for request not found"); + return; + } + DirectClient *dc = dynamic_cast(data->Direct.object()); + if (dc == NULL){ + log(L_WARN, "No direct connection"); + return; + } + dc->acceptMessage(msg); + }else{ + id.id_l = static_cast(msg)->getID_L(); + id.id_h = static_cast(msg)->getID_H(); + ICQBuffer b; + unsigned short type = ICQ_MSGxEXT; + client()->packMessage(b, msg, data, type, false, 0); + unsigned cookie = static_cast(msg)->getCookie(); + sendAdvMessage(client()->screen(data), b, PLUGIN_NULL, id, false, true, (unsigned short)(cookie & 0xFFFF), (unsigned short)((cookie >> 16) & 0xFFFF), 2); + } +} + +void SnacIcqICBM::accept(Message *msg, const QString &dir, OverwriteMode overwrite) +{ + ICQUserData *data = NULL; + bool bDelete = true; + if (!msg->client().isEmpty()){ + Contact *contact = getContacts()->contact(msg->contact()); + if (contact){ + ClientDataIterator it(contact->clientData, client()); + while ((data = (client()->toICQUserData(++it))) != NULL){ + if (client()->dataName(data) == msg->client()) + break; + data = NULL; + } + } + } + if (data){ + switch (msg->type()){ + case MessageICQFile:{ + ICQFileTransfer *ft = new ICQFileTransfer(static_cast(msg), data, client()); + ft->setDir(dir); + ft->setOverwrite(overwrite); + EventMessageAcked(msg).process(); + client()->m_processMsg.push_back(msg); + bDelete = false; + ft->listen(); + break; + } + case MessageFile: + { + AIMFileTransfer *ft = new AIMIncomingFileTransfer(static_cast(msg), data, client()); + AIMFileMessage* fmsg = static_cast(msg); + fmsg->m_transfer = ft; + ft->setDir(dir); + ft->setOverwrite(overwrite); + EventMessageAcked(msg).process(); + bDelete = false; + ft->setPort(fmsg->getPort()); + MessageId this_id; + this_id.id_l = fmsg->getID_L(); + this_id.id_h = fmsg->getID_H(); + ft->setICBMCookie(this_id); + log(L_DEBUG, "port = %d", fmsg->getPort()); + ft->setStage(1); + if(fmsg->isProxy) + { + ft->setICBMCookie2(fmsg->cookie2); + ft->setProxyActive(false); + ft->forceProxyConnection(); + } + ft->accept(); + return; + } + default: + log(L_DEBUG, "Bad message type %u for accept", msg->type()); + } + } + EventMessageDeleted(msg).process(); + if (bDelete) + { + delete msg; + } +} + +void SnacIcqICBM::decline(Message *msg, const QString &reason) +{ + if (msg->getFlags() & MESSAGE_DIRECT){ + Contact *contact = getContacts()->contact(msg->contact()); + ICQUserData *data = NULL; + if (contact){ + ClientDataIterator it(contact->clientData, client()); + while ((data = (client()->toICQUserData(++it))) != NULL){ + if (!msg->client().isEmpty() && (client()->dataName(data) == msg->client())) + break; + data = NULL; + } + } + if (data == NULL){ + log(L_WARN, "Data for request not found"); + return; + } + DirectClient *dc = dynamic_cast(data->Direct.object()); + if (dc == NULL){ + log(L_WARN, "No direct connection"); + return; + } + dc->declineMessage(msg, reason); + }else{ + MessageId id; + unsigned cookie = 0; + switch (msg->type()){ + case MessageICQFile: + id.id_l = static_cast(msg)->getID_L(); + id.id_h = static_cast(msg)->getID_H(); + cookie = static_cast(msg)->getCookie(); + break; + case MessageFile: + id.id_l = static_cast(msg)->getID_L(); + id.id_h = static_cast(msg)->getID_H(); + break; + default: + log(L_WARN, "Bad type %u for decline", msg->type()); + } + ICQUserData *data = NULL; + Contact *contact = NULL; + if (!msg->client().isEmpty()){ + contact = getContacts()->contact(msg->contact()); + if (contact){ + ClientDataIterator it(contact->clientData, client()); + while ((data = (client()->toICQUserData(++it))) != NULL){ + if (client()->dataName(data) == msg->client()) + break; + data = NULL; + } + } + } + if (data && (id.id_l || id.id_h)){ + if (msg->type() == MessageICQFile){ + ICQBuffer buf, msgBuf; + ICQBuffer b; + client()->packExtendedMessage(msg, buf, msgBuf, data); + b.pack((unsigned short)buf.size()); + b.pack(buf.data(0), buf.size()); + b.pack32(msgBuf); + unsigned short type = ICQ_MSGxEXT; + sendAutoReply(client()->screen(data), id, client()->plugins[PLUGIN_NULL], (unsigned short)(cookie & 0xFFFF), + (unsigned short)((cookie >> 16) & 0xFFFF), type, 1, 0, reason, 2, b); + }else{ + client()->snac(ICQ_SNACxFOOD_MESSAGE, ICQ_SNACxMSG_AUTOREPLY); + socket()->writeBuffer() << id.id_l << id.id_h << 0x0002; + socket()->writeBuffer().packScreen(client()->screen(data)); + socket()->writeBuffer() << 0x0003 << 0x0002 << 0x0001; + client()->sendPacket(false); + if (!reason.isEmpty()){ + Message *msg = new Message(MessageGeneric); //Fixme: Local declaration of 'msg' hides declaration of the same name in outer scope, see previous declaration at line '2262' + msg->setText(reason); + msg->setFlags(MESSAGE_NOHISTORY); + msg->setContact(contact->id()); + if (!client()->send(msg, data)) + delete msg; + } + } + } + } + EventMessageDeleted(msg).process(); + delete msg; +} + + +void SnacIcqICBM::requestReverseConnection(const QString &screen, DirectSocket *socket) +{ + SendMsg s; + s.flags = PLUGIN_REVERSE; + s.socket = socket; + s.screen = screen; + sendFgQueue.push_back(s); + processSendQueue(); +} + +bool SnacIcqICBM::cancelMessage(SIM::Message* msg) +{ + list::iterator it; + for(it = client()->m_processMsg.begin(); it != m_client->m_processMsg.end(); ++it) + if (*it == msg) + break; + if(it != m_client->m_processMsg.end()) + { + m_client->m_processMsg.erase(it); + delete msg; + return true; + } + if(msg->type() == MessageSMS) + { + for (list::iterator it = smsQueue.begin(); it != smsQueue.end(); ++it) + { + if (it->msg == msg) + { + if (it == smsQueue.begin()) + { + it->text = QString::null; + } + else + { + smsQueue.erase(it); + } + return msg; + } + } + } + else + { + Contact *contact = getContacts()->contact(msg->contact()); + if(contact) + { + ICQUserData *data; + ClientDataIterator it(contact->clientData, m_client); + while ((data = m_client->toICQUserData(++it)) != NULL) + { + DirectClient *dc = dynamic_cast(data->Direct.object()); + if (dc && dc->cancelMessage(msg)) + return msg; + } + } + if(m_send.msg == msg) + { + m_send.msg = NULL; + m_send.screen = QString::null; + m_sendTimer->stop(); + processSendQueue(); + return msg; + } + list::iterator it; + for(it = sendFgQueue.begin(); it != sendFgQueue.end(); ++it) + { + if(it->msg == msg) + { + sendFgQueue.erase(it); + delete msg; + return msg; + } + } + for(it = sendBgQueue.begin(); it != sendBgQueue.end(); ++it) + { + if (it->msg == msg) + { + sendBgQueue.erase(it); + delete msg; + return msg; + } + } + for(it = replyQueue.begin(); it != replyQueue.end(); ++it) + { + if (it->msg == msg) + { + replyQueue.erase(it); + delete msg; + return msg; + } + } + } + return true; +} + +void SnacIcqICBM::sendSMS(SendMsg msg) +{ + smsQueue.push_back(msg); + m_client->processSMSQueue(); +} + +void SnacIcqICBM::pluginInfoRequest(unsigned long uin, unsigned plugin_index) +{ + list::iterator it; + for (it = sendBgQueue.begin(); it != sendBgQueue.end(); ++it){ + SendMsg &s = *it; + if((s.screen.toULong() == uin) && (s.flags == plugin_index) && (s.msg == NULL)) + break; + } + if (it != sendBgQueue.end()) + return; + SendMsg s; + s.screen = QString::number(uin); + s.flags = plugin_index; + sendBgQueue.push_back(s); + processSendQueue(); +} + +bool SnacIcqICBM::process(unsigned short subtype, ICQBuffer* buf, unsigned short seq) +{ + switch (subtype){ + case ICQ_SNACxMSG_RIGHTSxGRANTED: + log(L_DEBUG, "Message rights granted"); + break; + case ICQ_SNACxMSG_MTN:{ + buf->incReadPos(10); + QString screen = buf->unpackScreen(); + unsigned short type; //Fixme!!! Local declaration of 'type' hides declaration of the same name in outer scope: Function parameter "type" + *buf >> type; + bool bType = (type > 1); + Contact *contact; + ICQUserData *data = m_client->findContact(screen, NULL, false, contact); + if (data == NULL) + break; + if (data->bTyping.toBool() == bType) + break; + data->bTyping.asBool() = bType; + EventContact e(contact, EventContact::eStatus);; + e.process(); + break; + } + case ICQ_SNACxMSG_ERROR:{ + if(seq == 0) + break; + unsigned short error; + *buf >> error; + QString err_str = I18N_NOOP("Unknown error"); + if ((error == 0x0009) && + ((m_send.msg == NULL) || (m_send.msg->type() != MessageContacts))){ + err_str = I18N_NOOP("Not supported by client"); + Contact *contact; + ICQUserData *data = m_client->findContact(m_send.screen, NULL, false, contact); + if (data){ + list::iterator it; + for (it = sendFgQueue.begin(); it != sendFgQueue.end();){ + if (it->screen != m_send.screen){ + ++it; + continue; + } + if (it->msg){ + it->flags = 0; + ++it; + continue; + } + sendFgQueue.erase(it); + it = sendFgQueue.begin(); + } + for (it = sendBgQueue.begin(); it != sendBgQueue.end();){ + if (it->screen != m_send.screen){ + ++it; + continue; + } + if (it->msg){ + it->flags = 0; + ++it; + continue; + } + sendBgQueue.erase(it); + it = sendBgQueue.begin(); + } + data->bBadClient.asBool() = true; + if (m_send.msg) + sendThruServer(m_send.msg, data); + m_send.msg = NULL; + m_send.screen = QString::null; + m_sendTimer->stop(); + processSendQueue(); + break; + } + }else{ + err_str = m_client->error_message(error); + } + if(error == 2) + m_client->snacService()->requestRateInfo(); + if (m_send.msg){ + m_send.msg->setError(err_str); + EventMessageSent(m_send.msg).process(); + delete m_send.msg; + } + m_send.msg = NULL; + m_send.screen = QString::null; + m_sendTimer->stop(); + processSendQueue(); + break; + } + case ICQ_SNACxMSG_SRV_MISSED_MSG: { + unsigned short mFormat; // missed channel + QString screen; // screen + unsigned short wrnLevel;// warning level + unsigned short nTlv; // number of tlvs + TlvList lTlv; // all tlvs in message + unsigned short missed; // number of missed messages + unsigned short error; // error reason + socket()->readBuffer() >> mFormat; + screen = socket()->readBuffer().unpackScreen(); + socket()->readBuffer() >> wrnLevel; + socket()->readBuffer() >> nTlv; + for(unsigned i = 0; i < nTlv; i++) { + unsigned short num; + unsigned short size; + const char* data; + *buf >> num >> size; + data = buf->data(socket()->readBuffer().readPos()); + Tlv* tlv = new Tlv(num,size,data); + lTlv += tlv; + } + *buf >> missed >> error; + const char *err_str = NULL; + switch (error) { + case 0x00: + err_str = I18N_NOOP("Invalid message"); + break; + case 0x01: + err_str = I18N_NOOP("Message was too large"); + break; + case 0x02: + err_str = I18N_NOOP("Message rate exceeded"); + break; + case 0x03: + err_str = I18N_NOOP("Sender too evil"); + break; + case 0x04: + err_str = I18N_NOOP("We are to evil :("); + break; + default: + err_str = I18N_NOOP("Unknown error"); + } + log(L_DEBUG, "ICMB error %u (%s) - screen(%s)", error, err_str, qPrintable(screen)); + break; + } + case ICQ_SNACxMSG_BLAMExSRVxACK: + if((m_send.id.id_l == seq) && m_send.msg) + { + unsigned short oldLevel, newLevel; + *buf >> oldLevel >> newLevel; + WarningMessage *msg = static_cast(m_send.msg); + msg->setOldLevel((unsigned short)(newLevel - oldLevel)); + msg->setNewLevel(newLevel); + ackMessage(m_send); + } + break; + case ICQ_SNACxMSG_ACK: + { + MessageId id; + *buf >> id.id_l >> id.id_h; + buf->incReadPos(2); + QString screen = buf->unpackScreen(); + bool bAck = false; + if (m_send.id == id){ + if(screen.toLower() == m_send.screen.toLower()) + bAck = true; + } + if (bAck){ + log(L_DEBUG, "Ack: %lu %lu (%s)", m_send.id.id_h, m_send.id.id_l, qPrintable(m_send.screen)); + if (m_send.msg){ + Contact *contact; + ICQUserData *data = m_client->findContact(screen, NULL, false, contact); + if (((data == NULL) || + (data->Status.toULong() == ICQ_STATUS_OFFLINE) || + (m_client->getAckMode() == 1)) && + (m_send.msg->type() != MessageFile)){ + m_sendTimer->stop(); + ackMessage(m_send); + return true; + }else{ + replyQueue.push_back(m_send); + } + }else{ + replyQueue.push_back(m_send); + } + } + m_send.msg = NULL; + m_send.screen = QString::null; + m_sendTimer->stop(); + processSendQueue(); + break; + } + case ICQ_SNACxMSG_AUTOREPLY:{ + MessageId id; + unsigned short len, channel, reason, version; + *buf >> id.id_l >> id.id_h; + buf->unpack(channel); + if (channel == 1) { + log(L_DEBUG,"Please send paket to developer!"); + return true; + } + QString screen = buf->unpackScreen(); + buf->unpack(reason); + buf->unpack(len); + buf->unpack(version); + plugin p; + buf->unpack((char*)p, sizeof(p)); + buf->incReadPos(len - sizeof(plugin) + 2); + buf->unpack(len); + buf->incReadPos(len + 12); + unsigned short ackFlags, msgFlags; + buf->unpack(ackFlags); + buf->unpack(msgFlags); + + list::iterator it; + for (it = replyQueue.begin(); it != replyQueue.end(); ++it){ + SendMsg &s = *it; + if ((s.id == id) && (s.screen == screen)) + break; + } + if (it == replyQueue.end()) + break; + + unsigned plugin_type = it->flags; + if (plugin_type == PLUGIN_AIM_FT_ACK){ + m_client->m_processMsg.push_back(it->msg); + replyQueue.erase(it); + break; + } + if (it->msg){ + QByteArray answer; + socket()->readBuffer() >> answer; + if (ackMessage(it->msg, ackFlags, answer)){ + ackMessage(*it); + }else{ + EventMessageSent(it->msg).process(); + delete it->msg; + } + replyQueue.erase(it); + break; + } + + replyQueue.erase(it); + Contact *contact; + ICQUserData *data = m_client->findContact(screen, NULL, false, contact); + + if (memcmp(p, m_client->plugins[PLUGIN_NULL], sizeof(plugin))){ + unsigned plugin_index; + for (plugin_index = 0; plugin_index < PLUGIN_NULL; plugin_index++){ + if (memcmp(p, m_client->plugins[plugin_index], sizeof(plugin)) == 0) + break; + } + if (plugin_index == PLUGIN_NULL){ + QString plugin_str; + unsigned i; + for (i = 0; i < sizeof(plugin); i++){ + char b[4]; + sprintf(b, "%02X ", p[i]); + plugin_str += b; + } + log(L_WARN, "Unknown plugin sign in reply %s", qPrintable(plugin_str)); + break; + } + if ((data == NULL) && (plugin_index != PLUGIN_RANDOMxCHAT)) + break; + m_client->parsePluginPacket(socket()->readBuffer(), plugin_type, data, screen.toULong(), false); + break; + } + + if (plugin_type == PLUGIN_AR){ + QByteArray answer; + *buf >> answer; + log(L_DEBUG, "Autoreply from %s %s", qPrintable(screen), answer.data()); + Contact *contact; //Fixme: Local declaration of 'contact' hides declaration of the same name in outer scope, see previous declaration at line '300' + ICQUserData *data = m_client->findContact(screen, NULL, false, contact); + if (data && data->AutoReply.setStr(getContacts()->toUnicode(contact, answer))){ + EventContact e(contact, EventContact::eChanged); + e.process(); + } + } + break; + } + case ICQ_SNACxMSG_SERVERxMESSAGE:{ + MessageId id; + *buf >> id.id_l >> id.id_h; + unsigned short mFormat; + *buf >> mFormat; + QString screen = buf->unpackScreen(); + log(L_DEBUG, "Message from %s [%04X]", qPrintable(screen), mFormat); + unsigned short level, nTLV; + *buf >> level >> nTLV; + TlvList tlvFixed(*buf, nTLV); + TlvList tlvChannel(*buf); + switch (mFormat){ + case 0x0001:{ + if (!tlvChannel(2)){ + log(L_WARN, "TLV 0x0002 not found"); + break; + } + ICQBuffer m(*tlvChannel(2)); + TlvList tlv_msg(m); + Tlv *m_tlv = tlv_msg(0x101); + if (m_tlv == NULL){ + log(L_WARN, "TLV 0x0101 not found"); + break; + } + if (m_tlv->Size() <= 4){ + log(L_WARN, "Bad TLV 0x0101 size (%d)",m_tlv->Size()); + break; + } + char *m_data = (*m_tlv); + unsigned short encoding = (unsigned short)((m_data[0] << 8) + m_data[1]); + unsigned short codepage = (unsigned short)((m_data[2] << 8) + m_data[3]); + m_data += 4; + QString text; + switch( encoding ) { + case 0 : { // ASCII + QTextCodec *pCodec = ContactList::getCodecByCodePage(codepage); + if( NULL != pCodec ) { + text = pCodec->toUnicode( m_data, m_tlv->Size() - 4 ); + } + else { + text = QString::fromAscii( m_data, m_tlv->Size() - 4 ); + } + break; + } + case 2 : { // Unicode + QTextCodec *codec = QTextCodec::codecForName("UTF-16BE"); + Q_ASSERT(codec); + text = codec->toUnicode( m_data, m_tlv->Size() - 4 ); + break; + } + case 3 : { // Latin_1 + text = QString::fromLatin1( m_data, m_tlv->Size() - 4 ); + break; + } + } + + Message *msg = new Message(MessageGeneric); + if (screen.toULong()){ + msg->setText(text); + }else{ + unsigned bgColor = m_client->clearTags(text); + msg->setText(text); + msg->setBackground(bgColor); + msg->setFlags(MESSAGE_RICHTEXT); + } + log(L_DEBUG, "Message %s", qPrintable(text)); + m_client->messageReceived(msg, screen); + break; + } + case 0x0002:{ + Tlv *tlv5 = tlvChannel(5); + if(!tlv5) + { + log(L_WARN, "TLV 0x0005 not found"); + break; + } + ICQBuffer msg(*tlv5); + unsigned short type; //Fixme: Local declaration of 'type' hides declaration of the same name in outer scope, see previous declaration at line '73' + msg >> type; + switch (type){ + case 0: + parseAdvancedMessage(screen, msg, tlvChannel(3) != NULL, id); + break; + case 1: + { + Contact *contact; + ICQUserData *data = m_client->findContact(screen, NULL, false, contact); + if (data){ + QString name = m_client->dataName(data); + for (list::iterator it = m_client->m_acceptMsg.begin(); it != m_client->m_acceptMsg.end(); ++it){ + Message *msg = *it; //Fixme: Local declaration of 'msg' hides declaration of the same name in outer scope, see previous declaration at line '413' + if (!msg->client().isEmpty() && (name == msg->client())){ + MessageId msg_id; + switch (msg->type()){ + case MessageICQFile: + msg_id.id_l = static_cast(msg)->getID_L(); + msg_id.id_h = static_cast(msg)->getID_H(); + break; + case MessageFile: + msg_id.id_l = static_cast(msg)->getID_L(); + msg_id.id_h = static_cast(msg)->getID_H(); + break; + } + if (msg_id == id) + { + m_client->m_acceptMsg.erase(it); + EventMessageDeleted(msg).process(); + delete msg; + break; + } + } + } + } + break; + } + case 2: + log(L_DEBUG, "File ack"); + break; + default: + log(L_WARN, "Unknown type: 0x%04X", type); + } + break; + } + case 0x0004:{ + Tlv *tlv5 = tlvChannel(5); + if (!tlv5){ + log(L_WARN, "TLV 0x0005 not found"); + break; + } + ICQBuffer msg(*tlv5); + unsigned long msg_uin; + msg >> msg_uin; + if (msg_uin == 0){ + parseAdvancedMessage(screen, msg, tlvChannel(6) != NULL, id); + return true; + } + unsigned char type, flags; //Fixme: Local declaration of 'type' hides declaration of the same name in outer scope, see previous declaration at line '73' + QByteArray msg_str; + msg >> type; + msg >> flags; + msg >> msg_str; + Message *m = m_client->parseMessage(type, screen, msg_str, msg, id, 0); + if (m) + m_client->messageReceived(m, screen); + break; + } + default: + log(L_WARN, "Unknown message format %04X", mFormat); + } + break; + } + default: + break; + } + return true; +} + +void SnacIcqICBM::parseAdvancedMessage(const QString &screen, ICQBuffer &m, bool needAck, MessageId id) +{ + m.incReadPos(8); /* msg-id cookie */ + capability cap; + m.unpack((char*)cap, sizeof(cap)); + if (!memcmp(cap, m_client->capabilities[CAP_DIRECT], sizeof(cap))) + { + TlvList tlv(m); + if(!tlv(0x2711)) + { + log(L_DEBUG, "TLV 0x2711 not found"); + return; + } + unsigned long req_uin; + unsigned long localIP; + unsigned long localPort; + unsigned long remotePort; + unsigned long localPort1; + char mode; + ICQBuffer adv(*tlv(0x2711)); + adv.unpack(req_uin); + adv.unpack(localIP); + adv.unpack(localPort); + adv.unpack(mode); + adv.unpack(remotePort); + adv.unpack(localPort1); + if (req_uin != screen.toULong()){ + log(L_WARN, "Bad UIN in reverse direct request"); + return; + } + Contact *contact; + ICQUserData *data = m_client->findContact(screen, NULL, false, contact); + if ((data == NULL) || contact->getIgnore()){ + log(L_DEBUG, "Reverse direct request from unknown user"); + return; + } + if (get_ip(data->RealIP) == 0) + set_ip(&data->RealIP, localIP); + for (list::iterator it = m_client->m_processMsg.begin(); it != m_client->m_processMsg.end(); ++it){ + if ((*it)->type() != MessageICQFile) + continue; + ICQFileMessage *msg = static_cast(*it); + if (msg->m_transfer == NULL) + continue; + } + log(L_DEBUG, "Setup reverse connect to %s %s:%lu", + qPrintable(screen), qPrintable(QHostAddress(localIP).toString()), localPort); + DirectClient *direct = new DirectClient(data, m_client); + m_client->m_sockets.push_back(direct); + direct->reverseConnect(localIP, localPort); + return; + } + + TlvList tlv(m); + unsigned long real_ip = 0; + unsigned long ip = 0; + unsigned short port = 0; + unsigned long test_ip = 0; + + if (tlv(2)) + test_ip = ((uint32_t)(*tlv(2))); + if (tlv(3)) + real_ip = ((uint32_t)(*tlv(3))); + if (tlv(4)) + ip = ((uint32_t)(*tlv(4))); + if (tlv(5)) + port = (*tlv(5)); + + if(tlv(13)) { + // lang? + } + if(tlv(14)) { + // codepage? + } + + log(L_DEBUG, "Test IP: %08x, Real IP: %08x, IP: %08x, PORT: %d",(unsigned int)test_ip, (unsigned int)real_ip, (unsigned int)ip, port); + + if(real_ip || ip) + { + Contact *contact; + ICQUserData *data = m_client->findContact(screen, NULL, false, contact); + if (data) + { + //if(real_ip && (get_ip(data->RealIP) == 0)) + if(real_ip) + set_ip(&data->RealIP, real_ip); + if(ip && (get_ip(data->IP) == 0)) + set_ip(&data->IP, ip); + if(port && (data->Port.toULong() == 0)) + data->Port.asULong() = port; + } + } + + if (!memcmp(cap, m_client->capabilities[CAP_AIM_IMIMAGE], sizeof(cap))){ + log(L_DEBUG, "AIM set direct connection"); + return; + } + + if (!memcmp(cap, m_client->capabilities[CAP_AIM_SENDFILE], sizeof(cap))) + { + sendFile(tlv, test_ip, ip, port, screen, id); + return; + } + + if (!memcmp(cap, m_client->capabilities[CAP_AIM_BUDDYLIST], sizeof(cap))) + { + log(L_DEBUG, "AIM buddies list"); + if (!tlv(0x2711)){ + log(L_WARN, "No body in ICMB message found"); + return; + } + ICQBuffer adv(*tlv(0x2711)); + QString contacts; + while (adv.readPos() < (unsigned)adv.size()){ + QString grp; + adv.unpackStr(grp); + unsigned short nBuddies; + adv >> nBuddies; + for (unsigned short i = 0; i < nBuddies; i++){ + QString s; + adv.unpackStr(s); + if (!contacts.isEmpty()) + contacts += ';'; + if (s.toULong()){ + contacts += "icq:"; + contacts += s; + contacts += ",ICQ "; + contacts += s; + }else{ + contacts += "aim:"; + contacts += s; + contacts += ",AIM "; + contacts += s; + } + } + } + m_client->snac(ICQ_SNACxFOOD_MESSAGE, ICQ_SNACxMSG_AUTOREPLY); + socket()->writeBuffer() << id.id_l << id.id_h << 0x0002; + socket()->writeBuffer().packScreen(screen); + socket()->writeBuffer() << 0x0003 << 0x0002 << 0x0002; + m_client->sendPacket(false); + ContactsMessage *msg = new ContactsMessage; + msg->setContacts(contacts); + m_client->messageReceived(msg, screen); + return; + } + + if (memcmp(cap, m_client->capabilities[CAP_SRV_RELAY], sizeof(cap))){ + QString s; + for (unsigned i = 0; i < sizeof(cap); i++){ + char b[5]; + sprintf(b, "0x%02X ", cap[i] & 0xFF); + s += b; + } + log(L_DEBUG, "Unknown capability in advanced message\n%s", qPrintable(s)); + return; + } + + if (!tlv(0x2711)){ + log(L_WARN, "No body in ICMB message found"); + return; + } + + ICQBuffer adv(*tlv(0x2711)); + unsigned short len; + unsigned short tcp_version; + plugin p; + + adv.unpack(len); + adv.unpack(tcp_version); + adv.unpack((char*)p, sizeof(p)); + adv.incReadPos(len - sizeof(p) - 4); + + unsigned short cookie1; + unsigned short cookie2; + unsigned short cookie3; + adv.unpack(cookie1); + adv.unpack(cookie2); + adv.unpack(cookie3); + if ((cookie1 != cookie3) && (cookie1 + 1 != cookie3)){ + log(L_WARN, "Bad cookie in TLV 2711 (%X %X %X)", cookie1, cookie2, cookie3); + return; + } + adv.unpack(len); + adv.incReadPos(len + 10); + + if (memcmp(p, m_client->plugins[PLUGIN_NULL], sizeof(p))){ + unsigned plugin_index; + for (plugin_index = 0; plugin_index < PLUGIN_NULL; plugin_index++) + if (memcmp(p, m_client->plugins[plugin_index], sizeof(p)) == 0) + break; + if (plugin_index >= PLUGIN_NULL){ + QString sign; + unsigned int i; + for (i = 0; i < sizeof(p); i++) { + char temp[8]; + int value = p[i]; + + sprintf(temp,"%02X",value); + sign += QString(temp); + } + if (sign.length()) + log(L_WARN, "Unknown plugin sign %s",qPrintable(sign)); + return; + } + switch (plugin_index){ + case PLUGIN_INFOxMANAGER: + case PLUGIN_STATUSxMANAGER: + break; + default: + log(L_WARN, "Unsupported plugin request %u", plugin_index); + return; + } + char type; + adv.unpack(type); + if (type != 1){ + log(L_WARN, "Unknown type plugin request %u", type); + return; + } + adv.incReadPos(8); + plugin p; //Fixme: Local declaration of 'p' hides declaration of the same name in outer scope: previous declaration at line '1176' + adv.unpack((char*)p, sizeof(p)); + unsigned plugin_type; + for (plugin_type = 0; plugin_type < PLUGIN_NULL; plugin_type++){ + if (memcmp(p, m_client->plugins[plugin_type], sizeof(p)) == 0) + break; + } + if (plugin_type >= PLUGIN_NULL){ + log(L_WARN, "Unknown plugin request"); + return; + } + ICQBuffer info; + m_client->pluginAnswer(plugin_type, screen.toULong(), info); + sendAutoReply(screen, id, m_client->plugins[plugin_index], + cookie1, cookie2, 0, 0, 0x0200, QString::null, 1, info); + return; + } + + unsigned short msgType; + unsigned short msgFlags; + unsigned short msgState; + adv.unpack(msgType); + adv.unpack(msgState); + adv.unpack(msgFlags); + QByteArray msg; + adv >> msg; + + switch (msgType){ + case ICQ_MSGxAR_AWAY: + case ICQ_MSGxAR_OCCUPIED: + case ICQ_MSGxAR_NA: + case ICQ_MSGxAR_DND: + case ICQ_MSGxAR_FFC:{ + unsigned req_status = STATUS_AWAY; + switch (msgType){ + case ICQ_MSGxAR_OCCUPIED: + req_status = STATUS_OCCUPIED; + break; + case ICQ_MSGxAR_NA: + req_status = STATUS_NA; + break; + case ICQ_MSGxAR_DND: + req_status = STATUS_DND; + break; + case ICQ_MSGxAR_FFC: + req_status = STATUS_FFC; + break; + } + Contact *contact; + ICQUserData *data = m_client->findContact(screen, NULL, false, contact); + if (data == NULL) + return; + if ((m_client->getInvisible() && (data->VisibleId.toULong() == 0)) || + (!m_client->getInvisible() && data->InvisibleId.toULong())) + return; + ar_request req; + req.screen = screen; + req.type = msgType; + req.ack = 0; + req.id = id; + req.id1 = cookie1; + req.id2 = cookie2; + req.bDirect = false; + m_client->arRequests.push_back(req); + + ARRequest ar; + ar.contact = contact; + ar.param = &m_client->arRequests.back(); + ar.receiver = m_client; + ar.status = req_status; + EventARRequest(&ar).process(); + + if (!msg.isEmpty()){ + Contact *contact; //Fixme: Local declaration of 'contact' hides declaration of the same name in outer scope, see previous declaration at line '1278' + ICQUserData *data = m_client->findContact(screen, NULL, false, contact); //Fixme: Local declaration of 'data' hides declaration of the same name in outer scope, see previous declaration at line '1279' + QString m = getContacts()->toUnicode(contact, msg); //Fixme: Local declaration of 'm' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '1006' + data->AutoReply.str() = m; + EventContact e(contact, EventContact::eChanged); + e.process(); + } + return; + } + } + ICQBuffer copy; + if (!msg.isEmpty() || (msgType == ICQ_MSGxEXT)){ + if (adv.readPos() < adv.writePos()) + copy.pack(adv.data(adv.readPos()), adv.writePos() - adv.readPos()); + log(L_DEBUG, "Msg size=%lu type=%u", (unsigned long) msg.size(), msgType); + if (msg.size() || (msgType == ICQ_MSGxEXT)){ + Message *m = m_client->parseMessage(msgType, screen, msg, adv, id, cookie1 | (cookie2 << 16)); //Fixme: Local declaration of 'm' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '1006' + if (m){ + if ((m_send.id == id) && (m_send.screen == screen)){ + replyQueue.push_back(m_send); + m_send.msg = NULL; + m_send.screen = ""; + m_sendTimer->stop(); + processSendQueue(); + return; + } + list::iterator it; + for (it = replyQueue.begin(); it != replyQueue.end(); ++it){ + SendMsg &s = *it; + log(L_DEBUG, "%lu %lu (%s) - %lu %lu (%s)", + s.id.id_h, s.id.id_l, qPrintable(s.screen), + id.id_h, id.id_l, qPrintable(screen)); + if ((s.id == id) && (s.screen == screen)) + break; + } + if (it == replyQueue.end()){ + bool bAccept = true; + unsigned short ackFlags = 0; + if (m->type() != MessageICQFile){ + if (m->type() == MessageStatus){ + bAccept = false; + }else{ + switch (m_client->getStatus()){ + case STATUS_DND: + if (m_client->getAcceptInDND()) + break; + ackFlags = ICQ_TCPxACK_DND; + bAccept = false; + break; + case STATUS_OCCUPIED: + if (m_client->getAcceptInOccupied()) + break; + ackFlags = ICQ_TCPxACK_OCCUPIED; + bAccept = false; + break; + } + if (msgFlags & (ICQ_TCPxMSG_URGENT | ICQ_TCPxMSG_LIST)) + bAccept = true; + } + if (!bAccept){ + Contact *contact; + ICQUserData *data = m_client->findContact(screen, NULL, false, contact); + if (data == NULL) + return; + + ar_request req; + req.screen = screen; + req.type = msgType; + req.ack = ackFlags; + req.id = id; + req.id1 = cookie1; + req.id2 = cookie2; + req.bDirect = false; + m_client->arRequests.push_back(req); + + ARRequest ar; + ar.contact = contact; + ar.param = &m_client->arRequests.back(); + ar.receiver = m_client; + ar.status = m_client->getStatus(); + EventARRequest(&ar).process(); + return; + } + } + if (msgFlags & ICQ_TCPxMSG_URGENT) + m->setFlags(m->getFlags() | MESSAGE_URGENT); + if (msgFlags & ICQ_TCPxMSG_LIST) + m->setFlags(m->getFlags() | MESSAGE_LIST); + needAck = m_client->messageReceived(m, screen); + } + else + { + Message *msg = it->msg; //Fixme: Local declaration of 'msg' hides declaration of the same name in outer scope, see previous declaration at line '1254' + replyQueue.erase(it); + if(msg->type() == MessageFile) + { + Contact *contact; + ICQUserData *data = m_client->findContact(screen, NULL, false, contact); + if ((m->type() != MessageICQFile) || (data == NULL)){ + log(L_WARN, "Bad answer type"); + msg->setError(I18N_NOOP("Send failed")); + EventMessageSent(msg).process(); + delete msg; + return; + } + if(m_client->getState() == 1) + { + msg->setError(I18N_NOOP("Message declined")); + EventMessageSent(msg).process(); + delete msg; + return; + } + } + else + { + log(L_WARN, "Unknown message type for ACK"); + delete msg; + } + } + } + } + } + if (!needAck) + return; + sendAutoReply(screen, id, p, cookie1, cookie2, + msgType, 0, 0, QString::null, 0, copy); //variable p seems corrupted, maybe crash? +} + +class AIMParser : public HTMLParser +{ +public: + AIMParser() {} + QString parse(const QString &str); +protected: + bool bPara; + QString res; + virtual void text(const QString &text); + virtual void tag_start(const QString &tag, const list &options); + virtual void tag_end(const QString &tag); +}; + +QString AIMParser::parse(const QString &str) +{ + bPara = false; + res = QString::null; + HTMLParser::parse(str); + return res; +} + +void AIMParser::text(const QString &text) +{ + if (text.isEmpty()) + return; + bPara = true; + res += text; +} + +void AIMParser::tag_start(const QString &tag, const list &options) +{ + QString dummytag=tag; //remove this cramp later + list::const_iterator dummyoptions = options.begin();//remove this cramp later + /*QString otag; + QString add; + if (tag == "br") + otag = "BR"; + if (tag == "p"){ + if (!bPara) + return; + otag = "BR"; + } + if ((tag == "font") || (tag == "b") || (tag == "u") || (tag == "i")) + otag = tag.upper(); + if (tag == "span") + otag = "FONT"; + if (otag.isEmpty()) + return; + res += '<'; + res += otag; + for (list::const_iterator it = options.begin(); it != options.end(); ++it){ + QString key = *it; + ++it; + QString value = *it; + if (key.lower() == "style"){ + list styles = parseStyle(value); + for (list::const_iterator its = styles.begin(); its != styles.end(); ++its){ + QString key = *its; + ++its; + QString value = *its; + if (key == "font-family") + { + res += " FACE=\""; + res += value; + res += '\"'; + } + else if (key == "font-size") + { + if (value == "smaller") + { + res += " SIZE=2"; + } + else if (value == "larger") + { + res += " SIZE=4"; + } + } + else if (key == "font-style") + { + if (value.lower() == "italic") + add = ""; + } + else if (key == "font-weight") + { + if (value.toInt() >= 600) + add = ""; + } + else if (key == "text-decoration") + { + if (value.lower() == "underline") + add = "u"; + } + else if (key == "color") + { + res += " COLOR=\""; + res += value; + res += '\"'; + } + } + continue; + } + res += ' '; + res += key.upper(); + res += "=\""; + res += value; + res += '\"'; + } + res += ">";*/ +} + +void AIMParser::tag_end(const QString &tag) +{ + if(tag == "p") { + res += '\n'; + } + /*QString otag; + if ((tag == "font") || (tag == "b") || (tag == "u") || (tag == "i")) + otag = tag.upper(); + if (tag == "span") + otag = "FONT"; + if (otag.isEmpty()) + return; + res += "";*/ +} + +void SnacIcqICBM::processSendQueue() +{ + if (m_sendTimer->isActive()) //Crash here on change Profile, m_sendTimer is 0 + return; + m_client->m_processTimer->stop(); + if (m_client->m_bNoSend) + return; + if (m_client->getState() != Client::Connected){ + m_sendTimer->stop(); + return; + } + unsigned delay = 0; + unsigned send_delay = 0; + if (m_client->m_bReady){ + while (!sendFgQueue.empty()){ + send_delay = m_client->delayTime(SNAC(ICQ_SNACxFOOD_MESSAGE, ICQ_SNACxMSG_SENDxSERVER)); + if (send_delay){ + delay = send_delay; + break; + } + log(L_DEBUG, "Process fg queue"); + m_send = sendFgQueue.front(); + sendFgQueue.pop_front(); + m_sendTimer->start(SEND_TIMEOUT); + if (processMsg()) + return; + m_sendTimer->stop(); + } + } + send_delay = m_client->processSMSQueue(); + if (send_delay && (delay > send_delay)) + delay = send_delay; + for (unsigned i = 0; i < m_client->m_rates.size(); i++){ + RateInfo &r = m_client->m_rates[i]; + for (;;){ + if (r.delayed.readPos() == r.delayed.writePos()) + break; + send_delay = m_client->delayTime(r); + if (send_delay){ + log(L_DEBUG, "Delay for group %d: %u", i, send_delay); + m_client->m_processTimer->start(send_delay); + return; + } + unsigned char *packet = (unsigned char*)(r.delayed.data(r.delayed.readPos())); + unsigned size = (packet[4] << 8) + packet[5] + 6; + ++m_client->m_nFlapSequence; + packet[2] = (m_client->m_nFlapSequence >> 8); + packet[3] = m_client->m_nFlapSequence; + socket()->writeBuffer().packetStart(); + socket()->writeBuffer().pack(r.delayed.data(r.delayed.readPos()), size); + EventLog::log_packet(socket()->writeBuffer(), true, ICQPlugin::icq_plugin->OscarPacket); + r.delayed.incReadPos(size); + m_client->setNewLevel(r); + socket()->write(); + } + if (r.delayed.readPos() == r.delayed.writePos()) + r.delayed.init(0); + } + send_delay = m_client->processInfoRequest(); + if (send_delay && (delay > send_delay)) + delay = send_delay; + send_delay = m_client->processListRequest(); + if (send_delay && (delay > send_delay)) + delay = send_delay; + if (m_client->m_bReady){ + while (!sendBgQueue.empty()){ + send_delay = m_client->delayTime(SNAC(ICQ_SNACxFOOD_MESSAGE, ICQ_SNACxMSG_SENDxSERVER)); + if (send_delay){ + if (send_delay < delay) + delay = send_delay; + break; + } + m_send = sendBgQueue.front(); + sendBgQueue.pop_front(); + m_sendTimer->start(SEND_TIMEOUT); + if (processMsg()) + return; + m_sendTimer->stop(); + } + } + if (delay){ + log(L_DEBUG, "Delay: %u", delay); + m_client->m_processTimer->start(delay); + } +} + +static QString getUtf8Part(QString &str, unsigned size) +{ + if ((unsigned) str.toUtf8().length() < size){ + QString res = str; + str = QString::null; + return res; + } + unsigned s = 0; + int n; + int wordStart = 0; + bool bWord = false; + for (n = 0; n < str.length(); n++) + { + QChar c = str[n]; + if (c.isSpace()) + { + if (bWord) + { + unsigned word_size = str.mid(wordStart, n - wordStart).toUtf8().length(); + if (s + word_size > 0){ + if (wordStart == 0) + { + s = 0; + for (n = 0; n < str.length(); n++) + { + unsigned char_size = str.mid(n, 1).toUtf8().length(); + if (s + char_size > 0) + break; + } + } + break; + } + s += word_size; + bWord = false; + } + unsigned char_size = str.mid(n, 1).toUtf8().length(); + if (s + char_size > 0) + break; + s += char_size; + } + else if (!bWord) + { + wordStart = n; + bWord = true; + } + } + QString res = str.left(n); + str = str.mid(n); + return res; +} + +bool SnacIcqICBM::processMsg() +{ + log(L_DEBUG, "SnacIcqICBM::processMsg()"); + Contact *contact; + ICQUserData *data = m_client->findContact(m_send.screen, NULL, false, contact); + if ((data == NULL) && (m_send.flags != PLUGIN_RANDOMxCHAT)){ + if (m_send.msg != NULL) + { + m_send.msg->setError(I18N_NOOP("No contact")); + EventMessageSent(m_send.msg).process(); + delete m_send.msg; + m_send.msg = NULL; + } + m_send.screen = QString::null; + return false; + } + unsigned short type = 0; + if (m_send.msg) + { + type = m_send.msg->type(); + log(L_DEBUG, "Send: %s %u %X", qPrintable(m_send.screen), type, m_send.flags); + } + if(m_send.msg && (m_send.socket == NULL)) + { + ICQBuffer b; + m_send.id.id_l = rand(); + m_send.id.id_h = rand(); + switch (m_send.msg->type()) + { + case MessageContacts: + if (data->Uin.toULong() == 0){ + CONTACTS_MAP c; + QString nc = m_client->packContacts(static_cast(m_send.msg), data, c); + if (c.empty()){ + m_send.msg->setError(I18N_NOOP("No contacts for send")); + EventMessageSent(m_send.msg).process(); + delete m_send.msg; + m_send.msg = NULL; + m_send.screen = QString::null; + return false; + } + static_cast(m_send.msg)->setContacts(nc); + ICQBuffer msgBuf; + vector cc; + for (CONTACTS_MAP::iterator it = c.begin(); it != c.end(); ++it){ + alias_group c; //Fixme: Local declaration of 'c' hides declaration of the same name in outer scope, see previous declaration at line '1786' + c.alias = it->first.str(); + c.grp = it->second.grp; + cc.push_back(c); + } + sort(cc.begin(), cc.end()); + + unsigned grp = (unsigned)(-1); + unsigned start = 0; + unsigned short size = 0; + unsigned i; + for (i = 0; i < cc.size(); i++){ + if (cc[i].grp != grp){ + if (grp != (unsigned)(-1)){ + QString s = "Not in list"; + if (grp){ + Group *group = getContacts()->group(grp); + if (group) + s = group->getName(); + } + msgBuf.pack(s); + msgBuf << size; + for (unsigned j = start; j < i; j++) + msgBuf.pack(cc[j].alias); + } + size = 0; + start = i; + grp = cc[i].grp; + } + size++; + } + QString s = "Not in list"; + if (grp){ + Group *group = getContacts()->group(grp); + if (group) + s = group->getName(); + } + msgBuf.pack(s); + msgBuf << size; + for (unsigned j = start; j < i; j++) + msgBuf.pack(cc[j].alias); + m_send.id.id_l = rand(); + m_send.id.id_h = rand(); + sendType2(m_send.screen, msgBuf, m_send.id, CAP_AIM_BUDDYLIST, false, 0); + return true; + } + case MessageUrl:{ + if (data->Uin.toULong() == 0) + break; + m_client->packMessage(b, m_send.msg, data, type, false); + QString err = m_send.msg->getError(); + if (!err.isEmpty()){ + EventMessageSent(m_send.msg).process(); + delete m_send.msg; + m_send.msg = NULL; + m_send.screen = QString::null; + return false; + } + sendThroughServer(m_client->screen(data), 4, b, m_send.id, true, false); + if (data->Status.toULong() != ICQ_STATUS_OFFLINE) + m_sendTimer->stop(); + if ((data->Status.toULong() != ICQ_STATUS_OFFLINE) || (m_client->getAckMode() == 0)) + ackMessage(m_send); + return true; + } + case MessageFile: + { + log(L_DEBUG, "processMsg: MessageFile"); + MessageId id; + m_client->generateCookie(id); + FileMessage* msg = static_cast(m_send.msg); + AIMOutcomingFileTransfer *ft = new AIMOutcomingFileTransfer(msg, data, m_client); + ft->setICBMCookie(id); + ft->listen(); + QString filename = msg->getDescription(); + ft->setStage(1); + //unsigned long filesize = msg->getSize(); //Fixme: filesize is initialized, but not used. + ft->requestFT(); + return true; + } + case MessageWarning:{ + WarningMessage *msg = static_cast(m_send.msg); + m_client->snac(ICQ_SNACxFOOD_MESSAGE, ICQ_SNACxMSG_BLAMExUSER, true); + m_send.id.id_l = m_client->m_nMsgSequence; + unsigned short flag = 0; + if (msg->getAnonymous()) + flag = 1; + socket()->writeBuffer() << flag; + socket()->writeBuffer().packScreen(m_client->screen(data)); + m_client->sendPacket(false); + return true; + } + } + QByteArray text; + log(L_DEBUG, "Alpha %x", m_send.flags); + switch (m_send.flags & SEND_MASK){ + case SEND_RTF: + text = m_client->createRTF(m_send.text, m_send.part, m_send.msg->getForeground(), contact, MAX_TYPE2_MESSAGE_SIZE); + break; + case SEND_UTF: + m_send.part = getUtf8Part(m_send.text, MAX_TYPE2_MESSAGE_SIZE); + text = m_send.part.toUtf8(); + break; + case SEND_TYPE2:{ + m_send.part = getPart(m_send.text, MAX_TYPE2_MESSAGE_SIZE); + text = getContacts()->fromUnicode(contact, m_send.part); + EventSend e(m_send.msg, text); + e.process(); + text = e.localeText(); + break; + } + case SEND_HTML: + case SEND_HTML_PLAIN:{ + QString t; + unsigned max_size = MAX_TYPE2_MESSAGE_SIZE; + bool bWide = false; + for (int i = 0; i < (int)(m_send.text.length()); i++){ + if (m_send.text[i].unicode() > 0x7F){ + max_size = max_size / 2; + bWide = true; + break; + } + } + m_send.part = getPart(m_send.text, max_size); + //char b[15]; + //sprintf(b, "%06X", (unsigned)(m_send.msg->getBackground() & 0xFFFFFF)); + //t += ""; + if ((m_send.flags & SEND_MASK) == SEND_HTML){ + AIMParser p; + t += p.parse(m_send.part); + }else{ + EventSend e(m_send.msg, m_send.part.toUtf8()); + e.process(); + m_send.part = QString::fromUtf8( e.localeText() ); + t += quoteString(m_send.part); + } + //t += ""; + sendType1(t, bWide, data); + return true; + } + default: + m_send.part = getPart(m_send.text, MAX_PLAIN_MESSAGE_SIZE); + sendType1(m_send.part, false, data); + return true; + } + + ICQBuffer msgBuf; + unsigned short size = (unsigned short)(text.length() + 1); + unsigned short flags = ICQ_TCPxMSG_NORMAL; + if (m_send.msg->getFlags() & MESSAGE_URGENT) + flags = ICQ_TCPxMSG_URGENT; + if (m_send.msg->getFlags() & MESSAGE_LIST) + flags = ICQ_TCPxMSG_LIST; + msgBuf.pack((unsigned short)1); + msgBuf.pack(m_client->msgStatus()); + msgBuf.pack(flags); + msgBuf.pack(size); + msgBuf.pack(text.data(), size); + if (m_send.msg->getBackground() == m_send.msg->getForeground()){ + msgBuf << 0x00000000L << 0xFFFFFF00L; + }else{ + msgBuf << (m_send.msg->getForeground() << 8) << (m_send.msg->getBackground() << 8); + } + if ((m_send.flags & SEND_MASK) != SEND_TYPE2){ + msgBuf << 0x26000000L; + packCap(msgBuf, m_client->capabilities[((m_send.flags & SEND_MASK) == SEND_RTF) ? CAP_RTF : CAP_UTF]); + } + m_send.id.id_l = rand(); + m_send.id.id_h = rand(); + sendAdvMessage(m_send.screen, msgBuf, PLUGIN_NULL, m_send.id, true, false); + return true; + } + if(m_send.socket) + { + ICQBuffer msgBuf; + if(m_send.flags == PLUGIN_AIM_FT_ACK) + { + log(L_DEBUG, "This way"); + AIMFileMessage *msg = static_cast(m_send.msg); + m_send.id.id_l = msg->getID_L(); + m_send.id.id_h = msg->getID_H(); + ICQBuffer b; + b << (unsigned short)0; + b << m_send.id.id_l << m_send.id.id_h; + b.pack((char*)m_client->capabilities[CAP_AIM_SENDFILE], sizeof(capability)); + b.tlv(0x0A, (unsigned short)2); + b.tlv(0x03, (unsigned long)htonl(get_ip(m_client->data.owner.RealIP))); + b.tlv(0x05, static_cast(msg->m_transfer)->remotePort()); + sendThroughServer(m_send.screen, 2, b, m_send.id, false, false); + replyQueue.push_back(m_send); + m_send.msg = NULL; + m_send.screen = QString::null; + return false; + } + m_send.id.id_l = rand(); + m_send.id.id_h = rand(); + if(m_send.flags == PLUGIN_AIM_FT) + { + TlvList tlvs; + tlvs += new Tlv(0x0E, 2, "en"); + char b[15]; + sprintf(b, "%06X", (unsigned)(m_send.msg->getBackground() & 0xFFFFFF)); + QString text = QString("%2") + .arg(b) + .arg(m_client->removeImages(m_send.msg->getRichText(), false)); + bool bWide = false; + int i; + for (i = 0; i < (int)(text.length()); i++){ + if (text[i].unicode() > 0x7F){ + bWide = true; + break; + } + } + QString charset = bWide ? "unicode-2-0" : "us-ascii"; + tlvs += new Tlv(0x0D, charset.length(), charset.toLatin1()); + QByteArray st; + if (bWide){ + for (i = 0; i < (int)(text.length()); i++){ + unsigned short s = text[i].unicode(); + st += (char)((s >> 8) & 0xFF); + st += (char)(s & 0xFF); + } + }else{ + st = text.toUtf8(); + } + tlvs += new Tlv(0x0C, st.length(), st.data()); + FileMessage *msg = static_cast(m_send.msg); + FileMessage::Iterator it(*msg); + msgBuf + << (unsigned short)0x0001 + << (unsigned short)(it.count()) + << (unsigned long)(it.size()); + QString fname; + if (it.count() == 1){ + fname = *(it[0]); + fname = fname.replace('\\', '/'); + int n = fname.lastIndexOf('/'); + if (n >= 0) + fname = fname.mid(n + 1); + }else{ + fname = QString::number(it.count()); + fname += " files"; + } + bWide = false; + for (i = 0; i < (int)(fname.length()); i++){ + if (fname[i].unicode() > 0x7F){ + bWide = true; + break; + } + } + charset = bWide ? "utf8" : "us-ascii"; + tlvs += new Tlv(0x2712, charset.length(), charset.toUtf8()); + msgBuf << (const char*)(fname.toUtf8()) << (char)0; + sendType2(m_send.screen, msgBuf, m_send.id, CAP_AIM_SENDFILE, false, m_send.socket->localPort(), &tlvs); + return true; + } + msgBuf.pack(m_client->data.owner.Uin.toULong()); + unsigned long ip = get_ip(m_client->data.owner.IP); + if (ip == get_ip(m_send.socket->m_data->IP)) + ip = get_ip(m_client->data.owner.RealIP); + msgBuf.pack(ip); + msgBuf.pack((unsigned long)(m_send.socket->localPort())); + msgBuf.pack((char)MODE_DIRECT); + msgBuf.pack((unsigned long)(m_send.socket->remotePort())); + msgBuf.pack(m_client->data.owner.Port.toULong()); + msgBuf.pack((unsigned short)8); + msgBuf.pack((unsigned long)m_client->m_nMsgSequence); + sendType2(m_send.screen, msgBuf, m_send.id, CAP_DIRECT, false, 0); + return true; + } + if (m_send.flags == PLUGIN_AR){ + log(L_DEBUG, "Request auto response %s", qPrintable(m_send.screen)); + + unsigned long status = data->Status.toULong(); + if ((status == ICQ_STATUS_ONLINE) || (status == ICQ_STATUS_OFFLINE)) + return false; + + unsigned short type = ICQ_MSGxAR_AWAY; //Fixme: Local declaration of 'type' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '1771' + if (status & ICQ_STATUS_DND){ + type = ICQ_MSGxAR_DND; + }else if (status & ICQ_STATUS_OCCUPIED){ + type = ICQ_MSGxAR_OCCUPIED; + }else if (status & ICQ_STATUS_NA){ + type = ICQ_MSGxAR_NA; + }else if (status & ICQ_STATUS_FFC){ + type = ICQ_MSGxAR_FFC; + } + + ICQBuffer msg; + msg.pack(type); + msg.pack((unsigned short)(m_client->fullStatus(m_client->m_status) & 0xFFFF)); + msg << 0x0100 << 0x0100 << (char)0; + + m_send.id.id_l = rand(); + m_send.id.id_h = rand(); + sendAdvMessage(m_client->screen(data), msg, PLUGIN_NULL, m_send.id, false, false); + return true; + }else if (m_send.flags == PLUGIN_RANDOMxCHAT){ + m_send.id.id_l = rand(); + m_send.id.id_h = rand(); + ICQBuffer b; + b << (char)1 << 0x00000000L << 0x00010000L; + sendAdvMessage(m_send.screen, b, PLUGIN_RANDOMxCHAT, m_send.id, false, false); + }else{ + unsigned plugin_index = m_send.flags; + log(L_DEBUG, "Plugin info request %s (%u)", qPrintable(m_send.screen), plugin_index); + + ICQBuffer b; + unsigned short type = 0; //Fixme: Local declaration of 'type' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '1771' + switch (plugin_index){ + case PLUGIN_QUERYxINFO: + case PLUGIN_PHONEBOOK: + case PLUGIN_PICTURE: + type = 2; + break; + } + b.pack((unsigned short)1); + b.pack((unsigned short)0); + b.pack((unsigned short)2); + b.pack((unsigned short)1); + b.pack((char)0); + b.pack((char*)m_client->plugins[plugin_index], sizeof(plugin)); + b.pack((unsigned long)0); + + m_send.id.id_l = rand(); + m_send.id.id_h = rand(); + sendAdvMessage(m_send.screen, b, type ? PLUGIN_INFOxMANAGER : PLUGIN_STATUSxMANAGER, m_send.id, false, false); + return true; + } + return false; +} + +static const plugin arrPlugins[] = + { + // PLUGIN_PHONExBOOK + { 0x90, 0x7C, 0x21, 0x2C, 0x91, 0x4D, + 0xD3, 0x11, 0xAD, 0xEB, 0x00, 0x04, + 0xAC, 0x96, 0xAA, 0xB2, 0x00, 0x00 }, + // PLUGIN_PICTURE + { 0x80, 0x66, 0x28, 0x83, 0x80, 0x28, + 0xD3, 0x11, 0x8D, 0xBB, 0x00, 0x10, + 0x4B, 0x06, 0x46, 0x2E, 0x00, 0x00 }, + // PLUGIN_FILExSERVER + { 0xF0, 0x2D, 0x12, 0xD9, 0x30, 0x91, + 0xD3, 0x11, 0x8D, 0xD7, 0x00, 0x10, + 0x4B, 0x06, 0x46, 0x2E, 0x04, 0x00 }, + // PLUGIN_FOLLOWxME + { 0x90, 0x7C, 0x21, 0x2C, 0x91, 0x4D, + 0xD3, 0x11, 0xAD, 0xEB, 0x00, 0x04, + 0xAC, 0x96, 0xAA, 0xB2, 0x02, 0x00 }, + // PLUGIN_ICQxPHONE + { 0x3F, 0xB6, 0x5E, 0x38, 0xA0, 0x30, + 0xD4, 0x11, 0xBD, 0x0F, 0x00, 0x06, + 0x29, 0xEE, 0x4D, 0xA1, 0x00, 0x00 }, + // PLUGIN_QUERYxINFO + { 0xF0, 0x02, 0xBF, 0x71, 0x43, 0x71, + 0xD3, 0x11, 0x8D, 0xD2, 0x00, 0x10, + 0x4B, 0x06, 0x46, 0x2E, 0x00, 0x00 }, + // PLUGIN_QUERYxSTATUS + { 0x10, 0x18, 0x06, 0x70, 0x54, 0x71, + 0xD3, 0x11, 0x8D, 0xD2, 0x00, 0x10, + 0x4B, 0x06, 0x46, 0x2E, 0x00, 0x00 }, + // PLUGIN_INFOxMANAGER + { 0xA0, 0xE9, 0x3F, 0x37, 0x4F, 0xE9, + 0xD3, 0x11, 0xBC, 0xD2, 0x00, 0x04, + 0xAC, 0x96, 0xDD, 0x96, 0x00, 0x00 }, + // PLUGIN_STATUSxMANAGER + { 0x10, 0xCF, 0x40, 0xD1, 0x4F, 0xE9, + 0xD3, 0x11, 0xBC, 0xD2, 0x00, 0x04, + 0xAC, 0x96, 0xDD, 0x96, 0x00, 0x00 }, + // PLUGIN_RANDOM_CHAT + { 0x60, 0xF1, 0xA8, 0x3D, 0x91, 0x49, + 0xD3, 0x11, 0x8D, 0xBE, 0x00, 0x10, + 0x4B, 0x06, 0x46, 0x2E, 0x00, 0x00 }, + // PLUGIN_VIDEO_CHAT + { 0x68, 0x33, 0x01, 0x6B, 0x0B, 0x7D, + 0x36, 0x4B, 0x98, 0x6C, 0x63, 0x72, + 0x01, 0x5E, 0x7C, 0x8E, 0x00, 0x00 }, + // PLUGIN_NULL + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + // PLUGIN_FILE + { 0xF0, 0x2D, 0x12, 0xD9, 0x30, 0x91, + 0xD3, 0x11, 0x8D, 0xD7, 0x00, 0x10, + 0x4B, 0x06, 0x46, 0x2E, 0x00, 0x00 }, + // PLUGIN_CHAT + { 0xBF, 0xF7, 0x20, 0xB2, 0x37, 0x8E, + 0xD4, 0x11, 0xBD, 0x28, 0x00, 0x04, + 0xAC, 0x96, 0xD9, 0x05, 0x00, 0x00 } + }; + +plugin const *ICQClient::plugins = arrPlugins; + +bool operator == (const MessageId &m1, const MessageId &m2) +{ + return ((m1.id_l == m2.id_l) && (m1.id_h == m2.id_h)); +} +/* +#ifndef NO_MOC_INCLUDES +#include "icqicmb.moc" +#endif +*/ diff --git a/plugins/icq/icqicmb.h b/plugins/icq/icqicmb.h new file mode 100644 index 0000000..f0a08f9 --- /dev/null +++ b/plugins/icq/icqicmb.h @@ -0,0 +1,106 @@ + +#ifndef ICQICMB_H +#define ICQICMB_H + +#include +#include +#include "snac.h" +#include "message.h" + +class ICQBuffer; +class ICQClientSocket; +class DirectSocket; +class TlvList; +class QTimer; + +struct ICQUserData; + + +struct MessageId +{ + unsigned long id_l; + unsigned long id_h; + MessageId() : id_l(0), id_h(0) {} +}; + +bool operator == (const MessageId &m1, const MessageId &m2); +namespace SIM +{ + class Message; +} + +struct SendMsg +{ + QString screen; + MessageId id; + SIM::Message *msg; + QString text; + QString part; + unsigned flags; + DirectSocket *socket; + SendMsg() : msg(NULL), socket(NULL) {} +}; + +typedef unsigned char plugin[0x12]; + +class SnacIcqICBM : public QObject, public SnacHandler +{ + Q_OBJECT +public: + SnacIcqICBM(ICQClient* client); + virtual ~SnacIcqICBM(); + + virtual bool process(unsigned short subtype, ICQBuffer* buf, unsigned short seq); + void rightsRequest(); + void sendICMB(unsigned short channel, unsigned long flags); + void sendThroughServer(const QString &screen, unsigned short channel, ICQBuffer &b, const MessageId &id, bool bOffline, bool bReqAck); + void sendType2(const QString &screen, ICQBuffer &msgBuf, const MessageId &id, unsigned cap, bool bOffline, unsigned short port, TlvList *tlvs = NULL, unsigned short type = 1); + bool ackMessage(SIM::Message *msg, unsigned short ackFlags, const QByteArray &msg_str); + void sendType1(const QString &text, bool bWide, ICQUserData *data); + void sendAdvMessage(const QString &screen, ICQBuffer &msgText, unsigned plugin_index, + const MessageId &id, bool bOffline, bool bDirect, unsigned short cookie1 = 0, + unsigned short cookie2 = 0, unsigned short type = 1); + void ackMessage(SendMsg &s); + bool sendThruServer(SIM::Message *msg, void *_data); + void clearMsgQueue(); + void sendFile(TlvList& tlv, unsigned long primary_ip, unsigned long secondary_ip, unsigned short port,const QString &screen, MessageId const& id); + void sendAutoReply(const QString &screen, MessageId id, + const plugin p, unsigned short cookie1, unsigned short cookie2, + unsigned short msgType, char msgFlags, unsigned short msgState, + const QString &response, unsigned short response_type, ICQBuffer ©); + void sendMTN(const QString &screen, unsigned short type); + void accept(SIM::Message *msg, ICQUserData *data); + void accept(SIM::Message *msg, const QString &dir, SIM::OverwriteMode overwrite); + void decline(SIM::Message *msg, const QString &reason); + void requestReverseConnection(const QString &screen, DirectSocket *socket); + void parseAdvancedMessage(const QString &screen, ICQBuffer &m, bool needAck, MessageId id); + bool processMsg(); + bool cancelMessage(SIM::Message* msg); + void sendSMS(SendMsg msg); + void pluginInfoRequest(unsigned long, unsigned plugin_index); + + QTimer* getSendTimer() { return m_sendTimer; } + +public slots: + void processSendQueue(); + +protected: + virtual ICQClientSocket *socket(); + +protected slots: + void sendTimeout(); + +private: + QTimer *m_sendTimer; + SendMsg m_send; + std::list sendFgQueue; + std::list sendBgQueue; + std::list replyQueue; + std::list smsQueue; + + friend class SMSRequest; + friend class ICQClient; +}; + +#endif + diff --git a/plugins/icq/icqinfo.cpp b/plugins/icq/icqinfo.cpp new file mode 100644 index 0000000..3a9fe32 --- /dev/null +++ b/plugins/icq/icqinfo.cpp @@ -0,0 +1,275 @@ +/*************************************************************************** + icqinfo.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "icons.h" +#include "icqinfo.h" +#include "icqclient.h" +#include "simgui/ballonmsg.h" +#include "contacts/contact.h" + +#include +#include +#include +#include +#include +#include + +using namespace SIM; + +const ext_info chat_groups[] = + { + { I18N_NOOP("General chat"), 1 }, + { I18N_NOOP("Romance"), 2 }, + { I18N_NOOP("Games"), 3 }, + { I18N_NOOP("Students"), 4 }, + { I18N_NOOP("20 Something"), 5 }, + { I18N_NOOP("30 Something"), 6 }, + { I18N_NOOP("40 Something"), 7 }, + { I18N_NOOP("50 Plus"), 8 }, + { I18N_NOOP("Seeking Women"), 9 }, + { I18N_NOOP("Seeking Men"), 10 }, + { "", 0 } + }; + +const ext_info *p_chat_groups = chat_groups; + +ICQInfo::ICQInfo(QWidget *parent, ICQUserData *data, unsigned contact, ICQClient *client) : QWidget(parent) +{ + setupUi(this); + m_client = client; + m_data = data; + m_contact = contact; + edtUin->setReadOnly(true); + if (m_data){ + edtFirst->setReadOnly(true); + edtLast->setReadOnly(true); + edtNick->setReadOnly(true); + edtAutoReply->setReadOnly(true); + lblRandom->hide(); + cmbRandom->hide(); + tabWnd->removeTab(tabWnd->indexOf(password)); + }else{ + edtAutoReply->hide(); + connect(this, SIGNAL(raise(QWidget*)), topLevelWidget(), SLOT(raisePage(QWidget*))); + } + edtOnline->setReadOnly(true); + edtNA->setReadOnly(true); + edtExtIP->setReadOnly(true); + edtIntIP->setReadOnly(true); + edtClient->setReadOnly(true); + fill(); +} + +void ICQInfo::apply() +{ + ICQUserData *data = m_data; + if (data == NULL){ + if (m_client->getState() == Client::Connected){ + QString errMsg; + QWidget *errWidget = edtCurrent; + if (!edtPswd1->text().isEmpty() || !edtPswd2->text().isEmpty()){ + if (edtCurrent->text().isEmpty()){ + errMsg = i18n("Input current password"); + }else{ + if (edtPswd1->text() != edtPswd2->text()){ + errMsg = i18n("Confirm password does not match"); + errWidget = edtPswd2; + }else if (edtCurrent->text() != m_client->getPassword()){ + errMsg = i18n("Invalid password"); + } + } + } + if (!errMsg.isEmpty()){ + for (QWidget *p = parentWidget(); p; p = p->parentWidget()){ + if (p->inherits("QTabWidget")){ + static_cast(p)->setCurrentWidget(this); + break; + } + } + emit raise(this); + BalloonMsg::message(errMsg, errWidget); + return; + } + if (!edtPswd1->text().isEmpty()) + m_client->changePassword(edtPswd1->text()); + // clear Textboxes + edtCurrent->clear(); + edtPswd1->clear(); + edtPswd2->clear(); + } + m_data = &m_client->data.owner; + m_client->setRandomChatGroup(getComboValue(cmbRandom, chat_groups)); + } +} + +void ICQInfo::apply(Client *client, void *_data) +{ + if (client != m_client) + return; + ICQUserData *data = m_client->toICQUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + data->FirstName.str() = edtFirst->text(); + data->LastName.str() = edtLast->text(); + data->Nick.str() = edtNick->text(); +} + +bool ICQInfo::processEvent(Event *e) +{ + if (e->type() == eEventContact){ + EventContact *ec = static_cast(e); + if(ec->action() != EventContact::eChanged) + return false; + Contact *contact = ec->contact(); + if (contact->clientData.have(m_data)) + fill(); + } else + if ((e->type() == eEventMessageReceived) && m_data){ + EventMessage *em = static_cast(e); + Message *msg = em->msg(); + if (msg->type() == MessageStatus){ + if (m_client->dataName(m_data) == msg->client()) + fill(); + } + } else + if ((e->type() == eEventClientChanged) && (m_data == 0)){ + EventClientChanged *ecc = static_cast(e); + if (ecc->client() == m_client) + fill(); + } + return false; +} + +void ICQInfo::fill() +{ + ICQUserData *data = m_data; + if (data == NULL) data = &m_client->data.owner; + + edtUin->setText(QString::number(data->Uin.toULong())); + edtFirst->setText(data->FirstName.str()); + edtLast->setText(data->LastName.str()); + edtNick->setText(data->Nick.str()); + + if (m_data == NULL){ + if (edtFirst->text().isEmpty()) { + QString firstName = getContacts()->owner()->getFirstName(); + firstName = getToken(firstName, '/'); + edtFirst->setText(firstName); + } + if (edtLast->text().isEmpty()) { + QString lastName = getContacts()->owner()->getLastName(); + lastName = getToken(lastName, '/'); + edtLast->setText(lastName); + } + password->setEnabled(m_client->getState() == Client::Connected); + } + + cmbStatus->clear(); + unsigned status = STATUS_ONLINE; + if (m_data){ + unsigned s = m_data->Status.toULong(); + if (s == ICQ_STATUS_OFFLINE){ + status = STATUS_OFFLINE; + }else if (s & ICQ_STATUS_DND){ + status = STATUS_DND; + }else if (s & ICQ_STATUS_OCCUPIED){ + status = STATUS_OCCUPIED; + }else if (s & ICQ_STATUS_NA){ + status = STATUS_NA; + }else if (s & ICQ_STATUS_AWAY){ + status = STATUS_AWAY; + }else if (s & ICQ_STATUS_FFC){ + status = STATUS_FFC; + } + }else{ + status = m_client->getStatus(); + initCombo(cmbRandom, m_client->getRandomChatGroup(), chat_groups); + } + if ((status != STATUS_ONLINE) && (status != STATUS_OFFLINE) && m_data){ + edtAutoReply->setPlainText(m_data->AutoReply.str()); + }else{ + edtAutoReply->hide(); + } + + int current = 0; + QString text; + if (m_data && (status == STATUS_OFFLINE) && m_data->bInvisible.toBool()){ + cmbStatus->addItem(Pict("ICQ_invisible"), i18n("Possibly invisible")); + }else{ + ProtocolPtr proto = ICQPlugin::icq_plugin->m_icq; + ICQProtocol* icq = static_cast(proto.data()); + for (const CommandDef *cmd = icq->statusList(); cmd->id; cmd++){ + if (cmd->flags & COMMAND_CHECK_STATE) + continue; + if (status == cmd->id){ + current = cmbStatus->count(); + text = cmd->text; + } + cmbStatus->addItem(Pict(cmd->icon), i18n(cmd->text)); + } + } + cmbStatus->setCurrentIndex(current); + disableWidget(cmbStatus); + if (status == STATUS_OFFLINE){ + lblOnline->setText(i18n("Last online") + ':'); + edtOnline->setText(formatDateTime(data->StatusTime.toULong())); + lblNA->hide(); + edtNA->hide(); + }else{ + if (data->OnlineTime.toULong()){ + edtOnline->setText(formatDateTime(data->OnlineTime.toULong())); + }else{ + lblOnline->hide(); + edtOnline->hide(); + } + if ((status == STATUS_ONLINE) || text.isEmpty()){ + lblNA->hide(); + edtNA->hide(); + }else{ + lblNA->setText(i18n(text)); + edtNA->setText(formatDateTime(data->StatusTime.toULong())); + } + } + if (data->IP.ip()){ + edtExtIP->setText(formatAddr(data->IP, data->Port.toULong())); + }else{ + lblExtIP->hide(); + edtExtIP->hide(); + } + if ((data->RealIP.ip()) && ((data->IP.ip() == NULL) || (get_ip(data->IP) != get_ip(data->RealIP)))){ + edtIntIP->setText(formatAddr(data->RealIP, data->Port.toULong())); + }else{ + lblIntIP->hide(); + edtIntIP->hide(); + } + if (m_data){ + QString client_name = m_client->clientName(data); + if (client_name.length()){ + edtClient->setText(client_name); + }else{ + lblClient->hide(); + edtClient->hide(); + } + }else{ + QString name = PACKAGE; + name += ' '; + name += VERSION; +#ifdef WIN32 + name += "/win32"; +#endif + edtClient->setText(name); + } +} + diff --git a/plugins/icq/icqinfo.h b/plugins/icq/icqinfo.h new file mode 100644 index 0000000..ae3622a --- /dev/null +++ b/plugins/icq/icqinfo.h @@ -0,0 +1,46 @@ +/*************************************************************************** + icqinfo.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _ICQINFO_H +#define _ICQINFO_H + +#include "ui_icqinfobase.h" +#include "event.h" + +class ICQClient; +struct ICQUserData; + +class ICQInfo : public QWidget, public Ui::MainInfo, public SIM::EventReceiver +{ + Q_OBJECT +public: + ICQInfo(QWidget *parent, ICQUserData*, unsigned contact, ICQClient *client); +signals: + void raise(QWidget*); +public slots: + void apply(); + void apply(SIM::Client*, void*); +protected: + virtual bool processEvent(SIM::Event *e); + void fill(); + ICQUserData *m_data; + unsigned m_contact; + ICQClient *m_client; +}; + +#endif + diff --git a/plugins/icq/icqinfobase.ui b/plugins/icq/icqinfobase.ui new file mode 100644 index 0000000..fd7579f --- /dev/null +++ b/plugins/icq/icqinfobase.ui @@ -0,0 +1,841 @@ + + + MainInfo + + + + 0 + 0 + 390 + 337 + + + + Form5 + + + + 6 + + + 11 + + + + + 1 + + + + &Names + + + + 11 + + + 6 + + + + + + + + Last Name: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + + + + + 75 + true + + + + Uin: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + Nick: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + 0 + + + + + + + 192 + 192 + 192 + + + + + + + 255 + 255 + 255 + + + + + + + 223 + 223 + 223 + + + + + + + 96 + 96 + 96 + + + + + + + 128 + 128 + 128 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 192 + 192 + 192 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 128 + + + + + + + 255 + 255 + 255 + + + + + + + + + 0 + 0 + 0 + + + + + + + 192 + 192 + 192 + + + + + + + 255 + 255 + 255 + + + + + + + 220 + 220 + 220 + + + + + + + 96 + 96 + 96 + + + + + + + 128 + 128 + 128 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 192 + 192 + 192 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 128 + + + + + + + 255 + 255 + 255 + + + + + + + + + 128 + 128 + 128 + + + + + + + 192 + 192 + 192 + + + + + + + 255 + 255 + 255 + + + + + + + 220 + 220 + 220 + + + + + + + 96 + 96 + 96 + + + + + + + 128 + 128 + 128 + + + + + + + 128 + 128 + 128 + + + + + + + 255 + 255 + 255 + + + + + + + 128 + 128 + 128 + + + + + + + 255 + 255 + 255 + + + + + + + 192 + 192 + 192 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 128 + + + + + + + 255 + 255 + 255 + + + + + + + + QFrame::HLine + + + QFrame::Sunken + + + + + + + 6 + + + 0 + + + + + + 75 + true + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + + First Name: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + 0 + 0 + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + Random chat group: + + + false + + + + + + + + + + + &Status + + + + 11 + + + 6 + + + + + Status: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Online: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + + + + + External IP: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Internal IP: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Client: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + + + + &Password + + + + 11 + + + 6 + + + + + New password: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + QLineEdit::Password + + + + + + + QLineEdit::Password + + + + + + + Retype new password: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + Current password: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + QFrame::HLine + + + QFrame::Sunken + + + + + + + QLineEdit::Password + + + + + + + + + + + tabWnd + edtUin + edtFirst + edtLast + edtNick + cmbRandom + cmbStatus + edtOnline + edtNA + edtExtIP + edtIntIP + edtClient + + + + diff --git a/plugins/icq/icqlists.cpp b/plugins/icq/icqlists.cpp new file mode 100644 index 0000000..abb1f9e --- /dev/null +++ b/plugins/icq/icqlists.cpp @@ -0,0 +1,1812 @@ +/*************************************************************************** + icqlists.cpp - description + ------------------- + begin : Sun Mar 10 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "icqclient.h" +#include "icqmessage.h" +#include "core_events.h" +#include "contacts/contact.h" +#include "contacts/group.h" + +#ifndef WIN32 +#include +#else +#include // htons +#endif +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "log.h" + +using namespace std; +using namespace SIM; + +const unsigned short ICQ_SNACxLISTS_ERROR = 0x0001; +const unsigned short ICQ_SNACxLISTS_REQxRIGHTS = 0x0002; +const unsigned short ICQ_SNACxLISTS_RIGHTS = 0x0003; +const unsigned short ICQ_SNACxLISTS_REQxROSTER = 0x0005; +const unsigned short ICQ_SNACxLISTS_ROSTER = 0x0006; +const unsigned short ICQ_SNACxLISTS_ACTIVATE = 0x0007; +const unsigned short ICQ_SNACxLISTS_CREATE = 0x0008; +const unsigned short ICQ_SNACxLISTS_UPDATE = 0x0009; +const unsigned short ICQ_SNACxLISTS_DELETE = 0x000A; +const unsigned short ICQ_SNACxLISTS_DONE = 0x000E; +const unsigned short ICQ_SNACxLISTS_ROSTERxOK = 0x000F; +const unsigned short ICQ_SNACxLISTS_EDIT = 0x0011; +const unsigned short ICQ_SNACxLISTS_SAVE = 0x0012; +const unsigned short ICQ_SNACxLISTS_FUTURE_AUTH = 0x0014; +const unsigned short ICQ_SNACxLISTS_FUTURE_GRANT = 0x0015; +const unsigned short ICQ_SNACxLISTS_REQUEST_AUTH = 0x0018; +const unsigned short ICQ_SNACxLISTS_AUTHxREQUEST = 0x0019; +const unsigned short ICQ_SNACxLISTS_AUTHxSEND = 0x001A; +const unsigned short ICQ_SNACxLISTS_AUTH = 0x001B; +const unsigned short ICQ_SNACxLISTS_ADDED = 0x001C; + +const unsigned short ICQ_USER = 0x0000; +const unsigned short ICQ_GROUPS = 0x0001; +const unsigned short ICQ_VISIBLE_LIST = 0x0002; +const unsigned short ICQ_INVISIBLE_LIST = 0x0003; +const unsigned short ICQ_INVISIBLE_STATE = 0x0004; +const unsigned short ICQ_PRESENCE_INFO = 0x0005; +const unsigned short ICQ_SHORTCUT_BAR = 0x0009; +const unsigned short ICQ_IGNORE_LIST = 0x000E; +const unsigned short ICQ_LAST_UPDATE = 0x000F; +const unsigned short ICQ_NON_IM = 0x0010; +const unsigned short ICQ_UNKNOWN = 0x0011; +const unsigned short ICQ_IMPORT_TIME = 0x0013; +const unsigned short ICQ_BUDDY_CHECKSUM = 0x0014; +const unsigned short ICQ_UNKNOWN2 = 0x0019; +const unsigned short ICQ_UNKNOWN3 = 0x001A; +const unsigned short ICQ_AWAITING_AUTH = 0x001B; + +const unsigned short TLV_WAIT_AUTH = 0x0066; +const unsigned short TLV_UNKNOWN2 = 0x006d; +const unsigned short TLV_UNKNOWN3 = 0x006e; +const unsigned short TLV_SUBITEMS = 0x00C8; +const unsigned short TLV_SHORTCUT_BAR = 0x00cd; +const unsigned short TLV_TIME = 0x00D4; +const unsigned short TLV_BUDDYHASH = 0x00D5; +const unsigned short TLV_ALIAS = 0x0131; +const unsigned short TLV_CELLULAR = 0x013A; +const unsigned short TLV_UNKNOWN4 = 0x015c; +const unsigned short TLV_UNKNOWN5 = 0x015d; + +const unsigned LIST_REQUEST_TIMEOUT = 50; + +class ListServerRequest +{ +public: + ListServerRequest(unsigned short seq) : m_seq(seq), m_time(QDateTime::currentDateTime()) {} + virtual ~ListServerRequest() {}; + + virtual void process(ICQClient *client, unsigned short res) + { + Q_UNUSED(res); + if(client->isSSITransaction()) + { + client->snac(ICQ_SNACxFOOD_LISTS, ICQ_SNACxLISTS_SAVE, true, false); + client->sendPacket(true); + } + } + + unsigned short seq() const { return m_seq; } + QDateTime getTime() const { return m_time; } +protected: + unsigned short m_seq; + QDateTime m_time; +}; + +class GroupServerRequest : public ListServerRequest +{ +public: + GroupServerRequest(unsigned short seq, unsigned long id, unsigned short icq_id, const QString &name); + virtual void process(ICQClient *client, unsigned short res); +protected: + unsigned long m_id; + unsigned short m_icqId; + QString m_name; +}; + +class ContactServerRequest : public ListServerRequest +{ +public: + ContactServerRequest(unsigned short seq, const QString &screen, + unsigned short icq_id, unsigned short grp_id, TlvList *tlv = NULL); + ~ContactServerRequest(); + virtual void process(ICQClient *client, unsigned short res); +protected: + QString m_screen; + unsigned short m_icqId; + unsigned short m_grpId; + TlvList *m_tlv; +}; + +class SetListRequest : public ListServerRequest +{ +public: + SetListRequest(unsigned short seq, const QString &screen, + unsigned short icq_id, unsigned short type); + virtual void process(ICQClient *client, unsigned short res); +protected: + QString m_screen; + unsigned short m_icqId; + unsigned short m_type; +}; + +class SetBuddyRequest : public ListServerRequest +{ +public: + SetBuddyRequest(unsigned short seq, const ICQUserData *icqUserData); + virtual void process(ICQClient *client, unsigned short res); +protected: + const ICQUserData *m_icqUserData; +}; + +static char PLEASE_UPGRADE[] = "PleaseUpgrade"; + +void ICQClient::parseRosterItem(unsigned short type, + const QString &str, + unsigned short grp_id, + unsigned short id, + TlvList *inf, + bool &bIgnoreTime) +{ + int seq; + + switch (type){ + case ICQ_USER: { + if (str.length()){ + if (str.startsWith(PLEASE_UPGRADE)){ + log(L_DEBUG, "Upgrade warning"); + return; + } + log(L_DEBUG, "User %s", qPrintable(str)); + // check for own uin in contact list + if (!m_bAIM && (str.toULong() == getUin())) { + log(L_DEBUG, "Own UIN in contact list - removing!"); + seq = sendRoster(ICQ_SNACxLISTS_DELETE, QString::null, grp_id, id); + m_listRequest = new ContactServerRequest(seq, QString::number(id), 0, 0); + break; + } + ListRequest *lr = findContactListRequest(str); + if (lr){ + log(L_DEBUG, "Request found"); + lr->icq_id = id; + lr->grp_id = grp_id; + Contact *contact; + ICQUserData *data = findContact(lr->screen, NULL, false, contact); + if (data){ + data->IcqID.asULong() = id; + data->GrpId.asULong() = grp_id; + } + }else{ + bool bChanged = false; + QString alias; + Tlv *tlv_name = inf ? (*inf)(TLV_ALIAS) : NULL; + if (tlv_name) + alias = QString::fromUtf8(*tlv_name); + log(L_DEBUG, "User %s [%s] id %u - group %u", qPrintable(str), qPrintable(alias), id, grp_id); + Contact *contact; + Group *grp = NULL; + ICQUserData *data = findGroup(grp_id, NULL, grp); + data = findContact(str, &alias, true, contact, grp); + if(data) + { + Tlv* unknown2 = inf ? (*inf)(TLV_UNKNOWN2) : NULL; + if(unknown2) + { + data->unknown2.setBinary(unknown2->byteArray()); + } + Tlv* unknown4 = inf ? (*inf)(TLV_UNKNOWN4) : NULL; + if(unknown4) + { + data->unknown4.setBinary(unknown4->byteArray()); + } + Tlv* unknown5 = inf ? (*inf)(TLV_UNKNOWN5) : NULL; + if(unknown5) + { + data->unknown5.setBinary(unknown5->byteArray()); + } + } + if (inf && (*inf)(TLV_WAIT_AUTH)){ + if (!data->WaitAuth.toBool()){ + data->WaitAuth.asBool() = true; + bChanged = true; + } + } else { + /* if not TLV(WAIT_AUTH) we are authorized ... */ + if (inf && !(*inf)(TLV_WAIT_AUTH)) { + if (data->WaitAuth.toBool()){ + data->WaitAuth.asBool() = false; + bChanged = true; + } + } + } + data->IcqID.asULong() = id; + data->GrpId.asULong() = grp_id; + Tlv *tlv_phone = inf ? (*inf)(TLV_CELLULAR) : NULL; + if (tlv_phone){ + data->Cellular.str() = QString::fromUtf8(*tlv_phone); + QString phone = trimPhone(data->Cellular.str()); + QString phone_str = quoteChars(phone, ","); + phone_str += ",Private Cellular,"; + phone_str += QString::number(CELLULAR); + bChanged |= contact->setPhones(phone_str, NULL); + }else{ + data->Cellular.clear(); + } + if (bChanged){ + EventContact e(contact, EventContact::eChanged); + e.process(); + } + if ((data->InfoFetchTime.toULong() == 0) && data->Uin.toULong()) + addFullInfoRequest(data->Uin.toULong()); + } + }else{ + bIgnoreTime = true; + } + break; + } + case ICQ_GROUPS:{ + if (str.isEmpty()) + break; + log(L_DEBUG, "group %s %u", qPrintable(str), grp_id); + ListRequest *lr = findGroupListRequest(grp_id); + if (lr) + break; + Group *grp; + ICQUserData *data = findGroup(grp_id, &str, grp); + if (data->IcqID.toULong()){ + lr = findGroupListRequest((unsigned short)(data->IcqID.toULong())); + if (lr) + removeListRequest(lr); + } + data->IcqID.asULong() = grp_id; + data->bChecked.asBool() = true; + if (grp->getName() != str){ + grp->setName(str); + EventGroup e(grp, EventGroup::eChanged); + e.process(); + } + break; + } + case ICQ_VISIBLE_LIST:{ + if (str.length()){ + log(L_DEBUG, "Visible %s", qPrintable(str)); + ListRequest *lr = findContactListRequest(str); + if (lr) + lr->visible_id = id; + if ((lr == NULL) || (lr->type != LIST_USER_DELETED)){ + Contact *contact; + ICQUserData *data = findContact(str, NULL, true, contact); + data->ContactVisibleId.asULong() = id; + if ((lr == NULL) && (data->VisibleId.toULong() != id)){ + data->VisibleId.asULong() = id; + EventContact e(contact, EventContact::eChanged); + e.process(); + } + if ((data->InfoFetchTime.toULong() == 0) && data->Uin.toULong()) + addFullInfoRequest(data->Uin.toULong()); + } + } + break; + } + case ICQ_INVISIBLE_LIST:{ + if (str.length()){ + log(L_DEBUG, "Invisible %s", qPrintable(str)); + ListRequest *lr = findContactListRequest(str); + if (lr) + lr->invisible_id = id; + if ((lr == NULL) || (lr->type != LIST_USER_DELETED)){ + Contact *contact; + ICQUserData *data = findContact(str, NULL, true, contact); + data->ContactInvisibleId.asULong() = id; + if ((lr == NULL) && (data->InvisibleId.toULong() != id)){ + data->InvisibleId.asULong() = id; + EventContact e(contact, EventContact::eChanged); + e.process(); + } + if ((data->InfoFetchTime.toULong() == 0) && data->Uin.toULong()) + addFullInfoRequest(data->Uin.toULong()); + } + } + break; + } + case ICQ_IGNORE_LIST:{ + if (str.length()){ + log(L_DEBUG, "Ignore %s", qPrintable(str)); + ListRequest *lr = findContactListRequest(str); + if (lr) + lr->ignore_id = id; + Contact *contact; + ICQUserData *data = findContact(str, NULL, true, contact); + if (data->IgnoreId.toULong() != id){ + data->IgnoreId.asULong() = id; + if (lr == NULL){ + contact->setIgnore(true); + EventContact e(contact, EventContact::eChanged); + e.process(); + } + } + } + break; + } + case ICQ_INVISIBLE_STATE: + setContactsInvisible(id); + break; + case ICQ_PRESENCE_INFO: + break; + case ICQ_BUDDY_CHECKSUM: { + if (str.length()){ + Tlv *tlv_buddyHash = inf ? (*inf)(TLV_BUDDYHASH) : NULL; + if(tlv_buddyHash) { + const QByteArray &ba = data.owner.buddyHash.toBinary(); + unsigned char flag, size; + QByteArray buddyHash; + + flag = tlv_buddyHash->Data()[0]; + size = tlv_buddyHash->Data()[1]; + buddyHash.resize(size); + memcpy(buddyHash.data(), &tlv_buddyHash->Data()[2], size); + + if(ba != buddyHash) { + data.owner.buddyHash.asBinary() = buddyHash; + data.owner.buddyID.asULong() = flag; + } + data.owner.buddyRosterID.asULong() = id; + } + } + break; + } + case ICQ_LAST_UPDATE: + case ICQ_UNKNOWN: + break; + case ICQ_UNKNOWN3: + if(inf) { + Tlv *tlv_uk3 = NULL; + tlv_uk3 = (*inf)(TLV_UNKNOWN3); + } + break; + case ICQ_SHORTCUT_BAR: + if(inf) { + Tlv *tlv_sc = NULL; + tlv_sc = (*inf)(TLV_SHORTCUT_BAR); + } + break; + case ICQ_UNKNOWN2: + if(inf) { + Tlv *tlv_uk2 = NULL; + tlv_uk2 = (*inf)(TLV_UNKNOWN2); + } + break; + case ICQ_NON_IM: { + Tlv *tlv_name = NULL; + Tlv *tlv_phone = NULL; + QString alias; + QString phone; + + if (inf) { + tlv_name = (*inf)(TLV_ALIAS); + if (tlv_name) + alias = (char*)(*tlv_name); + tlv_phone = (*inf)(TLV_CELLULAR); + if (tlv_phone){ + phone = (char*)(*tlv_phone); + } + log (L_DEBUG,"External Contact: %s Phone: %s", + qPrintable(alias), + qPrintable(phone)); + } + break; + } + case ICQ_IMPORT_TIME:{ + Tlv *tlv_time = NULL; + QDateTime qt_time; + + if (inf) { + tlv_time = (*inf)(TLV_TIME); + qt_time.setTime_t((uint32_t)(*tlv_time)); + log (L_DEBUG, "Import Time %s",qPrintable(qt_time.toString())); + } + break; + } + case ICQ_AWAITING_AUTH: { + Contact *contact; + if (str.length()){ + log(L_DEBUG, "%s is awaiting auth", qPrintable(str)); + ICQUserData *data; + if ((data = findContact(str, NULL, false, contact)) != NULL) { + addFullInfoRequest(str.toULong()); + data->WantAuth.asBool() = true; + } else { + log(L_DEBUG, "not in contact list, skipped"); + } + } + break; + } + default: + log(L_WARN,"Unknown roster type %04X", type); + } +} + +void ICQClient::snac_lists(unsigned short type, unsigned short seq) +{ + switch (type){ + case ICQ_SNACxLISTS_ERROR: + break; + case ICQ_SNACxLISTS_RIGHTS: + log(L_DEBUG, "List rights"); + break; + case ICQ_SNACxLISTS_EDIT: { + log(L_DEBUG, "Server begins SSI transaction"); + break; + } + case ICQ_SNACxLISTS_SAVE: { + log(L_DEBUG, "Server ends SSI transaction"); + break; + } + case ICQ_SNACxLISTS_CREATE: { + log(L_DEBUG, "Server adds new item"); + break; + } + case ICQ_SNACxLISTS_UPDATE: { + QString name; + unsigned short id, grp_id, type, len; + bool tmp; + + socket()->readBuffer().unpackStr(name); + socket()->readBuffer() >> grp_id >> id >> type >> len; + TlvList *inf = NULL; + if (len){ + ICQBuffer b(len); + b.pack(socket()->readBuffer().data(socket()->readBuffer().readPos()), len); + socket()->readBuffer().incReadPos(len); + inf = new TlvList(b); + } + log(L_DEBUG, "Server updates item: group_id = %d; id = %d", grp_id, id); + parseRosterItem(type,name,grp_id,id,inf,tmp); + delete inf; + break; + } + case ICQ_SNACxLISTS_DELETE: { + log(L_DEBUG, "Server deletes item"); + break; + } + case ICQ_SNACxLISTS_ROSTER:{ + char c; + unsigned short list_len; + log(L_DEBUG,"Rosters"); + socket()->readBuffer() >> c; + if (c){ + log(L_WARN, "Unknown SSI-Version 0x%02X", c); + break; + } + bool bIgnoreTime = false; + if (!m_bRosters){ + m_bRosters = true; + m_bJoin = false; + setContactsInvisible(0); + Group *grp; + ContactList::GroupIterator it_g; + while ((grp = ++it_g) != NULL){ + ICQUserData *data; + ClientDataIterator it(grp->clientData, this); + while ((data = toICQUserData(++it)) != NULL){ + if (data->IcqID.toULong() == 0){ + data->bChecked.asBool() = true; + continue; + } + data->bChecked.asBool() = false; + } + } + Contact *contact; + ContactList::ContactIterator it_c; + while ((contact = ++it_c) != NULL){ + ICQUserData *data; + ClientDataIterator it(contact->clientData, this); + while ((data = toICQUserData(++it)) != NULL){ + data->bChecked.asBool() = false; + data->GrpId.asULong() = 0; + data->IgnoreId.asULong() = 0; + data->VisibleId.asULong() = 0; + data->InvisibleId.asULong() = 0; + } + } + } + socket()->readBuffer() >> list_len; + for (unsigned i = 0; i < list_len; i++){ + QString name; + unsigned short id, grp_id, type, len; + socket()->readBuffer().unpackStr(name); + socket()->readBuffer() >> grp_id >> id >> type >> len; + TlvList *inf = NULL; + if (len){ + ICQBuffer b(len); + b.pack(socket()->readBuffer().data(socket()->readBuffer().readPos()), len); + socket()->readBuffer().incReadPos(len); + inf = new TlvList(b); + } + parseRosterItem(type, name, grp_id, id, inf, bIgnoreTime); + delete inf; + } + unsigned long time; + socket()->readBuffer() >> time; + if ((time == 0) && list_len && !bIgnoreTime) + break; + setContactsTime(time); + Group *grp; + ContactList::GroupIterator it_g; + list forRemove; + while ((grp = ++it_g) != NULL){ + ICQUserData *data = toICQUserData((SIM::clientData*)grp->clientData.getData(this)); // FIXME unsafe type conversion + QString n; + if (grp->id()) + n = grp->getName(); + log(L_DEBUG, "Check %ld %s %p %u", grp->id(), qPrintable(n), data, data ? data->bChecked.toBool() : 0); + if ((data == NULL) || data->bChecked.toBool()) + continue; + ListRequest *lr = findGroupListRequest((unsigned short)(data->IcqID.toULong())); + if (lr) + continue; + forRemove.push_back(grp); + } + for (list::iterator it = forRemove.begin(); it != forRemove.end(); ++it){ + delete *it; + } + + Contact *contact; + ContactList::ContactIterator it_c; + while ((contact = ++it_c) != NULL){ + ICQUserData *data; + SIM::clientData * client_data; + ClientDataIterator it_d(contact->clientData); + bool bOther = (contact->clientData.size() == 0); + bool bMy = false; + unsigned long newGroup = 0; + while ((client_data = ++it_d) != NULL){ + if (it_d.client() != this){ + bOther = true; + continue; + } + data=toICQUserData(client_data); // Will get here only when client is our's so feel free to converse + unsigned grpId = data->GrpId.toULong(); + ContactList::GroupIterator it_g; + while ((grp = ++it_g) != NULL){ + ICQUserData *data = toICQUserData((SIM::clientData*)grp->clientData.getData(this)); // FIXME unsafe type conversion + if (data && (data->IcqID.toULong() == grpId)) + break; + } + if (grp) + newGroup = grp->id(); + bMy = true; + } + if ((int)newGroup != contact->getGroup()){ + if ((newGroup == 0) && bOther){ + if (bMy) + addContactRequest(contact); + }else{ + contact->setGroup(newGroup); + EventContact e(contact, EventContact::eChanged); + e.process(); + } + } + } + } + getContacts()->save(); + if (m_bJoin){ + EventJoinAlert(this).process(); + m_bJoin = false; + } + case ICQ_SNACxLISTS_ROSTERxOK: // FALLTHROUGH + { + log(L_DEBUG, "Rosters OK"); + QTimer::singleShot(PING_TIMEOUT * 1000, this, SLOT(ping())); + setPreviousPassword(QString::null); + snac(ICQ_SNACxFOOD_LISTS, ICQ_SNACxLISTS_ACTIVATE, true, false); + sendPacket(true); + if (m_bAIM){ + Group *grp; + ContactList::GroupIterator it; + while ((grp = ++it) != NULL){ + if (grp->id()) + break; + } + if (grp == NULL){ + grp = getContacts()->group(0, true); + grp->setName("General"); + EventGroup e(grp, EventGroup::eChanged); + e.process(); + } + data.owner.OnlineTime.asULong() = QDateTime::currentDateTime().toTime_t(); + if (m_logonStatus == STATUS_ONLINE){ + m_status = STATUS_ONLINE; + sendCapability(); + snacICBM()->sendICMB(1, 11); + snacICBM()->sendICMB(2, 3); + snacICBM()->sendICMB(4, 3); + fetchProfiles(); + }else{ + m_status = STATUS_AWAY; + + ar_request req; + req.bDirect = false; + arRequests.push_back(req); + + ARRequest ar; + ar.contact = NULL; + ar.param = &arRequests.back(); + ar.receiver = this; + ar.status = m_logonStatus; + EventARRequest(&ar).process(); + } + m_snacService->sendClientReady(); + setState(Connected); + m_bReady = true; + snacICBM()->processSendQueue(); + break; + } + sendCapability(); + // 0x070b will send html text. + // Probably, later we can use it. + snacICBM()->sendICMB(0, 0x000b); + snacService()->sendLogonStatus(); + snacService()->sendClientReady(); + sendMessageRequest(); + + setState(Connected); + fetchProfiles(); + break; + } + case ICQ_SNACxLISTS_ADDED:{ + QString screen = socket()->readBuffer().unpackScreen(); + messageReceived(new AuthMessage(MessageAdded), screen); + break; + } + case ICQ_SNACxLISTS_AUTHxREQUEST:{ + QString screen = socket()->readBuffer().unpackScreen(); + QByteArray message; + QByteArray charset; + unsigned short have_charset; + socket()->readBuffer().unpackStr(message); + socket()->readBuffer() >> have_charset; + if (have_charset){ + socket()->readBuffer().incReadPos(2); + socket()->readBuffer().unpackStr(charset); + } + log(L_DEBUG, "Auth request %s", qPrintable(screen)); + Message *m = NULL; + if (charset.isEmpty()){ + AuthMessage *msg = new AuthMessage(MessageAuthRequest); + msg->setText(QString::fromUtf8(message)); + m = msg; + }else{ + ICQAuthMessage *msg = new ICQAuthMessage(MessageICQAuthRequest, MessageAuthRequest); + msg->setServerText(message); + msg->setCharset(charset); + m = msg; + } + messageReceived(m, screen); + Contact *contact; + ICQUserData *data = findContact(screen, NULL, false, contact); + if (data) + data->WantAuth.asBool() = true; + break; + } + case ICQ_SNACxLISTS_FUTURE_GRANT:{ + /* we treat future grant as normal grant but it isn't the same... + http://iserverd1.khstu.ru/oscar/snac_13_15.html */ + QString screen = socket()->readBuffer().unpackScreen(); + QByteArray message; + Message *m = NULL; + + socket()->readBuffer().unpackStr(message); + AuthMessage *msg = new AuthMessage(MessageAuthGranted); + msg->setText(QString::fromUtf8(message)); // toUnicode ?? + m = msg; + messageReceived(m, screen); + Contact *contact; + ICQUserData *data = findContact(screen, NULL, false, contact); + if (data){ + data->WaitAuth.asBool() = false; + EventContact e(contact, EventContact::eChanged); + e.process(); + addPluginInfoRequest(data->Uin.toULong(), PLUGIN_QUERYxSTATUS); + addPluginInfoRequest(data->Uin.toULong(), PLUGIN_QUERYxINFO); + } + } + case ICQ_SNACxLISTS_AUTH:{ + QString screen = socket()->readBuffer().unpackScreen(); + char auth_ok; + socket()->readBuffer() >> auth_ok; + QByteArray message; + QByteArray charset; + unsigned short have_charset; + socket()->readBuffer().unpackStr(message); + socket()->readBuffer() >> have_charset; + if (have_charset){ + socket()->readBuffer().incReadPos(2); + socket()->readBuffer().unpackStr(charset); + } + log(L_DEBUG, "Auth %u %s", auth_ok, qPrintable(screen)); + Message *m = NULL; + if (charset.isEmpty()){ + AuthMessage *msg = new AuthMessage(auth_ok ? MessageAuthGranted : MessageAuthRefused); + msg->setText(QString::fromUtf8(message)); + m = msg; + }else{ + ICQAuthMessage *msg = new ICQAuthMessage(auth_ok ? MessageICQAuthGranted : MessageICQAuthRefused, auth_ok ? MessageAuthGranted : MessageAuthRefused); + msg->setServerText(message); + msg->setCharset(charset); + m = msg; + } + messageReceived(m, screen); + if (auth_ok){ + Contact *contact; + ICQUserData *data = findContact(screen, NULL, false, contact); + if (data){ + data->WaitAuth.asBool() = false; + EventContact e(contact, EventContact::eChanged); + e.process(); + addPluginInfoRequest(data->Uin.toULong(), PLUGIN_QUERYxSTATUS); + addPluginInfoRequest(data->Uin.toULong(), PLUGIN_QUERYxINFO); + } + } + break; + } + case ICQ_SNACxLISTS_DONE: + if (m_listRequest && m_listRequest->seq() == seq) + { + unsigned short res; + const char *msg; + socket()->readBuffer() >> res; + switch (res) { + case 0x00: + msg = "No errors (success)"; + break; + case 0x02: + msg = "Item you want to modify not found in list"; + break; + case 0x03: + msg = "Item you want to add already exists"; + break; + case 0x0a: + msg = "Error adding item (invalid id, already in list, invalid data)"; + break; + case 0x0c: + msg = "Can't add item. Limit for this type of items exceeded"; + break; + case 0x0d: + msg = "Trying to add ICQ contact to an AIM list"; + break; + case 0x0e: + msg = "Can't add this contact because it requires authorization"; + break; + default: + msg = NULL; + } + if (msg) + log(L_DEBUG, "%s", msg); + else + log(L_DEBUG, "Unknown list request answer %u", res); + m_listRequest->process(this, res); + delete m_listRequest; + m_listRequest = NULL; + snacICBM()->processSendQueue(); + } + break; + default: + log(L_WARN, "Unknown lists foodgroup type %04X", type); + } +} + +void ICQClient::listsRequest() +{ + snac(ICQ_SNACxFOOD_LISTS, ICQ_SNACxLISTS_REQxRIGHTS, true, false); + sendPacket(true); + snac(ICQ_SNACxFOOD_LISTS, ICQ_SNACxLISTS_REQxROSTER, true, false); + unsigned long contactsTime = getContactsTime(); + unsigned short contactsLength = getContactsLength(); + socket()->writeBuffer() << contactsTime << contactsLength; + sendPacket(true); +} + +void ICQClient::sendInvisible(bool bInvisible) +{ + unsigned short cmd = ICQ_SNACxLISTS_UPDATE; + if (getContactsInvisible() == 0){ + cmd = ICQ_SNACxLISTS_CREATE; + setContactsInvisible((unsigned short)(get_random() & 0x7FFF)); + } + char data = bInvisible ? 4 : 3; + TlvList tlvs; + tlvs += new Tlv(0xCA, 1, &data); + sendRoster(cmd, NULL, 0, getContactsInvisible(), ICQ_INVISIBLE_STATE, &tlvs); +} + +ListRequest *ICQClient::findContactListRequest(const QString &screen) +{ + for (list::iterator it = listRequests.begin(); it != listRequests.end(); ++it){ + if (((it->type == LIST_USER_CHANGED) || (it->type == LIST_USER_DELETED)) && + (it->screen == screen)) + return &(*it); + } + return NULL; +} + +ListRequest *ICQClient::findGroupListRequest(unsigned short id) +{ + for (list::iterator it = listRequests.begin(); it != listRequests.end(); ++it){ + switch (it->type){ + case LIST_GROUP_DELETED: + case LIST_GROUP_CHANGED: + if (it->icq_id == id) + return &(*it); + break; + } + } + return NULL; +} + +void ICQClient::removeListRequest(ListRequest *lr) +{ + for (list::iterator it = listRequests.begin(); it != listRequests.end(); ++it){ + if (&(*it) == lr){ + listRequests.erase(it); + return; + } + } +} + +void ICQClient::clearListServerRequest() +{ + if (m_listRequest){ + delete m_listRequest; + m_listRequest = NULL; + } +} + +//----------------------------------------------------------------------------- + +GroupServerRequest::GroupServerRequest(unsigned short seq, unsigned long id, unsigned short icq_id, const QString &name) + : ListServerRequest(seq), m_id(id), m_icqId(icq_id), m_name(name) +{ +} + +void GroupServerRequest::process(ICQClient *client, unsigned short res) +{ + ListServerRequest::process(client, res); + + ListRequest *lr = client->findGroupListRequest(m_icqId); + if (lr && (lr->type == LIST_GROUP_DELETED)){ + lr->icq_id = 0; + return; + } + Group *group = getContacts()->group(m_id); + if (group == NULL) + return; + ICQUserData *data = client->toICQUserData((SIM::clientData*)group->clientData.getData(client)); // FIXME unsafe type conversion + if (data == NULL) + data = client->toICQUserData((SIM::clientData*)group->clientData.createData(client)); // FIXME unsafe type conversion + data->IcqID.asULong() = m_icqId; + data->Alias.str() = m_name; +} + +//----------------------------------------------------------------------------- + +ContactServerRequest::ContactServerRequest(unsigned short seq, const QString &screen, + unsigned short icq_id, unsigned short grp_id, TlvList *tlv) + : ListServerRequest(seq), m_screen(screen), m_icqId(icq_id), m_grpId(grp_id), m_tlv(tlv) +{ +} + +ContactServerRequest::~ContactServerRequest() +{ + delete m_tlv; +} + +void ContactServerRequest::process(ICQClient *client, unsigned short res) +{ + ListRequest *lr = client->findContactListRequest(m_screen); + if (lr && (lr->type == LIST_USER_DELETED)){ + lr->screen = QString::null; + lr->icq_id = 0; + lr->grp_id = 0; + return; + } + Contact *contact; + ICQUserData *data = client->findContact(m_screen, NULL, true, contact); + if(res == 0x0e) + { + //data->GrpId.setULong(0); + if(data->WaitAuth.toBool()) + { + client->ssiEndTransaction(); + client->ssiStartTransaction(); + TlvList *tlv = client->createListTlv(data, contact); + client->ssiAddBuddy(m_screen, m_grpId, (unsigned short) data->IcqID.toULong(), 0, tlv); + data->WaitAuth.setBool(true); + } + EventContact e(contact, EventContact::eChanged); + e.process(); + client->ssiEndTransaction(); + return; + } + data->IcqID.asULong() = m_icqId; + data->GrpId.asULong() = m_grpId; + if ((data->GrpId.toULong() == 0) && data->WaitAuth.toBool()){ + data->WaitAuth.asBool() = false; + EventContact e(contact, EventContact::eChanged); + e.process(); + } + if (m_tlv){ + Tlv *tlv_alias = (*m_tlv)(TLV_ALIAS); + if (tlv_alias){ + // ok here since Alias is utf8 and TLV_ALIAS too + data->Alias.str() = QString::fromUtf8(*tlv_alias); + }else{ + data->Alias.clear(); + } + Tlv *tlv_cell = (*m_tlv)(TLV_CELLULAR); + if (tlv_cell){ + data->Cellular.str() = QString::fromUtf8(*tlv_cell); + }else{ + data->Cellular.clear(); + } + } + ListServerRequest::process(client, res); +} + +//----------------------------------------------------------------------------- + +SetListRequest::SetListRequest(unsigned short seq, const QString &screen, + unsigned short icq_id, unsigned short type) + : ListServerRequest(seq), m_screen(screen), m_icqId(icq_id), m_type(type) +{ +} + +void SetListRequest::process(ICQClient *client, unsigned short res) +{ + ListServerRequest::process(client, res); + + ListRequest *lr = client->findContactListRequest(m_screen); + if (lr && (lr->type == LIST_USER_DELETED)){ + switch (m_type){ + case ICQ_VISIBLE_LIST: + lr->visible_id = 0; + break; + case ICQ_INVISIBLE_LIST: + lr->invisible_id = 0; + break; + case ICQ_IGNORE_LIST: + lr->ignore_id = 0; + break; + } + return; + } + Contact *contact; + ICQUserData *data = client->findContact(m_screen, NULL, true, contact); + switch (m_type){ + case ICQ_VISIBLE_LIST: + data->ContactVisibleId.asULong() = m_icqId; + break; + case ICQ_INVISIBLE_LIST: + data->ContactInvisibleId.asULong() = m_icqId; + break; + case ICQ_IGNORE_LIST: + data->IgnoreId.asULong() = m_icqId; + break; + } +} + +//----------------------------------------------------------------------------- +SetBuddyRequest::SetBuddyRequest(unsigned short seq, const ICQUserData *icqUserData) + : ListServerRequest(seq), m_icqUserData(icqUserData) +{ +} + +void SetBuddyRequest::process(ICQClient *client, unsigned short res) +{ + ListServerRequest::process(client, res); + + client->listRequests.erase(client->listRequests.begin()); + // item does not exist + if(res == 2) { + ListRequest lr; + lr.type = LIST_BUDDY_CHECKSUM; + lr.icq_id = m_icqUserData->buddyRosterID.toULong(); + lr.icqUserData = m_icqUserData; + client->listRequests.push_back(lr); + client->snacICBM()->processSendQueue(); + } + if(res != 0) + return; +} + +//----------------------------------------------------------------------------- + +unsigned short ICQClient::getListId() +{ + unsigned short id; + for (id = (unsigned short)(get_random() & 0x7FFF) ;; id++){ + id &= 0x7FFF; + if (id == 0) continue; + Group *group; + ContactList::GroupIterator it_grp; + while ((group = ++it_grp) != NULL){ + ICQUserData *data = toICQUserData((SIM::clientData*)group->clientData.getData(this)); // FIXME unsafe type conversion + if (data == NULL) + continue; + if (data->IcqID.toULong() == id) + break; + } + if (group) + continue; + Contact *contact; + ContactList::ContactIterator it_cnt; + while ((contact = ++it_cnt) != NULL){ + ClientDataIterator it(contact->clientData, this); + ICQUserData *data; + while((data = toICQUserData(++it)) != NULL){ + if((data->IcqID.toULong() == id) || (data->IgnoreId.toULong() == id) || + (data->VisibleId.toULong() == id) || (data->InvisibleId.toULong() == id)) + break; + } + if (data) + break; + } + if (contact) + continue; + break; + } + return id; +} + +TlvList *ICQClient::createListTlv(ICQUserData *data, Contact *contact) +{ + TlvList *tlv = new TlvList; //Fixme Leak, warning C6211: Leaking memory 'tlv' due to an exception. Consider using a local catch block to clean up memory: Lines: 1086, 1087, 1088 + QByteArray name = contact->getName().toUtf8(); + *tlv += new Tlv(TLV_ALIAS, (unsigned short)(name.length()), name); + if(data->WaitAuth.toBool()) + *tlv += new Tlv(TLV_WAIT_AUTH, 0, NULL); + QString cell = getUserCellular(contact); + if (cell.length()) + *tlv += new Tlv(TLV_CELLULAR, (unsigned short)(cell.length()), cell.toLatin1()); + if(data->unknown2.asBinary().size() > 0) + *tlv += new Tlv(TLV_UNKNOWN2, data->unknown2.asBinary().size() - 1, data->unknown2.asBinary().data()); + if(data->unknown4.asBinary().size() > 0) + *tlv += new Tlv(TLV_UNKNOWN4, data->unknown4.asBinary().size() - 1, data->unknown4.asBinary().data()); + if(data->unknown5.asBinary().size() > 0) + *tlv += new Tlv(TLV_UNKNOWN5, data->unknown5.asBinary().size() - 1, data->unknown5.asBinary().data()); + return tlv; +} + +void ICQClient::uploadBuddy(const ICQUserData *data) +{ + ListRequest lr; + lr.type = LIST_BUDDY_CHECKSUM; + lr.icq_id = data->buddyRosterID.toULong(); + lr.icqUserData = data; + listRequests.push_back(lr); + snacICBM()->processSendQueue(); +} + +void ICQClient::ssiStartTransaction() +{ + log(L_DEBUG, "ICQClient::ssiStartTransaction"); + snac(ICQ_SNACxFOOD_LISTS, ICQ_SNACxLISTS_EDIT, true, false); + sendPacket(true); +} + +void ICQClient::ssiEndTransaction() +{ + log(L_DEBUG, "ICQClient::ssiEndTransaction"); + snac(ICQ_SNACxFOOD_LISTS, ICQ_SNACxLISTS_SAVE, true, false); + sendPacket(true); +} + +unsigned short ICQClient::ssiAddBuddy(QString& screen, unsigned short group_id, unsigned short buddy_id, unsigned short buddy_type, TlvList* tlvs) +{ + log(L_DEBUG, "ICQClient::ssiAddBuddy"); + snac(ICQ_SNACxFOOD_LISTS, ICQ_SNACxLISTS_CREATE, true, false); + QByteArray utfscreen = screen.toUtf8(); + socket()->writeBuffer() << (unsigned short)utfscreen.length(); + socket()->writeBuffer().pack(utfscreen.data(), utfscreen.length()); + socket()->writeBuffer() << group_id << buddy_id << buddy_type; + if(!tlvs) + socket()->writeBuffer() << (unsigned short) 0x0000; + else + socket()->writeBuffer() << *tlvs; + sendPacket(true); + return m_nMsgSequence; +} + +unsigned short ICQClient::ssiDeleteBuddy(QString& screen, unsigned short group_id, unsigned short buddy_id, unsigned short buddy_type, TlvList* tlvs) +{ + log(L_DEBUG, "ICQClient::ssiDeleteBuddy"); + snac(ICQ_SNACxFOOD_LISTS, ICQ_SNACxLISTS_DELETE, true, false); + QByteArray utfscreen = screen.toUtf8(); + socket()->writeBuffer() << (unsigned short)utfscreen.length(); + socket()->writeBuffer().pack(utfscreen.data(), utfscreen.length()); + socket()->writeBuffer() << group_id << buddy_id << buddy_type; + if(!tlvs) + socket()->writeBuffer() << (unsigned short)0x0000; + else + socket()->writeBuffer() << *tlvs; + sendPacket(true); + return m_nMsgSequence; +} + +void ICQClient::getGroupIDs(unsigned short group_id, ICQBuffer* buf) +{ + if(!buf) + return; + ContactList::ContactIterator it; + Contact* contact; + ICQUserData *data; + while((contact = ++it) != NULL) + { + ClientDataIterator it(contact->clientData, this); + data = toICQUserData(++it); + if(!data) + continue; + if(data->GrpId.toULong() == group_id) + { + (*buf) << (unsigned short)data->IcqID.toULong(); + } + } +} + +unsigned short ICQClient::ssiAddToGroup(QString& groupname, unsigned short buddy_id, unsigned short group_id) +{ + QByteArray sName = groupname.toUtf8(); + snac(ICQ_SNACxFOOD_LISTS, ICQ_SNACxLISTS_UPDATE, true, false); + socket()->writeBuffer() << (unsigned short)sName.length(); + socket()->writeBuffer().pack(sName.data(), sName.length()); + socket()->writeBuffer() << group_id << (unsigned short)0x0000 << (unsigned short)0x0001; + ICQBuffer b; + getGroupIDs(group_id, &b); + b << buddy_id; + TlvList tlvs; + tlvs += new Tlv(TLV_SUBITEMS, b.writePos(), b.data()); + socket()->writeBuffer() << tlvs; + sendPacket(true); + return m_nMsgSequence; + +} + +unsigned short ICQClient::ssiRemoveFromGroup(QString& groupname, unsigned short buddy_id, unsigned short group_id) +{ + ContactList::ContactIterator it; + Contact* contact; + ICQUserData *data; + while((contact = ++it) != NULL) + { + ClientDataIterator it(contact->clientData, this); + data = toICQUserData(++it); + if(!data) + continue; + if(data->IcqID.toULong() == buddy_id) + { + data->GrpId.setULong(0); + break; + } + } + + QByteArray sName = groupname.toUtf8(); + snac(ICQ_SNACxFOOD_LISTS, ICQ_SNACxLISTS_UPDATE, true, false); + socket()->writeBuffer() << (unsigned short)sName.length(); + socket()->writeBuffer().pack(sName.data(), sName.length()); + socket()->writeBuffer() << group_id << (unsigned short)0x0000 << (unsigned short)0x0001; + ICQBuffer b; + getGroupIDs(group_id, &b); + TlvList tlvs; + tlvs += new Tlv(TLV_SUBITEMS, b.writePos(), b.data()); + socket()->writeBuffer() << tlvs; + sendPacket(true); + return m_nMsgSequence; +} + +unsigned short ICQClient::ssiModifyBuddy(const QString& name, unsigned short grp_id, unsigned short usr_id, unsigned short subCmd, TlvList* tlv) +{ + snac(ICQ_SNACxFOOD_LISTS, ICQ_SNACxLISTS_UPDATE, true, false); + QByteArray sName = name.toUtf8(); + socket()->writeBuffer().pack(static_cast(htons(sName.size()))); + socket()->writeBuffer().pack(sName.data(), sName.size()); + socket()->writeBuffer() + << grp_id + << usr_id + << subCmd; + if (tlv){ + socket()->writeBuffer() << *tlv; + }else{ + socket()->writeBuffer() << (unsigned short)0; + } + sendPacket(true); + return m_nMsgSequence; +} + +unsigned short ICQClient::sendRoster(unsigned short cmd, const QString &name, unsigned short grp_id, + unsigned short usr_id, unsigned short subCmd, TlvList *tlv) +{ + log(L_DEBUG, "ICQClient::sendRoster"); + // start edit SSI + snac(ICQ_SNACxFOOD_LISTS, ICQ_SNACxLISTS_EDIT, true, false); + sendPacket(true); + + snac(ICQ_SNACxFOOD_LISTS, cmd, true, false); + QByteArray sName = name.toUtf8(); + socket()->writeBuffer().pack(static_cast( htons(sName.length()) ) ); + socket()->writeBuffer().pack(sName.data(), sName.length()); + socket()->writeBuffer() + << grp_id + << usr_id + << subCmd; + if (tlv){ + socket()->writeBuffer() << *tlv; + }else{ + socket()->writeBuffer() << (unsigned short)0; + } + sendPacket(true); + return m_nMsgSequence; +} + +void ICQClient::sendRosterGrp(const QString &name, unsigned short grpId, unsigned short usrId) +{ + QByteArray sName = name.toUtf8(); + snac(ICQ_SNACxFOOD_LISTS, ICQ_SNACxLISTS_UPDATE, true, false); + socket()->writeBuffer().pack(sName.data(), sName.length()); + socket()->writeBuffer() + << grpId + << (unsigned long) ICQ_GROUPS; + if (usrId){ + socket()->writeBuffer() + << (unsigned short) 6 + << (unsigned short) 0xC8 + << (unsigned short) 2 + << (unsigned short) usrId; + }else{ + socket()->writeBuffer() + << (unsigned short) 4 + << (unsigned short) 0xC8 + << (unsigned short) 0; + } + sendPacket(true); +} + +static QString userStr(Contact *contact, const ICQUserData *data) +{ + QString name = contact ? contact->getName() : "unknown"; + return QString::number(data->Uin.toULong()) + '[' + name + ']'; +} + +unsigned ICQClient::processListRequest() +{ + if (m_listRequest || (getState() != Connected) || !m_bReady) + return false; + for (;;){ + if (listRequests.size() == 0) + return 0; + unsigned delay = delayTime(SNAC(ICQ_SNACxFOOD_LISTS, ICQ_SNACxLISTS_CREATE)); + if (delay) + return delay; + ListRequest &lr = listRequests.front(); + unsigned short seq = 0; + unsigned short icq_id; + Group *group = NULL; + Contact *contact; + ICQUserData *data; + unsigned grp_id = 0; + switch (lr.type){ + case LIST_USER_CHANGED: + data = findContact(lr.screen, NULL, false, contact); + if (data == NULL) + break; + if (data->VisibleId.toULong() != data->ContactVisibleId.toULong()){ + if ((data->VisibleId.toULong() == 0) || (data->ContactVisibleId.toULong() == 0)){ + if (data->VisibleId.toULong()){ + log(L_DEBUG, "%s add to visible list", qPrintable(userStr(contact, data))); + seq = sendRoster(ICQ_SNACxLISTS_CREATE, screen(data), 0, data->VisibleId.toULong(), ICQ_VISIBLE_LIST); + }else{ + log(L_DEBUG, "%s remove from visible list", qPrintable(userStr(contact, data))); + seq = sendRoster(ICQ_SNACxLISTS_DELETE, screen(data), 0, data->ContactVisibleId.toULong(), ICQ_VISIBLE_LIST); + } + m_listRequest = new SetListRequest(seq, screen(data), data->VisibleId.toULong(), ICQ_VISIBLE_LIST); + break; + } + data->VisibleId.asULong() = data->ContactVisibleId.toULong(); + } + if (data->InvisibleId.toULong() != data->ContactInvisibleId.toULong()){ + if ((data->InvisibleId.toULong() == 0) || (data->ContactInvisibleId.toULong() == 0)){ + if (data->InvisibleId.toULong()){ + log(L_DEBUG, "%s add to invisible list", qPrintable(userStr(contact, data))); + seq = sendRoster(ICQ_SNACxLISTS_CREATE, screen(data), 0, data->InvisibleId.toULong(), ICQ_INVISIBLE_LIST); + }else{ + log(L_DEBUG, "%s remove from invisible list", qPrintable(userStr(contact, data))); + seq = sendRoster(ICQ_SNACxLISTS_DELETE, screen(data), 0, data->ContactInvisibleId.toULong(), ICQ_INVISIBLE_LIST); + } + m_listRequest = new SetListRequest(seq, screen(data), data->InvisibleId.toULong(), ICQ_INVISIBLE_LIST); + break; + } + data->InvisibleId.asULong() = data->ContactInvisibleId.toULong(); + } + if (contact->getIgnore() != (data->IgnoreId.toULong() != 0)){ + unsigned short ignore_id = 0; + if (data->IgnoreId.toULong()){ + log(L_DEBUG, "%s remove from ignore list", qPrintable(userStr(contact, data))); + seq = sendRoster(ICQ_SNACxLISTS_DELETE, screen(data), 0, data->IgnoreId.toULong(), ICQ_IGNORE_LIST); + }else{ + ignore_id = getListId(); + log(L_DEBUG, "%s add to ignore list", qPrintable(userStr(contact, data))); + seq = sendRoster(ICQ_SNACxLISTS_CREATE, screen(data), 0, ignore_id, ICQ_IGNORE_LIST); + } + m_listRequest = new SetListRequest(seq, screen(data), ignore_id, ICQ_IGNORE_LIST); + break; + } + if (contact->getGroup()){ + group = getContacts()->group(contact->getGroup()); + if (group){ + ICQUserData *grp_data = toICQUserData((SIM::clientData*)group->clientData.getData(this)); // FIXME unsafe type conversion + if (grp_data) + grp_id = grp_data->IcqID.toULong(); + } + } + if (data->GrpId.toULong() != grp_id) + { + if (grp_id) + { + if (data->GrpId.toULong() == 0) + { + snac(ICQ_SNACxFOOD_LISTS, ICQ_SNACxLISTS_FUTURE_AUTH, true, false); + socket()->writeBuffer().packScreen(screen(data)); + socket()->writeBuffer() << 0x00000000L; + data->WaitAuth.setBool(true); + sendPacket(true); + } + if (data->IcqID.toULong() == 0) + data->IcqID.asULong() = getListId(); + TlvList *tlv = createListTlv(data, contact); + /* + if (data->GrpId.toULong()) + seq = sendRoster(ICQ_SNACxLISTS_DELETE, QString::null, data->GrpId.toULong(), data->IcqID.toULong()); + */ + QString name = screen(data); + QString groupname = group->getName(); + ssiStartTransaction(); + if(data->GrpId.toULong()) + { + seq = ssiDeleteBuddy(name, data->GrpId.toULong(), data->IcqID.toULong(), 0, tlv); + } + seq = ssiAddBuddy(name, grp_id, (unsigned short) data->IcqID.toULong(), 0, tlv); + ssiAddToGroup(groupname, data->IcqID.toULong(), grp_id); + data->GrpId.setULong(grp_id); + //ssiEndTransaction(); + /* + seq = sendRoster(ICQ_SNACxLISTS_CREATE, screen(data), grp_id, data->IcqID.toULong(), 0, tlv); + sendRosterGrp(group->getName(), grp_id, data->IcqID.toULong()); + */ + log(L_DEBUG, "%s move to group %s", qPrintable(userStr(contact, data)), qPrintable(group->getName())); + m_listRequest = new ContactServerRequest(seq, screen(data), data->IcqID.toULong(), grp_id, tlv); + } + else + { + log(L_DEBUG, "%s remove from contact list", qPrintable(userStr(contact, data))); + seq = sendRoster(ICQ_SNACxLISTS_DELETE, QString::null, data->GrpId.toULong(), data->IcqID.toULong()); + m_listRequest = new ContactServerRequest(seq, screen(data), 0, 0); + } + break; + } + if ((data->IcqID.toULong() == 0) || (data->Uin.toULong() == 0)) + break; + if (isContactRenamed(data, contact)){ + log(L_DEBUG, "%s rename", qPrintable(userStr(contact, data))); + TlvList *tlv = createListTlv(data, contact); + seq = sendRoster(ICQ_SNACxLISTS_UPDATE, screen(data), data->GrpId.toULong(), data->IcqID.toULong(), 0, tlv); + m_listRequest = new ContactServerRequest(seq, screen(data), data->IcqID.toULong(), data->GrpId.toULong(), tlv); + break; + } + break; + case LIST_USER_DELETED: + data = findContact(lr.screen, NULL, false, contact); + if (data == NULL) + break; + if (lr.visible_id){ + log(L_DEBUG, "%s remove from visible list", qPrintable(lr.screen)); + seq = sendRoster(ICQ_SNACxLISTS_DELETE, lr.screen, 0, lr.visible_id, ICQ_VISIBLE_LIST); + m_listRequest = new SetListRequest(seq, lr.screen, 0, ICQ_VISIBLE_LIST); + break; + } + if (lr.invisible_id){ + log(L_DEBUG, "%s remove from invisible list", qPrintable(lr.screen)); + seq = sendRoster(ICQ_SNACxLISTS_DELETE, lr.screen, 0, lr.invisible_id, ICQ_INVISIBLE_LIST); + m_listRequest = new SetListRequest(seq, lr.screen, 0, ICQ_INVISIBLE_LIST); + break; + } + if (lr.ignore_id){ + log(L_DEBUG, "%s remove from ignore list", qPrintable(lr.screen)); + seq = sendRoster(ICQ_SNACxLISTS_DELETE, lr.screen, 0, lr.ignore_id, ICQ_IGNORE_LIST); + m_listRequest = new SetListRequest(seq, lr.screen, 0, ICQ_IGNORE_LIST); + break; + } + if (lr.screen.length() && lr.grp_id){ + group = getContacts()->group(contact->getGroup()); + QString groupname = group->getName(); + /* + if(group) + { + ICQUserData *grp_data = toICQUserData((SIM::clientData*)group->clientData.getData(this)); // FIXME unsafe type conversion + if(grp_data) + grp_id = grp_data->IcqID.toULong(); + } + */ + log(L_DEBUG, "%s remove from contact list", qPrintable(lr.screen)); + seq = sendRoster(ICQ_SNACxLISTS_DELETE, QString::null, lr.grp_id, lr.icq_id); + seq = ssiRemoveFromGroup(groupname, lr.icq_id, lr.grp_id); + m_listRequest = new ContactServerRequest(seq, lr.screen, 0, 0); + } + break; + case LIST_GROUP_CHANGED: + group = getContacts()->group(lr.screen.toULong()); + if (group){ + QString name = group->getName(); + data = toICQUserData((SIM::clientData*)group->clientData.getData(this)); // FIXME unsafe type conversion + if (data){ + icq_id = (unsigned short)(data->IcqID.toULong()); + QString alias = data->Alias.str(); + if (alias != name){ + log(L_DEBUG, "rename group %s", qPrintable(group->getName())); + seq = sendRoster(ICQ_SNACxLISTS_UPDATE, name, icq_id, 0, ICQ_GROUPS); + } + }else{ + log(L_DEBUG, "create group %s", qPrintable(group->getName())); + icq_id = getListId(); + seq = sendRoster(ICQ_SNACxLISTS_CREATE, name, icq_id, 0, ICQ_GROUPS); + } + if (seq) + m_listRequest = new GroupServerRequest(seq, group->id(), icq_id, name); + } + break; + case LIST_GROUP_DELETED: + if (lr.icq_id){ + log(L_DEBUG, "delete group"); + seq = sendRoster(ICQ_SNACxLISTS_DELETE, QString::null, lr.icq_id, 0, ICQ_GROUPS); + m_listRequest = new GroupServerRequest(seq, 0, lr.icq_id, QString::null); + } + break; + case LIST_BUDDY_CHECKSUM: + if (lr.icqUserData){ + log(L_DEBUG, "Add/Modify buddy icon checksum"); + + QImage img(getPicture()); + if(img.isNull()) + break; + + QByteArray ba; + QBuffer buf(&ba); + if(!buf.open(QIODevice::WriteOnly)) { + log(L_ERROR, "Can't open QByteArray for writing!"); + break; + } + if(!img.save(&buf, "JPEG")) { + log(L_ERROR, "Can't save QImage to QBuffer"); + break; + } + buf.close(); + QByteArray hash = QCryptographicHash::hash(ba, QCryptographicHash::Md5); + if(hash == this->data.owner.buddyHash.toBinary() && + 1 == this->data.owner.buddyID.toULong()) { + log(L_DEBUG, "No need to upload buddy"); + // break; + } + + TlvList *tlvList = new TlvList; //Fixme Leak, warning C6211: Leaking memory 'tlvList' due to an exception. Consider using a local catch block to clean up memory: Lines: 1304, 1307, 1309, 1310, 1312, 1313, 1314, 1315, 1316, 1317, 1318, 1319, 1495, 1496, 1497, 1499, 1500, 1503, 1504, 1505, 1509, 1513, 1514, 1515, 1521, 1523, 1524, 1525, 1526, 1527 + + ba.resize(hash.size() + 2); + ba.data()[0] = 0x01; + ba.data()[1] = hash.size(); + memcpy(&ba.data()[2], hash.data(), hash.size()); + *tlvList += new Tlv(TLV_ALIAS, 0, NULL); + *tlvList += new Tlv(TLV_BUDDYHASH, ba.size(), ba.data()); + + //unsigned short seq = sendRoster(lr.icq_id ? ICQ_SNACxLISTS_UPDATE : ICQ_SNACxLISTS_CREATE, + // "1", lr.grp_id, lr.icq_id, ICQ_BUDDY_CHECKSUM, tlvList); + ssiStartTransaction(); + unsigned short seq = ssiModifyBuddy("1", lr.grp_id, lr.icq_id, ICQ_BUDDY_CHECKSUM, tlvList); + ssiEndTransaction(); + m_listRequest = new SetBuddyRequest(seq, &this->data.owner); + } + break; + } + if (m_listRequest) + break; + listRequests.erase(listRequests.begin()); + } + return 0; +} + +void ICQClient::checkListRequest() +{ + if (m_listRequest == NULL) + return; + if (QDateTime::currentDateTime() > (m_listRequest->getTime().addSecs(LIST_REQUEST_TIMEOUT))){ + log(L_WARN, "List request timeout"); + m_listRequest->process(this, USHRT_MAX); + delete m_listRequest; + m_listRequest = NULL; + snacICBM()->processSendQueue(); + } +} + +void ICQClient::addGroupRequest(Group *group) +{ + QString name; + name = group->getName(); + ICQUserData *data = toICQUserData((SIM::clientData*)group->clientData.getData(this)); // FIXME unsafe type conversion + if (data == NULL){ + list::iterator it; + for (it = listRequests.begin(); it != listRequests.end(); it++){ + if (it->type != LIST_GROUP_CHANGED) + continue; + if (it->screen.toULong() == group->id()) + return; + } + ListRequest lr; + lr.type = LIST_GROUP_CHANGED; + lr.screen = QString::number(group->id()); + listRequests.push_back(lr); + snacICBM()->processSendQueue(); + return; + } + list::iterator it; + for (it = listRequests.begin(); it != listRequests.end(); it++){ + if (it->type != LIST_GROUP_CHANGED) + continue; + if (it->icq_id == data->IcqID.toULong()) + return; + } + QString alias = data->Alias.str(); + if (alias == name) + return; + ListRequest lr; + lr.type = LIST_GROUP_CHANGED; + lr.icq_id = (unsigned short)(data->IcqID.toULong()); + lr.screen = QString::number(group->id()); + listRequests.push_back(lr); + snacICBM()->processSendQueue(); +} + +void ICQClient::addContactRequest(Contact *contact) +{ + ICQUserData *data; + ClientDataIterator it(contact->clientData, this); + while ((data = toICQUserData(++it)) != NULL){ + list::iterator it; + for (it = listRequests.begin(); it != listRequests.end(); it++){ + if (it->type != LIST_USER_CHANGED) + continue; + if (it->screen == screen(data)) + return; + } + + bool bChanged = false; + if (data->VisibleId.toULong() != data->ContactVisibleId.toULong()){ + if ((data->VisibleId.toULong() == 0) || (data->ContactVisibleId.toULong() == 0)){ + bChanged = true; + log(L_DEBUG, "%s change visible state", qPrintable(userStr(contact, data))); + }else{ + data->VisibleId.asULong() = data->ContactVisibleId.toULong(); + } + } + if (data->InvisibleId.toULong() != data->ContactInvisibleId.toULong()){ + if ((data->InvisibleId.toULong() == 0) || (data->ContactInvisibleId.toULong() == 0)){ + bChanged = true; + log(L_DEBUG, "%s change invisible state", qPrintable(userStr(contact, data))); + }else{ + data->InvisibleId.asULong() = data->ContactInvisibleId.toULong(); + } + } + if (contact->getIgnore() != (data->IgnoreId.toULong() != 0)){ + log(L_DEBUG, "%s change ignore state", qPrintable(userStr(contact, data))); + bChanged = true; + } + if (!bChanged){ + unsigned grp_id = 0; + if (contact->getGroup()){ + Group *group = getContacts()->group(contact->getGroup()); + if (group){ + ICQUserData *grp_data = toICQUserData((SIM::clientData*)group->clientData.getData(this)); // FIXME unsafe type conversion + if (grp_data){ + grp_id = grp_data->IcqID.toULong(); + }else{ + addGroupRequest(group); + } + } + } + if (data->GrpId.toULong() != grp_id){ + if (grp_id == 0) { + // + // fix for #5302 + grp_id = 1; + contact->setGroup(grp_id); + unsigned oldGrpId = data->GrpId.toULong(); + data->GrpId.asULong() = grp_id; + log(L_WARN, "%s change group %u->%u, because otherewise the contact would be deleted", + qPrintable(userStr(contact, data)), oldGrpId, grp_id); + return; + // + } else { + log(L_DEBUG, "%s change group %lu->%u", + qPrintable(userStr(contact, data)), data->GrpId.toULong(), grp_id); + bChanged = true; + } + } + if (!bChanged && (data->IcqID.toULong() == 0)) + return; + if (!bChanged && !isContactRenamed(data, contact)) + return; + } + + ListRequest lr; + lr.type = LIST_USER_CHANGED; + lr.screen = screen(data); + listRequests.push_back(lr); + snacICBM()->processSendQueue(); + } +} + +bool ICQClient::isContactRenamed(ICQUserData *data, Contact *contact) +{ + QString alias = data->Alias.str(); + if(alias.isEmpty()) + alias.sprintf("%lu", data->Uin.toULong()); + + if (contact->getName() != alias){ + log(L_DEBUG, "%lu renamed %s->%s", data->Uin.toULong(), qPrintable(alias), qPrintable(contact->getName())); + return true; + } + QString cell = getUserCellular(contact); + QString phone = data->Cellular.str(); + if (cell != phone){ + log(L_DEBUG, "%s phone changed %s->%s", qPrintable(userStr(contact, data)), qPrintable(phone), qPrintable(cell)); + return true; + } + return false; +} + +QString ICQClient::getUserCellular(Contact *contact) +{ + QString phones = contact->getPhones(); + while (phones.length()){ + QString phoneItem = getToken(phones, ';', false); + QString phone = getToken(phoneItem, '/', false); + if (phoneItem != "-") + continue; + QString value = getToken(phone, ','); + getToken(phone, ','); + if (phone.toUInt() == CELLULAR){ + return value; + } + } + return QString(); +} + +bool ICQClient::sendAuthRequest(Message *msg, void *_data) +{ + if ((getState() != Connected) || (_data == NULL)) + return false; + ICQUserData *data = toICQUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + + snac(ICQ_SNACxFOOD_LISTS, ICQ_SNACxLISTS_REQUEST_AUTH, true, false); + socket()->writeBuffer().packScreen(screen(data)); + QByteArray message; + QString charset; + if (hasCap(data, CAP_RTF) || hasCap(data, CAP_UTF)) + { + message = msg->getPlainText().toUtf8(); + charset = "utf-8"; + } + else + { + message = getContacts()->fromUnicode(NULL, msg->getPlainText()); + } + socket()->writeBuffer() + << (unsigned short)(message.length()) + << message.data() + << (char)0x00; + if (charset.isEmpty()){ + socket()->writeBuffer() << (char)0x00; + }else{ + socket()->writeBuffer() + << (char)0x01 + << (unsigned short)1 + << (unsigned short)(charset.length()) + << charset.toLatin1(); + } + sendPacket(true); + + msg->setClient(dataName(data)); + EventSent(msg).process(); + EventMessageSent(msg).process(); + delete msg; + return true; +} + +bool ICQClient::sendAuthGranted(Message *msg, void *_data) +{ + if ((getState() != Connected) || (_data == NULL)) + return false; + ICQUserData *data = toICQUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + data->WantAuth.asBool() = false; + + snac(ICQ_SNACxFOOD_LISTS, ICQ_SNACxLISTS_AUTHxSEND, true, false); + socket()->writeBuffer().packScreen(screen(data)); + socket()->writeBuffer() + << (char)0x01 + << (unsigned long)0; + sendPacket(true); + + msg->setClient(dataName(data)); + EventSent(msg).process(); + EventMessageSent(msg).process(); + delete msg; + return true; +} + +bool ICQClient::sendAuthRefused(Message *msg, void *_data) +{ + if ((getState() != Connected) || (_data == NULL)) + return false; + ICQUserData *data = toICQUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + data->WantAuth.asBool() = false; + + snac(ICQ_SNACxFOOD_LISTS, ICQ_SNACxLISTS_AUTHxSEND, true, false); + socket()->writeBuffer().packScreen(screen(data)); + + QByteArray message; + QByteArray charset; + if (hasCap(data, CAP_RTF) || hasCap(data, CAP_UTF)){ + message = msg->getPlainText().toUtf8(); + charset = "utf-8"; + }else{ + message = getContacts()->fromUnicode(NULL, msg->getPlainText()); + } + socket()->writeBuffer() + << (char) 0 + << (unsigned short)(message.length()) + << message + << (char)0x00; + if (charset.isEmpty()){ + socket()->writeBuffer() << (char)0x00; + }else{ + socket()->writeBuffer() << (char)0x01 + << (unsigned short)1 + << (unsigned short)(charset.length()) + << charset; + } + sendPacket(true); + + msg->setClient(dataName(data)); + EventSent(msg).process(); + EventMessageSent(msg).process(); + delete msg; + return true; +} diff --git a/plugins/icq/icqlocation.cpp b/plugins/icq/icqlocation.cpp new file mode 100644 index 0000000..143d6fc --- /dev/null +++ b/plugins/icq/icqlocation.cpp @@ -0,0 +1,648 @@ +/*************************************************************************** + icqlocation.cpp - description + ------------------- + begin : Sun Mar 10 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "icqclient.h" +#include "icqlocation.h" +#include "contacts/contact.h" + +#include +#include +#ifdef Q_OS_WIN32 +# include +#else +# include +#endif + +#include "log.h" + +using namespace SIM; + +const unsigned short ICQ_SNACxLOC_ERROR = 0x0001; +const unsigned short ICQ_SNACxLOC_REQUESTxRIGHTS = 0x0002; +const unsigned short ICQ_SNAXxLOC_RIGHTSxGRANTED = 0x0003; +const unsigned short ICQ_SNACxLOC_SETxUSERxINFO = 0x0004; +const unsigned short ICQ_SNACxLOC_REQUESTxUSERxINFO = 0x0005; +const unsigned short ICQ_SNACxLOC_LOCATIONxINFO = 0x0006; +const unsigned short ICQ_SNACxLOC_SETxDIRxINFO = 0x0009; +const unsigned short ICQ_SNACxLOC_RESPONSExSETxINFO = 0x000A; +const unsigned short ICQ_SNACxLOC_REQUESTxDIRxINFO = 0x000B; +const unsigned short ICQ_SNACxLOC_DIRxINFO = 0x000C; + +SnacIcqLocation::SnacIcqLocation(ICQClient* client) : QObject(NULL), SnacHandler(client, 0x0002) +{ +} + +SnacIcqLocation::~SnacIcqLocation() +{ +} + +static bool extractInfo(TlvList &tlvs, unsigned short id, SIM::Data &data, Contact *c = NULL) +{ + const char *info = NULL; + Tlv *tlv = tlvs(id); + if (tlv) + info = *tlv; + return data.setStr(getContacts()->toUnicode(c, info)); +} + +QString ICQClient::convert(Tlv *tlvInfo, TlvList &tlvs, unsigned n) +{ + if (tlvInfo == NULL) + return QString::null; + return convert(*tlvInfo, tlvInfo->Size(), tlvs, n); +} + +QString ICQClient::convert(const char *text, unsigned size, TlvList &tlvs, unsigned n) +{ + QByteArray charset = "us-ascii"; //perhaps Bug here, should be read from packet!? + Tlv *tlvCharset = NULL; + for (int i = 0; i < tlvs.count(); i++){ + Tlv *tlv = tlvs[i]; + if (tlv->Num() != n) + continue; + if (tlvCharset && (tlv->Size() < tlvCharset->Size())) + continue; + tlvCharset = tlv; + } + if (tlvCharset){ + int idx1 = charset.indexOf('\"'); + if (idx1 != -1){ + idx1++; + int idx2 = charset.indexOf('\"', idx1); + if(idx2 != -1) + charset = charset.mid(idx1, idx2 - idx1); + else + charset = charset.mid(idx1); + } + } + QString res; + if (charset.contains("us-ascii") || charset.contains("utf")){ //perhaps Bug here, should be read from packet!? + res = QString::fromUtf8(text, size); + }else if (charset.contains("unicode")){ + unsigned short *p = (unsigned short*)text; + for (unsigned i = 0; i < size - 1; i += 2, p++) + res += QChar((unsigned short)htons(*p)); + }else{ + QTextCodec *codec = QTextCodec::codecForName(charset); + if (codec){ + res = codec->toUnicode(text, size); + }else{ + res = QString::fromUtf8(text, size); + log(L_WARN, "Unknown encoding %s", charset.data()); + } + } + return res; +} + +void ICQClient::snac_location(unsigned short type, unsigned short seq) +{ + Contact *contact = NULL; + ICQUserData *data; + QString screen; + switch (type){ + case ICQ_SNAXxLOC_RIGHTSxGRANTED: + log(L_DEBUG, "Location rights granted"); + break; + case ICQ_SNACxLOC_ERROR: + break; + case ICQ_SNACxLOC_LOCATIONxINFO: + screen = socket()->readBuffer().unpackScreen(); + if (isOwnData(screen)){ + data = &this->data.owner; + }else{ + data = findContact(screen, NULL, false, contact); + } + if (data){ + socket()->readBuffer().incReadPos(4); + TlvList tlvs(socket()->readBuffer()); + Tlv *tlvInfo = tlvs(0x02); + if (tlvInfo){ + QString info = convert(tlvInfo, tlvs, 0x01); + if (info.startsWith("", Qt::CaseInsensitive)) + info = info.mid(6); + if (info.endsWith("", Qt::CaseInsensitive)) + info = info.left(info.length() - 7); + if (data->About.setStr(info)){ + data->ProfileFetch.asBool() = true; + if (contact){ + EventContact(contact, EventContact::eChanged).process(); + }else{ + EventClientChanged(this).process(); + } + } + break; /* Because we won't find tlv(0x03) which is + "since online" instead of encoding... */ + } + Tlv *tlvAway = tlvs(0x04); + if (tlvAway){ + QString info = convert(tlvAway, tlvs, 0x03); + data->AutoReply.str() = info; + EventClientChanged(this).process(); + } + } + break; + case ICQ_SNACxLOC_DIRxINFO: + if (isOwnData(screen)){ + data = &this->data.owner; + }else{ + data = findInfoRequest(seq, contact); + } + if (data){ + bool bChanged = false; + unsigned country = 0; + socket()->readBuffer().incReadPos(4); + TlvList tlvs(socket()->readBuffer()); + Contact *c = getContact(data); + bChanged |= extractInfo(tlvs, 0x01, data->FirstName, c); + bChanged |= extractInfo(tlvs, 0x02, data->LastName, c); + bChanged |= extractInfo(tlvs, 0x03, data->MiddleName, c); + bChanged |= extractInfo(tlvs, 0x04, data->Maiden, c); + bChanged |= extractInfo(tlvs, 0x07, data->State, c); + bChanged |= extractInfo(tlvs, 0x08, data->City, c); + bChanged |= extractInfo(tlvs, 0x0C, data->Nick, c); + bChanged |= extractInfo(tlvs, 0x0D, data->Zip, c); + bChanged |= extractInfo(tlvs, 0x21, data->Address, c); + Tlv *tlvCountry = tlvs(0x06); + if (tlvCountry){ + const char *code = *tlvCountry; + for (const ext_info *c = getCountryCodes(); c->nCode; c++){ + QString name(c->szName); + if (name.toUpper() == code){ + country = c->nCode; + break; + } + } + } + if (country != data->Country.toULong()){ + data->Country.asULong() = country; + bChanged = true; + } + data->ProfileFetch.asBool() = true; + if (bChanged){ + if (contact){ + EventContact e(contact, EventContact::eChanged); + e.process(); + }else{ + EventClientChanged(this).process(); + } + } + } + break; + case ICQ_SNACxLOC_RESPONSExSETxINFO: + break; + default: + log(L_WARN, "Unknown location foodgroup type %04X", type); + } +} + +void ICQClient::locationRequest() +{ + snac(ICQ_SNACxFOOD_LOCATION, ICQ_SNACxLOC_REQUESTxRIGHTS); + sendPacket(true); +} + +#define cap_id 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 +#define cap_none 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +#define cap_str 0xbc, 0xd2, 0x00, 0x04, 0xac, 0x96, 0xdd, 0x96 + +#define cap_mid 0x4c, 0x7f, 0x11, 0xd1 +#define cap_mstr 0x4f, 0xe9, 0xd3, 0x11 +#define cap_aim 0x09, 0x46 + +// must be synced with cap_id_t enum in icqclient.h +// +const capability arrCapabilities[] = + { + // CAP_AIM_SHORTCAPS + { cap_aim, 0x00, 0x00, cap_mid, cap_id }, + // CAP_AIM_VOICE + { cap_aim, 0x13, 0x41, cap_mid, cap_id }, + // CAP_AIM_SENDFILE + { cap_aim, 0x13, 0x43, cap_mid, cap_id }, + // CAP_DIRECT + { cap_aim, 0x13, 0x44, cap_mid, cap_id }, + // CAP_AIM_IMIMAGE + { cap_aim, 0x13, 0x45, cap_mid, cap_id }, + // CAP_AIM_BUDDYCON + { cap_aim, 0x13, 0x46, cap_mid, cap_id }, + // CAP_AIM_STOCKS + { cap_aim, 0x13, 0x47, cap_mid, cap_id }, + // CAP_AIM_GETFILE + { cap_aim, 0x13, 0x48, cap_mid, cap_id }, + // CAP_SRV_RELAY + { cap_aim, 0x13, 0x49, cap_mid, cap_id }, + // CAP_AIM_GAMES + { cap_aim, 0x13, 0x4a, cap_mid, cap_id }, + // CAP_AIM_BUDDYLIST + { cap_aim, 0x13, 0x4b, cap_mid, cap_id }, + // CAP_AVATAR + { cap_aim, 0x13, 0x4c, cap_mid, cap_id }, + // CAP_AIM_SUPPORT + { cap_aim, 0x13, 0x4d, cap_mid, cap_id }, + // CAP_UTF + { cap_aim, 0x13, 0x4e, cap_mid, cap_id }, + // CAP_RTF + { 0x97, 0xb1, 0x27, 0x51, 0x24, 0x3c, 0x43, 0x34, + 0xad, 0x22, 0xd6, 0xab, 0xf7, 0x3f, 0x14, 0x92 }, + // CAP_TYPING + { 0x56, 0x3f, 0xc8, 0x09, 0x0b, 0x6f, 0x41, 0xbd, + 0x9f, 0x79, 0x42, 0x26, 0x09, 0xdf, 0xa2, 0xf3 }, + // CAP_SIM + { 'S', 'I', 'M', ' ', 'c', 'l', 'i', 'e', + 'n', 't', ' ', ' ', 0, 0, 0, 0 }, + // CAP_STR_2001 + { 0xa0, 0xe9, 0x3f, 0x37, cap_mstr, cap_str }, + // CAP_STR_2002 + { 0x10, 0xcf, 0x40, 0xd1, cap_mstr, cap_str }, + // CAP_IS_2001 + { 0x2e, 0x7a, 0x64, 0x75, 0xfa, 0xdf, 0x4d, 0xc8, + 0x88, 0x6f, 0xea, 0x35, 0x95, 0xfd, 0xb6, 0xdf }, + // CAP_TRILLIAN + { 0x97, 0xb1, 0x27, 0x51, 0x24, 0x3c, 0x43, 0x34, + 0xad, 0x22, 0xd6, 0xab, 0xf7, 0x3f, 0x14, 0x09 }, + // CAP_TRIL_CRYPT + { 0xf2, 0xe7, 0xc7, 0xf4, 0xfe, 0xad, 0x4d, 0xfb, + 0xb2, 0x35, 0x36, 0x79, 0x8b, 0xdf, 0x00, 0x00 }, + // CAP_MACICQ + { 0xdd, 0x16, 0xf2, 0x02, 0x84, 0xe6, 0x11, 0xd4, + 0x90, 0xdb, 0x00, 0x10, 0x4b, 0x9b, 0x4b, 0x7d }, + // CAP_AIM_CHAT + { 0x74, 0x8f, 0x24, 0x20, 0x62, 0x87, 0x11, 0xd1, cap_id }, + // CAP_MICQ + { 'm', 'I', 'C', 'Q', ' ', (unsigned char)'©', 'R', '.', + 'K', ' ', '.', ' ', 0, 0, 0, 0 }, + // CAP_LICQ + { 'L', 'i', 'c', 'q', ' ', 'c', 'l', 'i', + 'e', 'n', 't', ' ', 0, 0, 0, 0 }, + // CAP_SIMOLD + { 0x97, 0xb1, 0x27, 0x51, 0x24, 0x3c, 0x43, 0x34, + 0xad, 0x22, 0xd6, 0xab, 0xf7, 0x3f, 0x14, 0x00 }, + // CAP_KOPETE + { 'K', 'o', 'p', 'e', 't', 'e', ' ', 'I', + 'C', 'Q', ' ', ' ', 0, 0, 0, 0 }, + // CAP_XTRAZ + { 0x1A, 0x09, 0x3C, 0x6C, 0xD7, 0xFD, 0x4E, 0xC5, + 0x9D, 0x51, 0xA6, 0x47, 0x4E, 0x34, 0xF5, 0xA0 }, + // CAP_IS_2002 + { 0x10, 0xcf, 0x40, 0xd1, cap_mid, cap_id }, + // CAP_MIRANDA + { 'M', 'i', 'r', 'a', 'n', 'd', 'a', 'M', cap_none }, + // CAP_ANDRQ + { '&', 'R', 'Q', 'i', 'n', 's', 'i', 'd', + 'e', 0, 0, 0, 0, 0, 0, 0 }, + // CAP_QIP + { 0x56, 0x3f, 0xc8, 0x09, 0x0b, 0x6f, 0x41, 'Q', + 'I', 'P', ' ', '2', '0', '0', '5', 'a' }, + // CAP_IMSECURE + { 'I', 'M', 's', 'e', 'c', 'u', 'r', 'e', + 'C', 'p', 'h', 'r', 0, 0, 0, 0 }, + // CAP_KXICQ + { 0x09, 0x49, 0x13, 0x44, cap_mid, cap_id }, + // CAP_ICQ5_1 + { 0xe3, 0x62, 0xc1, 0xe9, 0x12, 0x1a, 0x4b, 0x94, + 0xa6, 0x26, 0x7a, 0x74, 0xde, 0x24, 0x27, 0x0d }, + // CAP_UNKNOWN - used by Trillian and some ICQ 5 clients + { 0x17, 0x8c, 0x2d, 0x9b, 0xda, 0xa5, 0x45, 0xbb, + 0x8d, 0xdb, 0xf3, 0xbd, 0xbd, 0x53, 0xa1, 0x0a }, + // CAP_ICQ5_3 + { 0x67, 0x36, 0x15, 0x15, 0x61, 0x2d, 0x4c, 0x07, + 0x8f, 0x3d, 0xbd, 0xe6, 0x40, 0x8e, 0xa0, 0x41 }, + // CAP_ICQ5_4 + { 0xb9, 0x97, 0x08, 0xb5, 0x3a, 0x92, 0x42, 0x02, + 0xb0, 0x69, 0xf1, 0xe7, 0x57, 0xbb, 0x2e, 0x17 }, + // CAP_ICQ51 + { 0xb2, 0xec, 0x8f, 0x16, 0x7c, 0x6f, 0x45, 0x1b, + 0xbd, 0x79, 0xdc, 0x58, 0x49, 0x78, 0x88, 0xb9 }, + // CAP_JIMM + { 'J', 'i', 'm', 'm', ' ', 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 }, + //CAP_ICQJP + {'i', 'c', 'q', 'p', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + /*/* + // from Gaim: + // CAP_AIM_HIPTOP + { cap_aim, 0x13, 0x23, cap_mid, cap_id }, + // CAP_AIM_SECUREIM + { cap_aim, 0x00, 0x01, cap_mid, cap_id }, + // CAP_AIM_VIDEO + { cap_aim, 0x01, 0x00, cap_mid, cap_id }, + // CAP_AIM_LIVEVIDEO + { cap_aim, 0x01, 0x01, cap_mid, cap_id }, + // CAP_AIM_CAMERA + { cap_aim, 0x01, 0x02, cap_mid, cap_id }, + // CAP_AIM_ICHATAV + { cap_aim, 0x01, 0x05, cap_mid, cap_id }, + // CAP_AIM_SMS + { cap_aim, 0x01, 0xff, cap_mid, cap_id }, + // unknown + { cap_aim, 0xf0, 0x03, cap_mid, cap_id }, + { cap_aim, 0xf0, 0x05, cap_mid, cap_id }, + + // from http://community.livejournal.com/oscardoc/12366.html: + // HasMicrophone + { cap_aim, 0x01, 0x03, cap_mid, cap_id }, + // RtcAudio + { cap_aim, 0x01, 0x04, cap_mid, cap_id }, + // Aca + { cap_aim, 0x01, 0x06, cap_mid, cap_id }, + // MultiAudio + { cap_aim, 0x01, 0x07, cap_mid, cap_id }, + // MultiVideo + { cap_aim, 0x01, 0x08, cap_mid, cap_id }, + // Viceroy + { cap_aim, 0xf0, 0x04, cap_mid, cap_id }, + + // unknown QIP caps: + { 0xd3, 0xd4, 0x53, 0x19, 0x8b, 0x32, 0x40, 0x3b, + 0xac, 0xc7, 0xd1, 0xa9, 0xe2, 0xb5, 0x81, 0x3e }, + { 0x78, 0x5e, 0x8c, 0x48, 0x40, 0xd3, 0x4c, 0x65, + 0x88, 0x6f, 0x04, 0xcf, 0x3f, 0x3f, 0x43, 0xdf }, + { 0xe6, 0x01, 0xe4, 0x1c, 0x33, 0x73, 0x4b, 0xd1, + 0xbc, 0x06, 0x81, 0x1d, 0x6c, 0x32, 0x3d, 0x81 }, + { 0x61, 0xbe, 0xe0, 0xdd, 0x8b, 0xdd, 0x47, 0x5d, + 0x8d, 0xee, 0x5f, 0x4b, 0xaa, 0xcf, 0x19, 0xa7 }, + + // from mICQ: + { 0x17, 0x8c, 0x2d, 0x9b, 0xda, 0xa5, 0x45, 0xbb, + 0x8d, 0xdb, 0xf3, 0xbd, 0xbd, 0x53, 0xa1, 0x0a }, + { 0x67, 0x36, 0x15, 0x15, 0x61, 0x2d, 0x4c, 0x07, + 0x8f, 0x3d, 0xbd, 0xe6, 0x40, 0x8e, 0xa0, 0x41 }, + { 0xe3, 0x62, 0xc1, 0xe9, 0x12, 0x1a, 0x4b, 0x94, + 0xa6, 0x26, 0x7a, 0x74, 0xde, 0x24, 0x27, 0x0d }, + { 0xb9, 0x97, 0x08, 0xb5, 0x3a, 0x92, 0x42, 0x02, + 0xb0, 0x69, 0xf1, 0xe7, 0x57, 0xbb, 0x2e, 0x17 }, + { 0xb6, 0x07, 0x43, 0x78, 0xf5, 0x0c, 0x4a, 0xc7, + 0x90, 0x92, 0x59, 0x38, 0x50, 0x2d, 0x05, 0x91 }, + { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x19, 0x04, + 0x4a, 0x16, 0xed, 0x79, 0x2c, 0xb1, 0x71, 0x01 }, + { 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0xb3, 0xf8, + 0x53, 0x44, 0x7f, 0x0d, 0x2d, 0x83, 0xbd, 0x76 }, +*/ + // CAP_NULL + { cap_none, cap_none }, + }; + +const capability *ICQClient::capabilities = arrCapabilities; + +#ifndef VERSION +#define VERSION "0.1" +#endif + +static unsigned char get_ver(const char *&v) +{ + if (v == NULL) + return 0; + char c = (char)atol(v); + v = strchr(v, '.'); + if (v) + v++; + return c; +} + +static bool isWide(const QString &str) +{ + for (int i = 0; i < (int)(str.length()); i++) + if (str[i].unicode() > 0x7F) + return true; + return true; +} + +static inline bool isWide(const SIM::Data &data) +{ + return isWide(data.str()); +} + +void ICQClient::encodeString(const QString &str, unsigned short nTlv, bool bWide) +{ + if (str.isEmpty()){ + socket()->writeBuffer().tlv(nTlv); + return; + } + QString m = str; + if (bWide){ + unsigned short *unicode = new unsigned short[m.length()]; + unsigned short *t = unicode; + for (int i = 0; i < (int)(m.length()); i++) + *(t++) = htons(m[i].unicode()); + socket()->writeBuffer().tlv(nTlv, (char*)unicode, (unsigned short)(m.length() * sizeof(unsigned short))); + delete[] unicode; + }else{ + socket()->writeBuffer().tlv(nTlv, m.toLatin1().data()); + } +} + +void ICQClient::encodeString(const QString &m, const QString &type, unsigned short charsetTlv, unsigned short infoTlv) +{ + bool bWide = isWide(m); + QString content_type = type + "; charset=\""; + if (bWide){ + unsigned short *unicode = new unsigned short[m.length()]; + unsigned short *t = unicode; + for (int i = 0; i < (int)(m.length()); i++) + *(t++) = htons(m[i].unicode()); + content_type += "unicode-2\""; + socket()->writeBuffer().tlv(charsetTlv, content_type.toUtf8().data()); + socket()->writeBuffer().tlv(infoTlv, (char*)unicode, (unsigned short)(m.length() * sizeof(unsigned short))); + delete[] unicode; + }else{ + content_type += "us-ascii\""; + socket()->writeBuffer().tlv(charsetTlv, content_type.toUtf8().data()); + socket()->writeBuffer().tlv(infoTlv, m.toLatin1().data()); + } +} + +void ICQClient::addCapability(ICQBuffer &cap, cap_id_t id) +{ + cap.pack((char*)capabilities[id], sizeof(capability)); +} + +void ICQClient::sendCapability(const QString &away_msg) +{ + ICQBuffer cap; + capability c; + + memcpy(c, capabilities[CAP_SIM], sizeof(c)); + const char *ver = VERSION; + unsigned char *pack_ver = c + sizeof(capability) - 4; + *(pack_ver++) = get_ver(ver); + *(pack_ver++) = get_ver(ver); + *(pack_ver++) = get_ver(ver); + unsigned char os_ver; +#ifdef WIN32 + os_ver = 0x80; +#else +#ifdef Q_OS_MAC + os_ver = 0x40; +#else + os_ver = 0; +#endif +#endif + *(pack_ver++) = os_ver | get_ver(ver); + addCapability(cap, CAP_AIM_SHORTCAPS); + addCapability(cap, CAP_AIM_SUPPORT); + addCapability(cap, CAP_AVATAR); + if (m_bAIM){ + addCapability(cap, CAP_AIM_CHAT); + addCapability(cap, CAP_AIM_BUDDYCON); + addCapability(cap, CAP_AIM_IMIMAGE); + addCapability(cap, CAP_AIM_SENDFILE); + addCapability(cap, CAP_AIM_BUDDYLIST); + }else{ + addCapability(cap, CAP_AIM_SENDFILE); //Since we add this, ICQ6 accepts the client as filetransfer partner + addCapability(cap, CAP_DIRECT); + addCapability(cap, CAP_SRV_RELAY); + addCapability(cap, CAP_XTRAZ); // What? We don't support it. Yet. + if (getSendFormat() <= 1) + addCapability(cap, CAP_UTF); + if (getSendFormat() == 0) + addCapability(cap, CAP_RTF); + } + if (!getDisableTypingNotification()) + cap.pack((char*)capabilities[CAP_TYPING], sizeof(capability)); + + cap.pack((char*)c, sizeof(c)); + snac(ICQ_SNACxFOOD_LOCATION, ICQ_SNACxLOC_SETxUSERxINFO); + if (m_bAIM){ + if (data.owner.ProfileFetch.toBool()){ + QString profile; + profile = QString("") + data.owner.About.str() + ""; + encodeString(profile, "text/aolrtf", 1, 2); + } + if (!away_msg.isNull()) + encodeString(away_msg, "text/plain", 3, 4); + } + socket()->writeBuffer().tlv(0x0005, cap); + if (m_bAIM) + socket()->writeBuffer().tlv(0x0006, "\x00\x04\x00\x02\x00\x02", 6); + sendPacket(true); +} + +void ICQClient::setAwayMessage(const QString &msg) +{ + snac(ICQ_SNACxFOOD_LOCATION, ICQ_SNACxLOC_SETxUSERxINFO); + if (!msg.isNull()){ + encodeString(msg, "text/plain", 3, 4); + }else{ + socket()->writeBuffer().tlv(0x0004); + } + sendPacket(true); +} + +void ICQClient::fetchProfile(ICQUserData *data) +{ + snac(ICQ_SNACxFOOD_LOCATION, ICQ_SNACxLOC_REQUESTxUSERxINFO, true); + socket()->writeBuffer() << (unsigned short)0x0001; + socket()->writeBuffer().packScreen(screen(data)); + sendPacket(false); + snac(ICQ_SNACxFOOD_LOCATION, ICQ_SNACxLOC_REQUESTxDIRxINFO, true); + socket()->writeBuffer().packScreen(screen(data)); + sendPacket(false); + m_info_req.insert(INFO_REQ_MAP::value_type(m_nMsgSequence, screen(data))); + data->ProfileFetch.setBool(true); +} + +void ICQClient::fetchProfiles() +{ + if (!data.owner.ProfileFetch.toBool()) + fetchProfile(&data.owner); + Contact *contact; + ContactList::ContactIterator itc; + while ((contact = ++itc) != NULL){ + ICQUserData *data; + ClientDataIterator itd(contact->clientData, this); + while ((data = toICQUserData(++itd)) != NULL){ + if (data->Uin.toULong() || data->ProfileFetch.toBool()) + continue; + fetchProfile(data); + } + } +} + +ICQUserData *ICQClient::findInfoRequest(unsigned short seq, Contact *&contact) +{ + INFO_REQ_MAP::iterator it = m_info_req.find(seq); + if (it == m_info_req.end()){ + log(L_WARN, "Info req %u not found", seq); + return NULL; + } + QString screen = it->second; + m_info_req.erase(it); + return findContact(screen, NULL, false, contact); +} + +void ICQClient::setAIMInfo(ICQUserData *data) +{ + if (getState() != Connected) + return; + bool bWide = isWide(data->FirstName) || + isWide(data->LastName) || + isWide(data->MiddleName) || + isWide(data->Maiden) || + isWide(data->Nick) || + isWide(data->Zip) || + isWide(data->Address) || + isWide(data->City); + QString country; + for (const ext_info *e = getCountryCodes(); e->szName; e++){ + if (e->nCode == data->Country.toULong()){ + country = e->szName; + break; + } + } + snac(ICQ_SNACxFOOD_LOCATION, ICQ_SNACxLOC_SETxDIRxINFO); + QString encoding = bWide ? "unicode-2-0" : "us-ascii"; + socket()->writeBuffer().tlv(0x1C, encoding.toUtf8().data()); + socket()->writeBuffer().tlv(0x0A, (unsigned short)0x01); + encodeString(data->FirstName.str(), 0x01, bWide); + encodeString(data->LastName.str(), 0x02, bWide); + encodeString(data->MiddleName.str(), 0x03, bWide); + encodeString(data->Maiden.str(), 0x04, bWide); + encodeString(country, 0x06, bWide); + encodeString(data->Address.str(), 0x07, bWide); + encodeString(data->City.str(), 0x08, bWide); + encodeString(data->Nick.str(), 0x0C, bWide); + encodeString(data->Zip.str(), 0x0D, bWide); + encodeString(data->State.str(), 0x21, bWide); + sendPacket(false); + + ICQUserData *ownerData = &this->data.owner; + ownerData->FirstName.str() = data->FirstName.str(); + ownerData->LastName.str() = data->LastName.str(); + ownerData->MiddleName.str() = data->MiddleName.str(); + ownerData->Maiden.str() = data->Maiden.str(); + ownerData->Address.str() = data->Address.str(); + ownerData->City.str() = data->City.str(); + ownerData->Nick.str() = data->Nick.str(); + ownerData->Zip.str() = data->Zip.str(); + ownerData->State.str() = data->State.str(); + ownerData->Country.asULong() = data->Country.toULong(); +} + +void ICQClient::setProfile(ICQUserData *data) +{ + snac(ICQ_SNACxFOOD_LOCATION, ICQ_SNACxLOC_SETxUSERxINFO); + QString profile; + profile = QString("") + data->About.str() + ""; + encodeString(profile, "text/aolrtf", 1, 2); + sendPacket(false); +} + +/* +#ifndef NO_MOC_INCLUDES +#include "icqlocation.moc" +#endif +*/ diff --git a/plugins/icq/icqlocation.h b/plugins/icq/icqlocation.h new file mode 100644 index 0000000..9face63 --- /dev/null +++ b/plugins/icq/icqlocation.h @@ -0,0 +1,18 @@ + +#ifndef ICQLOCATION_H +#define ICQLOCATION_H + +#include "snac.h" +#include + +class SnacIcqLocation : public QObject, public SnacHandler +{ + Q_OBJECT +public: + SnacIcqLocation(ICQClient* client); + virtual ~SnacIcqLocation(); + +}; + + +#endif diff --git a/plugins/icq/icqlogin.cpp b/plugins/icq/icqlogin.cpp new file mode 100644 index 0000000..37f03fa --- /dev/null +++ b/plugins/icq/icqlogin.cpp @@ -0,0 +1,398 @@ +/*************************************************************************** + login.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include +#include +#include + +#include "log.h" +#include "buffer.h" +#include "socket/socket.h" + +#include "icqclient.h" +#include "verifydlg.h" + +using namespace SIM; + +const unsigned short ICQ_SNACxLOGIN_ERROR = 0x0001; +const unsigned short ICQ_SNACxLOGIN_MD5xLOGIN = 0x0002; +const unsigned short ICQ_SNACxLOGIN_LOGINxREPLY = 0x0003; +const unsigned short ICQ_SNACxLOGIN_REGISTERxREQ = 0x0004; +const unsigned short ICQ_SNACxLOGIN_REGISTER = 0x0005; +const unsigned short ICQ_SNACxLOGIN_AUTHxREQUEST = 0x0006; +const unsigned short ICQ_SNACxLOGIN_AUTHxKEYxRESPONSE = 0x0007; +const unsigned short ICQ_SNACxLOGIN_REGISTERxREQ_IMG = 0x000c; +const unsigned short ICQ_SNACxLOGIN_REGISTERxSEND_IMG = 0x000d; + +const unsigned ICQ_LOGIN_ERRxBAD_PASSWD1 = 0x0001; +const unsigned ICQ_LOGIN_ERRxBAD_PASSWD2 = 0x0004; +const unsigned ICQ_LOGIN_ERRxBAD_PASSWD3 = 0x0005; +const unsigned ICQ_LOGIN_ERRxBAD_LOGIN = 0x0006; +const unsigned ICQ_LOGIN_ERRxNOT_EXISTS1 = 0x0007; +const unsigned ICQ_LOGIN_ERRxNOT_EXISTS2 = 0x0008; +const unsigned ICQ_LOGIN_ERRxUNAVAILABLE1 = 0x000c; +const unsigned ICQ_LOGIN_ERRxUNAVAILABLE2 = 0x000d; +const unsigned ICQ_LOGIN_ERRxSUSPENDED1 = 0x0011; +const unsigned ICQ_LOGIN_ERRxUNAVAILABLE3 = 0x0012; +const unsigned ICQ_LOGIN_ERRxUNAVAILABLE4 = 0x0013; +const unsigned ICQ_LOGIN_ERRxUNAVAILABLE5 = 0x0014; +const unsigned ICQ_LOGIN_ERRxUNAVAILABLE6 = 0x0015; +const unsigned ICQ_LOGIN_ERRxIP_RATE_LIMIT1 = 0x0016; +const unsigned ICQ_LOGIN_ERRxIP_RATE_LIMIT2 = 0x0017; +const unsigned ICQ_LOGIN_ERRxRATE_LIMIT1 = 0x0018; +const unsigned ICQ_LOGIN_ERRxUNAVAILABLE7 = 0x001a; +const unsigned ICQ_LOGIN_ERRxOLDCLIENT1 = 0x001b; +const unsigned ICQ_LOGIN_ERRxOLDCLIENT2 = 0x001c; +const unsigned ICQ_LOGIN_ERRxRATE_LIMIT2 = 0x001d; +const unsigned ICQ_LOGIN_ERRxCANT_REGISTER = 0x001e; +const unsigned ICQ_LOGIN_ERRxUNAVAILABLE8 = 0x001f; +const unsigned ICQ_LOGIN_ERRxINVALID_ID = 0x0020; +const unsigned ICQ_LOGIN_ERRxTOO_YOUNG = 0x0022; + +void ICQClient::snac_login(unsigned short type, unsigned short) +{ + unsigned long newUin; + switch (type){ + case ICQ_SNACxLOGIN_ERROR: + if (data.owner.Uin.toULong()){ + m_reconnect = NO_RECONNECT; + socket()->error_state(I18N_NOOP("Login error"), AuthError); + break; + } + // in the process of registering; + // it seems that we need to request bot protection picture; + // reconnecting to send the request. + log(L_DEBUG, "Verification required, reconnecting"); + m_bVerifying = true; + socket()->close(); + socket()->connect(getServer(), getPort(), this); + break; + case ICQ_SNACxLOGIN_REGISTER: + if (data.owner.Uin.toULong()){ + socket()->error_state(I18N_NOOP("Registered in no register state")); + break; + } + socket()->readBuffer().incReadPos(0x2E); + socket()->readBuffer().unpack(newUin); + log(L_DEBUG, "Register %lu %08lX", newUin, newUin); + setUin(newUin); + setState(Connecting); + socket()->connect(getServer(), getPort(), this); + break; + case ICQ_SNACxLOGIN_AUTHxKEYxRESPONSE: + log(L_DEBUG, "Sending MD5 key"); + if (!data.owner.Screen.str().isEmpty() || data.owner.Uin.toULong()){ + QByteArray md5_key; + socket()->readBuffer().unpackStr(md5_key); + snac(ICQ_SNACxFOOD_LOGIN, ICQ_SNACxLOGIN_MD5xLOGIN, false, false); + if (data.owner.Uin.toULong()){ + char uin[20]; + sprintf(uin, "%lu", data.owner.Uin.toULong()); + socket()->writeBuffer().tlv(0x0001, uin); + } + else + { + socket()->writeBuffer().tlv(0x0001, data.owner.Screen.str().toUtf8().data()); + } + QByteArray md = md5_key; + md += getContacts()->fromUnicode(NULL, getPassword()); + md += "AOL Instant Messenger (SM)"; + md = QCryptographicHash::hash(md, QCryptographicHash::Md5); + socket()->writeBuffer().tlv(0x0025, md.data(), md.size()); + if (data.owner.Uin.toULong()){ + socket()->writeBuffer().tlv(0x0003, "ICQBasic"); //ToDo: Should be updated anytime + socket()->writeBuffer().tlv(0x0016, 0x010A); // ID Number + socket()->writeBuffer().tlv(0x0017, 0x0014); // major + socket()->writeBuffer().tlv(0x0018, 0x0034); // minor + socket()->writeBuffer().tlv(0x0019, 0x0009); + socket()->writeBuffer().tlv(0x001A, 0x0c18); + socket()->writeBuffer().tlv(0x0014, 0x0000043dL); + socket()->writeBuffer().tlv(0x000f, "en"); + socket()->writeBuffer().tlv(0x000e, "us"); + }else{ + socket()->writeBuffer().tlv(0x0003, "AOL Instant Messenger, version 5.1.3036/WIN32"); //ToDo: Should be updated anytime + socket()->writeBuffer().tlv(0x0016, (unsigned short)0x0109); + socket()->writeBuffer().tlv(0x0017, (unsigned short)0x0005); + socket()->writeBuffer().tlv(0x0018, (unsigned short)0x0001); + socket()->writeBuffer().tlv(0x0019, (unsigned short)0x0000); + socket()->writeBuffer().tlv(0x001A, (unsigned short)0x0BDC); + socket()->writeBuffer().tlv(0x0014, 0x000000D2L); + socket()->writeBuffer().tlv(0x000F, "en"); //Todo Send right language shortcut ;) same below + socket()->writeBuffer().tlv(0x000E, "us"); + socket()->writeBuffer().tlv(0x004A, "\x01"); + } + sendPacket(true); + } + break; + case ICQ_SNACxLOGIN_LOGINxREPLY: + chn_close(); + break; + case ICQ_SNACxLOGIN_REGISTERxSEND_IMG: { + m_bVerifying = false; + TlvList tlv(socket()->readBuffer()); + // currently there are 2 TLVs in SNAC(17,0D): + // type = 1: the value contains the mime type of the image (image/jpeg); ignored + // type = 2: the value contains the image itself in the binary form + Tlv* tlvImage = tlv(2); + if (!tlvImage) + break; + log(L_DEBUG, "Image length: %d bytes", tlvImage->Size()); + QByteArray buf = tlvImage->byteArray(); + QPixmap pict; + if (!pict.loadFromData(buf)) + break; + log(L_DEBUG, "Received verification image"); + VerifyDlg verdlg(qApp->activeWindow(), pict); + if (verdlg.exec() == QDialog::Accepted) // what to do if the user has cancelled the dialog? + { + QString verifyStr = verdlg.getVerifyString(); + log(L_DEBUG, "User input: %s", qPrintable(verifyStr)); + snac(ICQ_SNACxFOOD_LOGIN, ICQ_SNACxLOGIN_REGISTERxREQ); + ICQBuffer msg; + msg + << 0x00000000L << 0x28000300L << 0x00000000L + << 0x00000000L << 0x94680000L << 0x94680000L + << 0x00000000L << 0x00000000L << 0x00000000L + << 0x00000000L; + QByteArray pswd = getContacts()->fromUnicode(NULL, getPassword()); + unsigned short len = (unsigned short)(pswd.length() + 1); + msg.pack(len); + msg.pack(pswd.data(), len); + msg << 0x94680000L << 0x00000602L; + socket()->writeBuffer().tlv(0x0001, msg); + socket()->writeBuffer().tlv(0x0009, verifyStr.toLatin1(), verifyStr.length()); + sendPacket(true); + } + break; + } + default: + log(L_WARN, "Unknown login foodgroup type %04X", type); + } +} + +void ICQClient::chn_login() +{ + m_bconnectionLost = false; + if (m_cookie.size()){ + flap(ICQ_CHNxNEW); + socket()->writeBuffer() << 0x00000001L; + socket()->writeBuffer().tlv(6, m_cookie.data(), (unsigned short)(m_cookie.size())); + m_cookie.resize(0); + sendPacket(true); + return; + } + if (data.owner.Uin.toULong() && ! getUseMD5()){ + QByteArray pswd = cryptPassword(); + log(L_DEBUG, "Login %lu [%s]", data.owner.Uin.toULong(), /*pswd.c_str()*/""); + char uin[20]; + sprintf(uin, "%lu", data.owner.Uin.toULong()); + + flap(ICQ_CHNxNEW); + socket()->writeBuffer() << 0x00000001L; + socket()->writeBuffer().tlv(0x0001, uin); + socket()->writeBuffer().tlv(0x0002, pswd.data(), pswd.size()); + // Thanks to pidgin guys for those values + socket()->writeBuffer().tlv(0x0003, "ICQBasic"); // ID String, currently ICQ 5.1 (21.08.2006) + socket()->writeBuffer().tlv(0x0016, 0x010A); // ID Number + socket()->writeBuffer().tlv(0x0017, 0x0014); // major + socket()->writeBuffer().tlv(0x0018, 0x0034); // minor + socket()->writeBuffer().tlv(0x0019, 0x0000); // lesser + socket()->writeBuffer().tlv(0x001A, 0x0c18); // build number + socket()->writeBuffer().tlv(0x0014, 0x0000043dL); // distribution number + socket()->writeBuffer().tlv(0x000f, "en"); //Todo Send right language shortcut + socket()->writeBuffer().tlv(0x000e, "us"); + sendPacket(true); + return; + } + if (!data.owner.Screen.str().isEmpty() || getUseMD5()){ + log(L_DEBUG, "Requesting MD5 salt"); + flap(ICQ_CHNxNEW); + socket()->writeBuffer() << 0x00000001L; + sendPacket(true); + snac(ICQ_SNACxFOOD_LOGIN, ICQ_SNACxLOGIN_AUTHxREQUEST, false, false); + if (data.owner.Uin.toULong()) + { + QString uin = QString::number(data.owner.Uin.toULong()); + socket()->writeBuffer().tlv(0x0001, uin.toUtf8().data()); + }else{ + socket()->writeBuffer().tlv(0x0001, data.owner.Screen.str().toUtf8().data()); + } + socket()->writeBuffer().tlv(0x004B); + socket()->writeBuffer().tlv(0x005A); + sendPacket(true); + return; + } + if (m_bVerifying){ + log(L_DEBUG, "Requesting verification picture"); + flap(ICQ_CHNxNEW); + socket()->writeBuffer() << 0x00000001L; + sendPacket(true); + snac(ICQ_SNACxFOOD_LOGIN, ICQ_SNACxLOGIN_REGISTERxREQ_IMG); + sendPacket(true); + return; + } + flap(ICQ_CHNxNEW); + socket()->writeBuffer() << 0x00000001L; + sendPacket(true); + // first try the old registration scheme + snac(ICQ_SNACxFOOD_LOGIN, ICQ_SNACxLOGIN_REGISTERxREQ); + ICQBuffer msg; + msg + << 0x00000000L << 0x28000300L << 0x00000000L + << 0x00000000L << 0x94680000L << 0x94680000L + << 0x00000000L << 0x00000000L << 0x00000000L + << 0x00000000L; + QByteArray pswd = getContacts()->fromUnicode(NULL, getPassword()); + unsigned short len = (unsigned short)(pswd.length() + 1); + msg.pack(len); + msg.pack(pswd.data(), len); + msg << 0x94680000L << 0x00000602L; + socket()->writeBuffer().tlv(0x0001, msg); + sendPacket(true); +} + +void ICQClient::chn_close() +{ + unsigned errorCode = 0; + TlvList tlv(socket()->readBuffer()); + Tlv *tlv_error = tlv(8); + if (tlv_error){ + unsigned short err = *tlv_error; + QString errString; + switch (err){ + case ICQ_LOGIN_ERRxOLDCLIENT1: + case ICQ_LOGIN_ERRxOLDCLIENT2: + errString = I18N_NOOP("This client is outdated"); + m_reconnect = NO_RECONNECT; + break; + case ICQ_LOGIN_ERRxIP_RATE_LIMIT1: + case ICQ_LOGIN_ERRxIP_RATE_LIMIT2: + errString = I18N_NOOP("Too many clients from same IP"); + m_reconnect = NO_RECONNECT; + break; + case ICQ_LOGIN_ERRxRATE_LIMIT1: + case ICQ_LOGIN_ERRxRATE_LIMIT2: + errString = I18N_NOOP("Rate limit"); + m_reconnect = NO_RECONNECT; + break; + case ICQ_LOGIN_ERRxBAD_PASSWD1: + case ICQ_LOGIN_ERRxBAD_PASSWD2: + case ICQ_LOGIN_ERRxBAD_PASSWD3: + errString = I18N_NOOP("Invalid UIN and password combination"); + m_reconnect = NO_RECONNECT; + errorCode = AuthError; + break; + case ICQ_LOGIN_ERRxNOT_EXISTS1: + case ICQ_LOGIN_ERRxNOT_EXISTS2: + errString = I18N_NOOP("Non-existant UIN"); + m_reconnect = NO_RECONNECT; + errorCode = AuthError; + break; + case ICQ_LOGIN_ERRxBAD_LOGIN: + errString = I18N_NOOP("Bad login procedure"); + m_reconnect = NO_RECONNECT; + break; + case ICQ_LOGIN_ERRxUNAVAILABLE1: + case ICQ_LOGIN_ERRxUNAVAILABLE2: + case ICQ_LOGIN_ERRxUNAVAILABLE3: + case ICQ_LOGIN_ERRxUNAVAILABLE4: + case ICQ_LOGIN_ERRxUNAVAILABLE5: + case ICQ_LOGIN_ERRxUNAVAILABLE6: + case ICQ_LOGIN_ERRxUNAVAILABLE7: + case ICQ_LOGIN_ERRxUNAVAILABLE8: + errString = I18N_NOOP("Service temporarly unavailable"); + m_reconnect = NO_RECONNECT; + break; + case ICQ_LOGIN_ERRxINVALID_ID: + errString = I18N_NOOP("Invalid SecureID"); + m_reconnect = NO_RECONNECT; + break; + case ICQ_LOGIN_ERRxTOO_YOUNG: + errString = I18N_NOOP("Too young!"); + m_reconnect = NO_RECONNECT; + break; + case ICQ_LOGIN_ERRxSUSPENDED1: + errString = I18N_NOOP("UIN was suspended"); + m_reconnect = NO_RECONNECT; + break; + case ICQ_LOGIN_ERRxCANT_REGISTER: + errString = I18N_NOOP("Can't login to ICQ network - Please try again later"); + m_reconnect = NO_RECONNECT; + break; + case 0: + break; + default: + errString = "Unknown error "; + errString += QString::number(err); + } + if (err){ + log(L_ERROR, "%s", qPrintable(errString)); + socket()->error_state(errString, errorCode); + flap(ICQ_CHNxCLOSE); + sendPacket(true); + return; + } + } + tlv_error = tlv(9); + if (tlv_error){ + QString errString; + unsigned short err = *tlv_error; + switch (err){ + case 0x1:{ + errString = I18N_NOOP("Your UIN is being used from another location"); + m_reconnect = NO_RECONNECT; + break; + } + case 0: + break; + default: + errString = "Unknown run-time error "; + errString += QString::number(err); + } + if (err){ + log(L_ERROR, "%s", qPrintable(errString)); + socket()->error_state(errString); + return; + } + } + flap(ICQ_CHNxCLOSE); + sendPacket(true); + + Tlv *tlv_host = tlv(5); + Tlv *tlv_cookie = tlv(6); + if ((tlv_host == NULL) || (tlv_cookie == NULL)){ + socket()->error_state(I18N_NOOP("Close packet from server")); + return; + } + QString host = tlv_host->byteArray().data(); + int idx = host.indexOf(':'); + if (idx == -1){ + log(L_ERROR, "Bad host address %s", qPrintable(host)); + socket()->error_state(I18N_NOOP("Bad host address")); + return; + } + unsigned short port = host.mid(idx + 1).toUShort(); + host = host.left(idx); + + socket()->close(); + socket()->connect(host, port, this); + m_cookie = tlv_cookie->byteArray(); + m_cookie.resize(m_cookie.size() - 1); // tlv has \0 terminator... time for Qt4 +} + diff --git a/plugins/icq/icqmessage.cpp b/plugins/icq/icqmessage.cpp new file mode 100644 index 0000000..ca41fae --- /dev/null +++ b/plugins/icq/icqmessage.cpp @@ -0,0 +1,1593 @@ +/*************************************************************************** + icqmessage.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "simgui/toolbtn.h" +#include "log.h" + +#include "icqmessage.h" +#include "icqclient.h" +#include "icq.h" +#include "core.h" +#include "xml.h" +#include "contacts/contact.h" + +using namespace std; +using namespace SIM; + +static DataDef aimFileMessageData[] = + { + { "", DATA_ULONG, 1, 0 }, // Port + { "", DATA_ULONG, 1, 0 }, // ID_L + { "", DATA_ULONG, 1, 0 }, // ID_H + { NULL, DATA_UNKNOWN, 0, 0 } + }; + +AIMFileMessage::AIMFileMessage(Buffer *cfg) + : FileMessage(MessageFile, cfg) +{ + load_data(aimFileMessageData, &data, cfg); + isProxy = false; +} + +AIMFileMessage::~AIMFileMessage() +{ + free_data(aimFileMessageData, &data); +} + +static DataDef icqFileMessageData[] = + { + { "ServerDescr", DATA_STRING, 1, 0 }, + { "", DATA_ULONG, 1, 0 }, // IP + { "", DATA_ULONG, 1, 0 }, // Port + { "", DATA_ULONG, 1, 0 }, // ID_L + { "", DATA_ULONG, 1, 0 }, // ID_H + { "", DATA_ULONG, 1, 0 }, // Cookie + { "", DATA_ULONG, 1, 0 }, // Extended + { NULL, DATA_UNKNOWN, 0, 0 } + }; + +ICQFileMessage::ICQFileMessage(Buffer *cfg) + : FileMessage(MessageICQFile, cfg) +{ + load_data(icqFileMessageData, &data, cfg); +} + +ICQFileMessage::~ICQFileMessage() +{ + free_data(icqFileMessageData, &data); +} + +QString ICQFileMessage::getDescription() +{ + QString serverText = getServerDescr(); + if (serverText.isEmpty()) + return FileMessage::getDescription(); + return serverText; +} + +QByteArray ICQFileMessage::save() +{ + QByteArray s = FileMessage::save(); + QByteArray s1 = save_data(icqFileMessageData, &data); + if (!s1.isEmpty()){ + if (!s.isEmpty()) + s += '\n'; + s += s1; + } + return s; +} + +IcqContactsMessage::IcqContactsMessage(Buffer *cfg) + : ContactsMessage(MessageICQContacts, cfg) +{ +} + +IcqContactsMessage::~IcqContactsMessage() +{ +} + +QString IcqContactsMessage::getContacts() const +{ + QByteArray serverText = getServerText(); + if (serverText.isEmpty()) + return ContactsMessage::getContacts(); + return serverText; // this is wrong ... but I'm currently unsure what'ssaved in there +} + +static DataDef icqAuthMessageData[] = + { + { "Charset", DATA_STRING, 1, 0 }, + { NULL, DATA_UNKNOWN, 0, 0 } + }; + +ICQAuthMessage::ICQAuthMessage(unsigned type, unsigned baseType, Buffer *cfg) + : AuthMessage(type, cfg) +{ + load_data(icqAuthMessageData, &data, cfg); + m_baseType = baseType; +} + +ICQAuthMessage::~ICQAuthMessage() +{ + free_data(icqAuthMessageData, &data); +} + +QString ICQAuthMessage::getText() const +{ + QByteArray serverText = getServerText(); + if (serverText.isEmpty()) + return Message::getText(); + QString charset = getCharset(); + if (!charset.isEmpty()){ + QTextCodec *codec = QTextCodec::codecForName(charset.toUtf8().constData()); + if (codec) + return codec->toUnicode(serverText); + } + return Message::getText(); +} + +QByteArray ICQAuthMessage::save() +{ + QByteArray s = Message::save(); + QByteArray s1 = save_data(icqAuthMessageData, &data); + if (!s1.isEmpty()){ + if (!s.isEmpty()) + s += '\n'; + s += s1; + } + return s; +} + +static bool h2b(const char *&p, char &r) +{ + char c = *(p++); + if ((c >= '0') && (c <= '9')){ + r = (char)(c - '0'); + return true; + } + if ((c >= 'A') && (c <= 'F')){ + r = (char)(c - 'A' + 10); + return true; + } + return false; +} + +static bool h2b(const char *&p, QByteArray &cap) +{ + char r1, r2; + if (h2b(p, r1) && h2b(p, r2)){ + cap += (char)((r1 << 4) + r2); + return true; + } + return false; +} + +static bool parseFE(QByteArray str, QList &l, unsigned n) +{ + int idx = str.indexOf('\xFE'); + while(idx != -1) { + l += str.left(idx); + str = str.mid(idx+1); + idx = str.indexOf('\xFE'); + } + l += str; + for( unsigned i = l.count(); i < n; i++ ) + l += QByteArray(); + return true; +} + +static Message *parseTextMessage(const QByteArray &str, const QByteArray &_pp, Contact *contact) +{ + if (str.isEmpty()) + return NULL; + log(L_DEBUG, "Text message: %s %s", str.data(), _pp.data()); + if (_pp.length() == 38){ + QByteArray cap; + const char *pp = _pp.data(); + if ((*(pp++) == '{') && + h2b(pp, cap) && h2b(pp, cap) && h2b(pp, cap) && h2b(pp, cap) && + (*(pp++) == '-') && + h2b(pp, cap) && h2b(pp, cap) && + (*(pp++) == '-') && + h2b(pp, cap) && h2b(pp, cap) && + (*(pp++) == '-') && + h2b(pp, cap) && h2b(pp, cap) && + (*(pp++) == '-') && + h2b(pp, cap) && h2b(pp, cap) && h2b(pp, cap) && h2b(pp, cap) && + h2b(pp, cap) && h2b(pp, cap) && + (*(pp++) == '}')){ + const char *unpack_cap = cap.data(); + if (!memcmp(unpack_cap, ICQClient::capabilities[CAP_RTF], sizeof(capability))){ + Message *msg = new Message(MessageGeneric); + QString text; + if (ICQClient::parseRTF(str, contact, text)) + msg->setFlags(MESSAGE_RICHTEXT); + log(L_DEBUG, "Msg: %s", str.data()); + msg->setText(text); + return msg; + } + if (!memcmp(unpack_cap, ICQClient::capabilities[CAP_UTF], sizeof(capability))){ + Message *msg = new Message(MessageGeneric); + msg->setText(QString::fromUtf8(str)); + return msg; + } + } + } + Message *m = new Message; + m->setServerText(str); + return m; +} + +static Message *parseURLMessage(const QByteArray &str) +{ + QList l; + if (!parseFE(str, l, 2)){ + log(L_WARN, "Parse error URL message"); + return NULL; + } + UrlMessage *m = new UrlMessage; + m->setServerText(l[0]); + m->setUrl(l[1]); + return m; +} + +//ToDo: Send Contacts does not work +static Message *parseContactMessage(const QByteArray &str) +{ + QList l; + if (!parseFE(str, l, 2)){ + log(L_WARN, "Parse error contacts message"); + return NULL; + } + unsigned nContacts = l[0].toUInt(); + if (nContacts == 0){ + log(L_WARN, "No contacts found"); + return NULL; + } + QList c; + if (!parseFE(l[1], c, nContacts*2+1)){ + log(L_WARN, "Parse error contacts message"); + return NULL; + } + QByteArray serverText; + for (unsigned i = 0; i < nContacts; i++){ + QByteArray screen = c[i*2]; + QByteArray alias = c[i*2+1]; + if (!serverText.isEmpty()) + serverText += ';'; + if (screen.toULong()){ + serverText += "icq:"; + serverText += screen; + serverText += '/'; + serverText += alias; + serverText += ','; + if (screen == alias){ + serverText += "ICQ "; + serverText += screen; + }else{ + serverText += alias; + serverText += " (ICQ "; + serverText += screen; + serverText += ')'; + } + }else{ + serverText += "aim:"; + serverText += screen; + serverText += '/'; + serverText += alias; + serverText += ','; + if (screen == alias){ + serverText += "AIM "; + serverText += screen; + }else{ + serverText += alias; + serverText += " (AIM "; + serverText += screen; + serverText += ')'; + } + } + } + IcqContactsMessage *m = new IcqContactsMessage; + m->setServerText(serverText); + return m; +} + +static Message *parseAuthRequest(const QByteArray &str) +{ + QList l; + if (!parseFE(str, l, 6)){ + log(L_WARN, "Parse error auth request message"); + return NULL; + } + ICQAuthMessage *m = new ICQAuthMessage(MessageICQAuthRequest, MessageAuthRequest); + m->setServerText(l[4]); + return m; +} + +Message *ICQClient::parseExtendedMessage(const QString &screen, ICQBuffer &packet, MessageId &id, unsigned cookie) +{ + string header; + packet >> header; + ICQBuffer h(header.size()); + //QString strheader(header); + h.pack(header.c_str(), header.size()); + h.incReadPos(16); + unsigned short msg_type; + h >> msg_type; + //QString msgType; + string msgType; + h.unpackStr32(msgType); + //QString info; + string info; + packet.unpackStr32(info); + ICQBuffer b(info.size()); + b.pack(info.c_str(), info.size()); + + log(L_DEBUG, "Extended message %s [%04X] %u", msgType.data(), msg_type, (unsigned int)info.length()); + + int n = msgType.find("URL"); + if (n >= 0){ + QByteArray info; + b.unpackStr32(info); + return parseURLMessage(info); + } + if (msgType == "Request For Contacts"){ + QByteArray info; + b.unpackStr32(info); + ICQAuthMessage *m = new ICQAuthMessage(MessageContactRequest, MessageContactRequest); + m->setServerText(info); + return m; + } + if (msgType == "Contacts"){ + QByteArray p; + b.unpackStr32(p); + return parseContactMessage(p); + } + if (msgType == "Message"){ + QByteArray p; + b.unpackStr32(p); + unsigned long forecolor, backcolor; + b >> forecolor >> backcolor; + QByteArray cap_str; + b.unpackStr32(cap_str); + Contact *contact; + ICQUserData *data = findContact(screen, NULL, false, contact); + if (data == NULL) { + data = findContact(screen, NULL, true, contact); + if (data == NULL) { + return NULL; + } + contact->setFlags(contact->getFlags() | CONTACT_TEMP); + } + Message *msg = parseTextMessage(p, cap_str, contact); + if (msg){ + if (forecolor != backcolor){ + msg->setForeground(forecolor >> 8); + msg->setBackground(backcolor >> 8); + } + } + return msg; + } + n = msgType.find("File"); + if (n >= 0){ + string fileDescr, fileName; + b.unpackStr32(fileDescr); + unsigned short port; + b >> port; + b.incReadPos(2); + b >> fileName; + unsigned long fileSize; + b.unpack(fileSize); + ICQFileMessage *m = new ICQFileMessage; +//#ifdef __OS2__ // to make it compileable under OS/2 (gcc 3.3.5) + m->setServerDescr(fileName.c_str()); +//#else +// m->setServerDescr(fileName); +//#endif + m->setServerText(QByteArray(fileDescr.data())); + m->setSize(fileSize); + m->setPort(port); + m->setFlags(MESSAGE_TEMP); + m->setID_L(id.id_l); + m->setID_H(id.id_h); + m->setCookie(cookie); + m->setExtended(true); + return m; + } + if (msgType == "ICQSMS"){ + string p; + b.unpackStr32(p); + //p = QCString(info).data(); // FIXME!! + string::iterator s = p.begin(); + auto_ptr top(XmlNode::parse(s, p.end())); + if (top.get() == NULL){ + log(L_WARN, "Parse SMS XML error"); + return NULL; + } + if (msg_type == 0){ + if (top->getTag() != "sms_message"){ + log(L_WARN, "No sms_message tag in SMS message"); + return NULL; + } + XmlNode *n = top.get(); + if ((n == NULL) || !n->isBranch()){ + log(L_WARN, "Parse no branch"); + return NULL; + } + XmlBranch *sms_message = static_cast(n); + XmlLeaf *text = sms_message->getLeaf("text"); + if (text == NULL){ + log(L_WARN, "No in SMS message"); + return NULL; + } + SMSMessage *m = new SMSMessage; + XmlLeaf *sender = sms_message->getLeaf("sender"); + if (sender != NULL){ + m->setPhone(QString::fromUtf8(sender->getValue().c_str())); + // string -> QString is ok here since phone doesn't contain non ascii chars + Contact *contact = getContacts()->contactByPhone(sender->getValue().c_str()); + m->setContact(contact->id()); + } + XmlLeaf *senders_network = sms_message->getLeaf("senders_network"); + if (senders_network != NULL) + m->setNetwork(QString::fromUtf8(senders_network->getValue().c_str())); + m->setText(QString::fromUtf8(text->getValue().c_str())); + return m; + } + } + if (msgType == "StatusMsgExt"){ + StatusMessage *m = new StatusMessage; + return m; + } + log(L_WARN, "Unknown extended message type %s", msgType.data()); + return NULL; +} + +Message *ICQClient::parseMessage(unsigned short type, const QString &screen, const QByteArray &p, ICQBuffer &packet, MessageId &id, unsigned cookie) +{ + if (screen.toULong() == 0x0A){ + QList l; + if (!parseFE(p, l, 6)){ + log(L_WARN, "Parse error web panel message"); + return NULL; + } + char SENDER_IP[] = "Sender IP:"; + QByteArray head = l[5].left(strlen(SENDER_IP)); + Message *msg = new Message((head == SENDER_IP) ? MessageWebPanel : MessageEmailPager); + QString name = getContacts()->toUnicode(NULL, l[0]); + QString mail = getContacts()->toUnicode(NULL, l[3]); + msg->setServerText(l[5]); + Contact *contact = getContacts()->contactByMail(mail, name); + if (contact == NULL){ + delete msg; + return NULL; + } + msg->setContact(contact->id()); + return msg; + } + log(L_DEBUG, "Parse message [type=%u]", type); + Message *msg = NULL; + switch (type){ + case ICQ_MSGxMSG:{ + unsigned long forecolor, backcolor; + packet >> forecolor >> backcolor; + QByteArray cap_str; + packet.unpackStr32(cap_str); + Contact *contact; + ICQUserData *data = findContact(screen, NULL, false, contact); + if (data == NULL) { + data = findContact(screen, NULL, true, contact); + if (data == NULL) { + return NULL; + } + contact->setFlags(contact->getFlags() | CONTACT_TEMP); + } + msg = parseTextMessage(p, cap_str, contact); + if (msg == NULL) + break; + if (forecolor != backcolor){ + msg->setForeground(forecolor >> 8); + msg->setBackground(backcolor >> 8); + } + break; + } + case ICQ_MSGxURL: + msg = parseURLMessage(p); + break; + case ICQ_MSGxAUTHxREQUEST: + msg = parseAuthRequest(p); + break; + case ICQ_MSGxAUTHxGRANTED: + msg = new AuthMessage(MessageAuthGranted); + break; + case ICQ_MSGxAUTHxREFUSED: + msg = new AuthMessage(MessageAuthRefused); + break; + case ICQ_MSGxADDEDxTOxLIST: + msg = new AuthMessage(MessageAdded); + break; + case ICQ_MSGxCONTACTxLIST: + msg = parseContactMessage(p); + break; + case ICQ_MSGxFILE:{ + ICQFileMessage *m = new ICQFileMessage; + m->setServerText(p); + unsigned short port; + unsigned long fileSize; + QByteArray fileName; + packet >> port; + packet.incReadPos(2); + packet >> fileName; + packet.unpack(fileSize); + m->setPort(port); + m->setSize(fileSize); + m->setServerDescr(fileName); + msg = m; + break; + } + case ICQ_MSGxEXT: + msg = parseExtendedMessage(screen, packet, id, cookie); + break; + default: + log(L_WARN, "Unknown message type %04X", type); + } + return msg; +} + +static Message *createIcqFile(Buffer *cfg) +{ + return new ICQFileMessage(cfg); +} + +#if 0 +i18n("File", "%n files", 1); +#endif + +static MessageDef defIcqFile = + { + NULL, + NULL, + MESSAGE_CHILD, + "File", + "%n files", + createIcqFile, + NULL, + NULL + }; + +#if 0 +i18n("WWW-panel message", "%n WWW-panel messages", 1); +#endif + +static Message *createWebPanel(Buffer *cfg) +{ + return new Message(MessageWebPanel, cfg); +} + +static MessageDef defWebPanel = + { + NULL, + NULL, + MESSAGE_DEFAULT, + "WWW-panel message", + "%n WWW-panel messages", + createWebPanel, + NULL, + NULL + }; + +#if 0 +i18n("Email pager message", "%n Email pager messages", 1); +#endif + +static Message *createEmailPager(Buffer *cfg) +{ + return new Message(MessageEmailPager, cfg); +} + +static MessageDef defEmailPager = + { + NULL, + NULL, + MESSAGE_DEFAULT, + "Email pager message", + "%n Email pager messages", + createEmailPager, + NULL, + NULL + }; + +#if 0 +i18n("Request secure channel", "%n requests secure channel", 1); +#endif + +static Message *createOpenSecure(Buffer *cfg) +{ + return new Message(MessageOpenSecure, cfg); +} + +static MessageDef defOpenSecure = + { + NULL, + NULL, + MESSAGE_SENDONLY, + "Request secure channel", + "%n requests secure channel", + createOpenSecure, + NULL, + NULL + }; + +#if 0 +i18n("Close secure channel", "%n times close secure channel", 1); +#endif + +static Message *createCloseSecure(Buffer *cfg) +{ + return new Message(MessageCloseSecure, cfg); +} + +static MessageDef defCloseSecure = + { + NULL, + NULL, + MESSAGE_SILENT | MESSAGE_SENDONLY, + "Close secure channel", + "%n times close secure channel", + createCloseSecure, + NULL, + NULL + }; + +#if 0 +i18n("Warning", "%n warnings", 1); +#endif + +static DataDef warningMessageData[] = + { + { "Anonymous", DATA_BOOL, 1, 0 }, + { "OldLevel", DATA_ULONG, 1, 0 }, + { "NewLevel", DATA_ULONG, 1, 0 }, + { NULL, DATA_UNKNOWN, 0, 0 } + }; + +WarningMessage::WarningMessage(Buffer *cfg) + : AuthMessage(MessageWarning, cfg) +{ + load_data(warningMessageData, &data, cfg); +} + +QByteArray WarningMessage::save() +{ + QByteArray res = AuthMessage::save(); + if (!res.isEmpty()) + res += '\n'; + return res + save_data(warningMessageData, &data); +} + +QString WarningMessage::presentation() +{ + return QString("Increase warning level from %1% to %2%") + .arg(ICQClient::warnLevel(getOldLevel())) + .arg(ICQClient::warnLevel(getNewLevel())); +} + +static Message *createWarning(Buffer *cfg) +{ + return new WarningMessage(cfg); +} + +static MessageDef defWarning = + { + NULL, + NULL, + MESSAGE_SENDONLY, + "Warning", + "%n warnings", + createWarning, + NULL, + NULL + }; + +static Message *createIcqAuthRequest(Buffer *cfg) +{ + return new ICQAuthMessage(MessageICQAuthRequest, MessageAuthRequest, cfg); +} + +static MessageDef defIcqAuthRequest = + { + NULL, + NULL, + MESSAGE_CHILD, + NULL, + NULL, + createIcqAuthRequest, + NULL, + NULL + }; + +static Message *createIcqAuthGranted(Buffer *cfg) +{ + return new ICQAuthMessage(MessageICQAuthGranted, MessageAuthGranted, cfg); +} + +static MessageDef defIcqAuthGranted = + { + NULL, + NULL, + MESSAGE_CHILD, + NULL, + NULL, + createIcqAuthGranted, + NULL, + NULL + }; + +static Message *createIcqAuthRefused(Buffer *cfg) +{ + return new ICQAuthMessage(MessageICQAuthRefused, MessageAuthRefused, cfg); +} + +static MessageDef defIcqAuthRefused = + { + NULL, + NULL, + MESSAGE_CHILD, + NULL, + NULL, + createIcqAuthRefused, + NULL, + NULL + }; + +static Message *createContactRequest(Buffer *cfg) +{ + return new ICQAuthMessage(MessageContactRequest, MessageContactRequest, cfg); +} + +#if 0 +i18n("Contact request", "%n contact requests", 1); +#endif + +static MessageDef defContactRequest = + { + NULL, + NULL, + MESSAGE_DEFAULT | MESSAGE_SYSTEM, + "Contact request", + "%n contact requests", + createContactRequest, + NULL, + NULL + }; + +static Message *createIcqContacts(Buffer *cfg) +{ + return new IcqContactsMessage(cfg); +} + +static MessageDef defIcqContacts = + { + NULL, + NULL, + MESSAGE_CHILD, + NULL, + NULL, + createIcqContacts, + NULL, + NULL + }; + +void ICQPlugin::registerMessages() +{ + Command cmd; + + cmd->id = MessageICQContacts; + cmd->text = "ICQContacts"; + cmd->icon = "contacts"; + cmd->param = &defIcqContacts; + EventCreateMessageType(cmd).process(); + + cmd->id = MessageICQFile; + cmd->text = "ICQFile"; + cmd->icon = "file"; + cmd->param = &defIcqFile; + EventCreateMessageType(cmd).process(); + + cmd->id = MessageContactRequest; + cmd->text = I18N_NOOP("Contact Request"); + cmd->icon = "contacts"; + cmd->param = &defContactRequest; + EventCreateMessageType(cmd).process(); + + cmd->id = MessageICQAuthRequest; + cmd->text = "ICQAuthRequest"; + cmd->icon = "auth"; + cmd->param = &defIcqAuthRequest; + EventCreateMessageType(cmd).process(); + + cmd->id = MessageICQAuthGranted; + cmd->text = "ICQAuthGranted"; + cmd->icon = "auth"; + cmd->param = &defIcqAuthGranted; + EventCreateMessageType(cmd).process(); + + cmd->id = MessageICQAuthRefused; + cmd->text = "ICQAuthRefused"; + cmd->icon = "auth"; + cmd->param = &defIcqAuthRefused; + EventCreateMessageType(cmd).process(); + + cmd->id = MessageWebPanel; + cmd->text = I18N_NOOP("Web panel"); + cmd->icon = "web"; + cmd->param = &defWebPanel; + EventCreateMessageType(cmd).process(); + + cmd->id = MessageEmailPager; + cmd->text = I18N_NOOP("Email pager"); + cmd->icon = "mailpager"; + cmd->param = &defEmailPager; + EventCreateMessageType(cmd).process(); + + cmd->id = MessageOpenSecure; + cmd->text = I18N_NOOP("Request secure channel"); + cmd->icon = "encrypted"; + cmd->menu_grp = 0x30F0; + cmd->param = &defOpenSecure; + EventCreateMessageType(cmd).process(); + + cmd->id = MessageCloseSecure; + cmd->text = I18N_NOOP("Close secure channel"); + cmd->icon = "encrypted"; + cmd->menu_grp = 0x30F0; + cmd->param = &defCloseSecure; + EventCreateMessageType(cmd).process(); + + cmd->id = MessageWarning; + cmd->text = I18N_NOOP("Warning"); + cmd->icon = "error"; + cmd->menu_grp = 0x30F2; + cmd->param = &defWarning; + EventCreateMessageType(cmd).process(); + + cmd->id = CmdUrlInput; + cmd->text = I18N_NOOP("&URL"); + cmd->icon = "empty"; + cmd->icon_on = QString::null; + cmd->bar_id = ToolBarMsgEdit; + cmd->bar_grp = 0x1030; + cmd->menu_id = 0; + cmd->menu_grp = 0; + cmd->flags = BTN_EDIT | BTN_NO_BUTTON | COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); +} + +void ICQPlugin::unregisterMessages() +{ + EventRemoveMessageType(MessageICQUrl).process(); + EventRemoveMessageType(MessageICQContacts).process(); + EventRemoveMessageType(MessageICQ).process(); + EventRemoveMessageType(MessageICQFile).process(); + EventRemoveMessageType(MessageICQAuthRequest).process(); + EventRemoveMessageType(MessageICQAuthGranted).process(); + EventRemoveMessageType(MessageICQAuthRefused).process(); + EventRemoveMessageType(MessageContactRequest).process(); + EventRemoveMessageType(MessageWebPanel).process(); + EventRemoveMessageType(MessageEmailPager).process(); + EventRemoveMessageType(MessageOpenSecure).process(); + EventRemoveMessageType(MessageCloseSecure).process(); + EventRemoveMessageType(MessageWarning).process(); + + EventCommandRemove(CmdUrlInput).process(); +} + +void ICQClient::packExtendedMessage(Message *msg, ICQBuffer &buf, ICQBuffer &msgBuf, ICQUserData *data) +{ + unsigned short port = 0; + switch (msg->type()){ + case MessageICQFile: + port = static_cast(msg)->getPort(); + case MessageFile: + buf.pack((char*)plugins[PLUGIN_FILE], sizeof(plugin)); + buf.packStr32("File"); + buf << 0x00000100L << 0x00010000L << 0x00000000L << (unsigned short)0 << (char)0; + //msgBuf.packStr32(getContacts()->fromUnicode(getContact(data), msg->getPlainText())); + string msgdata1 = getContacts()->fromUnicode(getContact(data), msg->getPlainText()).data(); + msgBuf.packStr32(msgdata1.c_str()); + msgBuf << port << (unsigned short)0; + //msgBuf << getContacts()->fromUnicode(getContact(data), static_cast(msg)->getDescription()); + string msgdata2 = getContacts()->fromUnicode(getContact(data), static_cast(msg)->getDescription()).data(); + msgBuf << msgdata2.c_str(); + msgBuf.pack((unsigned long)(static_cast(msg)->getSize())); + msgBuf << 0x00000000L; + break; + } +} + +QString ICQClient::packContacts(ContactsMessage *msg, ICQUserData *, CONTACTS_MAP &c) +{ + QString contacts = msg->getContacts(); + QString newContacts; + while (!contacts.isEmpty()){ + QString contact = getToken(contacts, ';'); + QString url = getToken(contact, ','); + QString proto = getToken(url, ':'); + if (proto == "sim"){ + Contact *contact = getContacts()->contact(url.toULong()); + if (contact){ + ClientDataIterator it(contact->clientData); + clientData *cdata; + while ((cdata = ++it) != NULL){ + Contact *cc = contact; + if (!isMyData(cdata, cc)) + continue; + ICQUserData *d = toICQUserData(cdata); + QString screen = this->screen(d); + CONTACTS_MAP::iterator it = c.find(screen); + if (it == c.end()){ + alias_group ci; + ci.alias = contact->getName(); + ci.grp = cc ? cc->getGroup() : 0; + c.insert(CONTACTS_MAP::value_type(screen, ci)); + if (!newContacts.isEmpty()) + newContacts += ';'; + if (screen.toULong()){ + newContacts += "icq:"; + newContacts += screen; + newContacts += '/'; + newContacts += contact->getName(); + newContacts += ','; + if (contact->getName() == screen){ + newContacts += "ICQ "; + newContacts += screen; + }else{ + newContacts += contact->getName(); + newContacts += " (ICQ "; + newContacts += screen; + newContacts += ')'; + } + }else{ + newContacts += "aim:"; + newContacts += screen; + newContacts += '/'; + newContacts += contact->getName(); + newContacts += ','; + if (contact->getName() == screen){ + newContacts += "AIM "; + newContacts += screen; + }else{ + newContacts += contact->getName(); + newContacts += " (AIM "; + newContacts += screen; + newContacts += ')'; + } + } + } + } + } + } + if ((proto == "icq") || (proto == "aim")){ + QString screen = getToken(url, '/'); + if (url.isEmpty()) + url = screen; + CONTACTS_MAP::iterator it = c.find(screen); + if (it == c.end()){ + alias_group ci; + ci.alias = url; + ci.grp = 0; + c.insert(CONTACTS_MAP::value_type(screen, ci)); + } + } + } + return newContacts; +} + +void ICQClient::packMessage(ICQBuffer &b, Message *msg, ICQUserData *data, unsigned short &type, bool bDirect, unsigned short flags) +{ + ICQBuffer msgBuf, buf; + QString res; + switch (msg->type()){ + case MessageUrl: + res = getContacts()->fromUnicode(getContact(data), msg->getPlainText()); + res += '\xFE'; + res += getContacts()->fromUnicode(getContact(data), static_cast(msg)->getUrl()); + type = ICQ_MSGxURL; + break; + case MessageContacts:{ + CONTACTS_MAP c; + QString nc = packContacts(static_cast(msg), data, c); + if (c.empty()){ + msg->setError(I18N_NOOP("No contacts for send")); + return; + } + static_cast(msg)->setContacts(nc); + res = QString::number(c.size()); + for (CONTACTS_MAP::iterator it = c.begin(); it != c.end(); ++it){ + res += '\xFE'; + res += getContacts()->fromUnicode(getContact(data), it->first.str()); + res += '\xFE'; + res += getContacts()->fromUnicode(getContact(data), it->second.alias); + } + res += '\xFE'; + type = ICQ_MSGxCONTACTxLIST; + break; + } + case MessageICQFile: + if (!static_cast(msg)->getExtended()){ + res = getContacts()->fromUnicode(getContact(data), msg->getPlainText()); + type = ICQ_MSGxFILE; + break; + } + case MessageFile: // FALLTHROW + type = ICQ_MSGxEXT; + packExtendedMessage(msg, buf, msgBuf, data); + break; + case MessageOpenSecure: + type = ICQ_MSGxSECURExOPEN; + break; + case MessageCloseSecure: + type = ICQ_MSGxSECURExCLOSE; + break; + } + if (flags == ICQ_TCPxMSG_NORMAL){ + if (msg->getFlags() & MESSAGE_URGENT) + flags = ICQ_TCPxMSG_URGENT; + if (msg->getFlags() & MESSAGE_LIST) + flags = ICQ_TCPxMSG_LIST; + } + if (bDirect || (type == ICQ_MSGxEXT)){ + b.pack(type); + b.pack(msgStatus()); + b.pack(flags); + }else{ + b.pack(this->data.owner.Uin.toULong()); + b.pack((char)type); + b.pack((char)0x01); + } + b << res; + if (buf.size()){ + b.pack((unsigned short)buf.size()); + b.pack(buf.data(0), buf.size()); + b.pack32(msgBuf); + } +} + +void ICQClient::parsePluginPacket(ICQBuffer &b, unsigned plugin_type, ICQUserData *data, unsigned uin, bool bDirect) +{ + b.incReadPos(1); + unsigned short type; + b >> type; + b.incReadPos(bDirect ? 1 : 4); + QList phonebook; + QList numbers; + QList phonedescr; + Contact *contact = NULL; + unsigned long state, time, size, nEntries; + unsigned i; + unsigned nActive; + switch (type){ + case 0: + case 1: + b.unpack(time); + b.unpack(size); + b.incReadPos(4); + b.unpack(nEntries); + if (data) + log(L_DEBUG, "Plugin info reply %lu %lu (%lu %lu) %lu %lu (%u)", + data->Uin.toULong(), time, data->PluginInfoTime.toULong(), + data->PluginStatusTime.toULong(), size, nEntries, plugin_type); + switch (plugin_type){ + case PLUGIN_RANDOMxCHAT:{ + QByteArray name, topic, homepage; + + b.incReadPos(-12); + b.unpackStr(name); + b.unpackStr(topic); + unsigned short age; + char gender; + unsigned short country; + unsigned short language; + b.unpack(age); + b.unpack(gender); + b.unpack(country); + b.unpack(language); + b.unpackStr(homepage); + ICQUserData data; + load_data(static_cast(protocol())->icqUserData, &data, NULL); + data.Uin.asULong() = uin; + data.Alias.str() = QString::fromUtf8(name); + data.About.str() = QString::fromUtf8(topic); + data.Age.asULong() = age; + data.Gender.asULong() = gender; + data.Country.asULong() = country; + data.Language.asULong() = language; + data.Homepage.str() = QString::fromUtf8(homepage); +// currently unhandled +// Event e(EventRandomChatInfo, &data); +// e.process(); + free_data(static_cast(protocol())->icqUserData, &data); + break; + } + case PLUGIN_QUERYxSTATUS: + if (data == NULL) + break; + if (!bDirect){ + b.incReadPos(5); + b.unpack(nEntries); + } + log(L_DEBUG, "Status info answer %lu", nEntries); + case PLUGIN_QUERYxINFO: + if (data == NULL) + break; + if (nEntries > 0x80){ + log(L_DEBUG, "Bad entries value %lX", nEntries); + break; + } + for (i = 0; i < nEntries; i++){ + plugin p; + b.unpack((char*)p, sizeof(p)); + b.incReadPos(4); + QByteArray name, descr; + b.unpackStr32(name); + b.unpackStr32(descr); + b.incReadPos(4); + unsigned plugin_index; + for (plugin_index = 0; plugin_index < PLUGIN_NULL; plugin_index++) + if (memcmp(p, plugins[plugin_index], sizeof(p)) == 0) + break; + if (plugin_index >= PLUGIN_NULL){ + log(L_DEBUG, "Unknown plugin sign %s %s", name.data(), descr.data()); + continue; + } + log(L_DEBUG, "Plugin %u %s %s", plugin_index, name.data(), descr.data()); + switch (plugin_index){ + case PLUGIN_PHONEBOOK: + case PLUGIN_FOLLOWME: + if (plugin_type == PLUGIN_QUERYxINFO){ + addPluginInfoRequest(uin, PLUGIN_PHONEBOOK); + }else{ + addPluginInfoRequest(uin, PLUGIN_FOLLOWME); + } + break; + case PLUGIN_PICTURE: + if (plugin_type == PLUGIN_QUERYxINFO) { + // when buddyID -> new avatar support, no need to ask for old picture plugin + if(data->buddyID.toULong() == 0 || data->buddyHash.toBinary().size() != 16) { + data->buddyID.asULong() = 0; + addPluginInfoRequest(uin, plugin_index); + } + } + break; + case PLUGIN_FILESERVER: + case PLUGIN_ICQPHONE: + if (plugin_type == PLUGIN_QUERYxSTATUS) + addPluginInfoRequest(uin, plugin_index); + break; + } + } + if (plugin_type == PLUGIN_QUERYxINFO){ + data->PluginInfoFetchTime = data->PluginInfoTime; + }else{ + data->PluginStatusFetchTime = data->PluginStatusTime; + } + break; + case PLUGIN_PICTURE: + if (data){ + b.incReadPos(-4); + QByteArray pict; + QByteArray ba; + b.unpackStr32(pict); + b.unpackStr32(ba); + QImage img; + QString fName = pictureFile(data); + QFile f(fName); + if (f.open(QIODevice::WriteOnly | QIODevice::Truncate)){ + f.write(ba.data()); + f.close(); + img.load(fName); + }else{ + log(L_ERROR, "Can't create %s", qPrintable(fName)); + } + data->PictureWidth.asULong() = img.width(); + data->PictureHeight.asULong() = img.height(); + } + break; + case PLUGIN_PHONEBOOK: + if (data){ + QString phones; + nActive = (unsigned)(-1); + if (nEntries > 0x80){ + log(L_DEBUG, "Bad entries value %lX", nEntries); + break; + } + for (i = 0; i < nEntries; i++){ + QByteArray descr, area, phone, ext, country; + unsigned long active; + b.unpackStr32(descr); + b.unpackStr32(area); + b.unpackStr32(phone); + b.unpackStr32(ext); + b.unpackStr32(country); + numbers.push_back(phone); + QByteArray value; + for (const ext_info *e = getCountries(); e->szName; e++){ + if (country == e->szName){ + value = "+"; + value += QByteArray::number(e->nCode); + break; + } + } + if (!area.isEmpty()){ + if (!value.isEmpty()) + value += ' '; + value += '('; + value += area; + value += ')'; + } + if (!value.isEmpty()) + value += ' '; + value += phone; + if (!ext.isEmpty()){ + value += " - "; + value += ext; + } + b.unpack(active); + if (active) + nActive = i; + phonebook.push_back(value); + phonedescr.push_back(descr); + } + for (i = 0; i < nEntries; i++){ + unsigned long type; + QByteArray phone = phonebook[i]; + QByteArray gateway; + b.incReadPos(4); + b.unpack(type); + b.unpackStr32(gateway); + b.incReadPos(16); + switch (type){ + case 1: + case 2: + type = CELLULAR; + break; + case 3: + type = FAX; + break; + case 4:{ + type = PAGER; + phone = numbers[i]; + const pager_provider *p; + for (p = getProviders(); *p->szName; p++){ + if (gateway == p->szName){ + phone += '@'; + phone += p->szGate; + phone += '['; + phone += p->szName; + phone += ']'; + break; + } + } + if (*p->szName == 0){ + phone += '@'; + phone += gateway; + } + break; + } + default: + type = PHONE; + } + phone += ','; + phone += phonedescr[i]; + phone += ','; + phone += QByteArray::number((quint32)type); + if (i == nActive) + phone += ",1"; + if (!phones.isEmpty()) + phones += ';'; + phones += QString::fromUtf8(phone); + } + data->PhoneBook.str() = phones; + Contact *contact = NULL; + findContact(data->Uin.toULong(), NULL, false, contact); + if (contact){ + setupContact(contact, data); + EventContact e(contact, EventContact::eChanged); + e.process(); + } + } + } + break; + case 2: + if (data){ + if (bDirect) + b.incReadPos(3); + b.unpack(state); + b.unpack(time); + log(L_DEBUG, "Plugin status reply %u %lu %lu (%u)", uin, state, time, plugin_type); + findContact(uin, NULL, false, contact); + if (contact == NULL) + break; + switch (plugin_type){ + case PLUGIN_FILESERVER: + if ((state != 0) != (data->SharedFiles.toBool() != 0)){ + data->SharedFiles.asBool() = (state != 0); + EventContact e(contact, EventContact::eChanged); + e.process(); + } + break; + case PLUGIN_FOLLOWME: + if (state != data->FollowMe.toULong()){ + data->FollowMe.asULong() = state; + EventContact e(contact, EventContact::eChanged); + e.process(); + } + break; + case PLUGIN_ICQPHONE: + if ((state != 0) != (data->ICQPhone.toULong() != 0)){ + data->ICQPhone.asULong() = (state != 0); + EventContact e(contact, EventContact::eChanged); + e.process(); + } + break; + } + } + break; + default: + log(L_DEBUG, "Unknown plugin type answer %u %u (%u)", uin, type, plugin_type); + } +} + +static const char* plugin_name[] = + { + "Phone Book", // PLUGIN_PHONEBOOK + "Picture", // PLUGIN_PICTURE + "Shared Files Directory", // PLUGIN_FILESERVER + "Phone \"Follow Me\"", // PLUGIN_FOLLOWME + "ICQphone Status" // PLUGIN_ICQPHONE + }; + +static const char* plugin_descr[] = + { + "Phone Book / Phone \"Follow Me\"", // PLUGIN_PHONEBOOK + "Picture", // PLUGIN_PICTURE + "Shared Files Directory", // PLUGIN_FILESERVER + "Phone Book / Phone \"Follow Me\"", // PLUGIN_FOLLOWME + "ICQphone Status" // PLUGIN_ICQPHONE + }; + +void ICQClient::pluginAnswer(unsigned plugin_type, unsigned long uin, ICQBuffer &info) +{ + Contact *contact; + ICQUserData *data = findContact(uin, NULL, false, contact); + log(L_DEBUG, "Request about %u", plugin_type); + ICQBuffer answer; + unsigned long typeAnswer = 0; + unsigned long nEntries = 0; + unsigned long time = 0; + switch (plugin_type){ + case PLUGIN_PHONEBOOK:{ + if (data && data->GrpId.toULong() && !contact->getIgnore()){ + ICQBuffer answer1; + time = this->data.owner.PluginInfoTime.toULong(); + QString phones = getContacts()->owner()->getPhones(); + while (!phones.isEmpty()){ + QString item = getToken(phones, ';', false); + unsigned long publish = 0; + QString phoneItem = getToken(item, '/', false); + if (item != "-") + publish = 1; + QString number = getToken(phoneItem, ','); + QString descr = getToken(phoneItem, ','); + unsigned long type = getToken(phoneItem, ',').toUInt(); + unsigned long active = 0; + if (!phoneItem.isEmpty()) + active = 1; + QString area; + QString phone; + QString ext; + QString country; + QString gateway; + if (type == PAGER){ + phone = getToken(number, '@'); + int n = number.indexOf('['); + if (n >= 0){ + getToken(number, '['); + gateway = getToken(number, ']'); + }else{ + gateway = number; + } + }else{ + int n = number.indexOf('('); + if (n >= 0){ + country = getToken(number, '('); + area = getToken(number, ')'); + if (country[0] == '+') + country = country.mid(1); + unsigned code = country.toULong(); + country = QString::null; + for (const ext_info *e = getCountries(); e->nCode; e++){ + if (e->nCode == code){ + country = e->szName; + break; + } + } + } + n = number.indexOf(" - "); + if (n >= 0){ + ext = number.mid(n + 3); + number = number.left(n); + } + phone = number; + } + answer.packStr32(descr.toUtf8().data()); + answer.packStr32(area.toUtf8().data()); + answer.packStr32(phone.toUtf8().data()); + answer.packStr32(ext.toUtf8().data()); + answer.packStr32(country.toUtf8().data()); + answer.pack(active); + + unsigned long len = gateway.length() + 24; + unsigned long sms_available = 0; + switch (type){ + case PHONE: + type = 0; + break; + case FAX: + type = 3; + break; + case CELLULAR: + type = 2; + sms_available = 1; + break; + case PAGER: + type = 4; + break; + } + answer1.pack(len); + answer1.pack(type); + answer1.packStr32(gateway.toUtf8().data()); + answer1.pack((unsigned long)0); + answer1.pack(sms_available); + answer1.pack((unsigned long)0); + answer1.pack(publish); + nEntries++; + } + answer.pack(answer1.data(0), answer1.size()); + typeAnswer = 0x00000003; + break; + } + } + case PLUGIN_PICTURE:{ + time = this->data.owner.PluginInfoTime.toULong(); + typeAnswer = 0x00000001; + QString pictFile = getPicture(); + if (!pictFile.isEmpty()){ + QFile f(pictFile); + if (f.open(QIODevice::ReadOnly)){ + QFileInfo fi(f); + pictFile = fi.fileName(); + nEntries = pictFile.length(); + answer.pack(pictFile.toLocal8Bit(), pictFile.length()); + unsigned long size = f.size(); + answer.pack(size); + while (size > 0){ + char buf[2048]; + unsigned tail = sizeof(buf); + if (tail > size) + tail = size; + f.read(buf, tail); + answer.pack(buf, tail); + size -= tail; + } + } + } + break; + } + case PLUGIN_FOLLOWME: + time = this->data.owner.PluginStatusTime.toULong(); + break; + case PLUGIN_QUERYxINFO: + time = this->data.owner.PluginInfoTime.toULong(); + typeAnswer = 0x00010002; + if (!getPicture().isEmpty()){ + nEntries++; + answer.pack((char*)plugins[PLUGIN_PICTURE], sizeof(plugin)); + answer.pack((unsigned short)0); + answer.pack((unsigned short)1); + answer.packStr32(plugin_name[PLUGIN_PICTURE]); + answer.packStr32(plugin_descr[PLUGIN_PICTURE]); + answer.pack((unsigned long)0); + } + if (!getContacts()->owner()->getPhones().isEmpty()){ + nEntries++; + answer.pack((char*)plugins[PLUGIN_PHONEBOOK], sizeof(plugin)); + answer.pack((unsigned short)0); + answer.pack((unsigned short)1); + answer.packStr32(plugin_name[PLUGIN_PHONEBOOK]); + answer.packStr32(plugin_descr[PLUGIN_PHONEBOOK]); + answer.pack((unsigned long)0); + } + break; + case PLUGIN_QUERYxSTATUS: + time = this->data.owner.PluginStatusTime.toULong(); + typeAnswer = 0x00010000; + nEntries++; + answer.pack((char*)plugins[PLUGIN_FOLLOWME], sizeof(plugin)); + answer.pack((unsigned short)0); + answer.pack((unsigned short)1); + answer.packStr32(plugin_name[PLUGIN_FOLLOWME]); + answer.packStr32(plugin_descr[PLUGIN_FOLLOWME]); + answer.pack((unsigned long)0); + if (this->data.owner.SharedFiles.toBool()){ + nEntries++; + answer.pack((char*)plugins[PLUGIN_FILESERVER], sizeof(plugin)); + answer.pack((unsigned short)0); + answer.pack((unsigned short)1); + answer.packStr32(plugin_name[PLUGIN_FILESERVER]); + answer.packStr32(plugin_descr[PLUGIN_FILESERVER]); + answer.pack((unsigned long)0); + } + if (this->data.owner.ICQPhone.toULong()){ + nEntries++; + answer.pack((char*)plugins[PLUGIN_ICQPHONE], sizeof(plugin)); + answer.pack((unsigned short)0); + answer.pack((unsigned short)1); + answer.packStr32(plugin_name[PLUGIN_ICQPHONE]); + answer.packStr32(plugin_descr[PLUGIN_ICQPHONE]); + answer.pack((unsigned long)0); + } + break; + default: + log(L_DEBUG, "Bad plugin type request %u", plugin_type); + } + unsigned long size = answer.size() + 8; + info.pack((unsigned short)0); + info.pack((unsigned short)1); + switch (plugin_type){ + case PLUGIN_FOLLOWME: + info.pack(this->data.owner.FollowMe.toULong()); + info.pack(time); + info.pack((char)1); + break; + case PLUGIN_QUERYxSTATUS: + info.pack((unsigned long)0); + info.pack((unsigned long)0); + info.pack((char)1); + default: + info.pack(time); + info.pack(size); + info.pack(typeAnswer); + info.pack(nEntries); + info.pack(answer.data(0), answer.size()); + } +} + + + diff --git a/plugins/icq/icqmessage.h b/plugins/icq/icqmessage.h new file mode 100644 index 0000000..d403c70 --- /dev/null +++ b/plugins/icq/icqmessage.h @@ -0,0 +1,142 @@ +/*************************************************************************** + icqmessage.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _ICQMESSAGE_H +#define _ICQMESSAGE_H + +#include "contacts.h" + +#include +#include +#include + +const unsigned long MessageICQ = 0x100; +const unsigned long MessageICQUrl = 0x101; +const unsigned long MessageICQContacts = 0x102; +const unsigned long MessageContactRequest = 0x103; +const unsigned long MessageICQAuthRequest = 0x104; +const unsigned long MessageICQAuthGranted = 0x105; +const unsigned long MessageICQAuthRefused = 0x106; +const unsigned long MessageWebPanel = 0x107; +const unsigned long MessageEmailPager = 0x108; +const unsigned long MessageOpenSecure = 0x109; +const unsigned long MessageCloseSecure = 0x110; +const unsigned long MessageICQFile = 0x112; +const unsigned long MessageWarning = 0x113; + +class IcqContactsMessage : public SIM::ContactsMessage +{ +public: + IcqContactsMessage(Buffer *cfg=NULL); + ~IcqContactsMessage(); + QString getContacts() const; + virtual unsigned baseType() { return SIM::MessageContacts; } +}; + +struct ICQAuthMessageData +{ + SIM::Data Charset; +}; + +class ICQAuthMessage : public SIM::AuthMessage +{ +public: + ICQAuthMessage(unsigned type, unsigned base_type, Buffer *cfg=NULL); + ~ICQAuthMessage(); + PROP_STR(Charset); + virtual QString getText() const; + virtual QByteArray save(); + virtual unsigned baseType() { return m_baseType; } +protected: + unsigned m_baseType; + ICQAuthMessageData data; +}; + +struct ICQFileMessageData +{ + SIM::Data ServerDescr; + SIM::Data IP; + SIM::Data Port; + SIM::Data ID_L; + SIM::Data ID_H; + SIM::Data Cookie; + SIM::Data Extended; +}; + +class ICQFileMessage : public SIM::FileMessage +{ +public: + ICQFileMessage(Buffer *cfg=NULL); + ~ICQFileMessage(); + PROP_STR(ServerDescr); + PROP_ULONG(IP); + PROP_USHORT(Port); + PROP_ULONG(ID_L); + PROP_ULONG(ID_H); + PROP_ULONG(Cookie); + PROP_ULONG(Extended); + virtual QString getDescription(); + virtual QByteArray save(); + virtual unsigned baseType() { return SIM::MessageFile; } +protected: + ICQFileMessageData data; +}; + +struct AIMFileMessageData +{ + SIM::Data Port; + SIM::Data ID_L; + SIM::Data ID_H; +}; + +class AIMFileMessage : public SIM::FileMessage +{ +public: + AIMFileMessage(Buffer *cfg=NULL); + ~AIMFileMessage(); + PROP_USHORT(Port); + PROP_ULONG(ID_L); + PROP_ULONG(ID_H); + virtual unsigned baseType() { return SIM::MessageFile; } + bool isProxy; + uint16_t cookie2; +protected: + AIMFileMessageData data; +}; + +struct MessageWarningData +{ + SIM::Data Anonymous; + SIM::Data OldLevel; + SIM::Data NewLevel; +}; + +class WarningMessage : public SIM::AuthMessage +{ +public: + WarningMessage(Buffer *cfg=NULL); + PROP_BOOL(Anonymous); + PROP_USHORT(OldLevel); + PROP_USHORT(NewLevel); + virtual QByteArray save(); + QString presentation(); +protected: + MessageWarningData data; +}; + +#endif + diff --git a/plugins/icq/icqpicture.cpp b/plugins/icq/icqpicture.cpp new file mode 100644 index 0000000..7c5f4e1 --- /dev/null +++ b/plugins/icq/icqpicture.cpp @@ -0,0 +1,152 @@ +/*************************************************************************** + icqpicture.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "icqpicture.h" +#include "icqclient.h" + +#include "log.h" + +#include "contacts/contact.h" +#include "simgui/editfile.h" +#include "simgui/ballonmsg.h" +#include "simgui/preview.h" + +#include +#include +#include +#include +#include +#include + +#include + +using namespace SIM; + +#ifndef USE_KDE + +static FilePreview *createPreview(QWidget *parent) +{ + return new PictPreview(parent); +} + +#endif + +ICQPicture::ICQPicture(QWidget *parent, ICQUserData *data, ICQClient *client) + : QWidget(parent) +{ + setupUi(this); + m_data = data; + m_client = client; + if (m_data) + { + edtPict->hide(); + btnClear->hide(); + } else { + QString format = QString("*.jpg"); + QList formats = QImageReader::supportedImageFormats(); + QByteArray f; + foreach( f, formats ) + { + f.toLower(); + format += " *." + f; + } +#ifdef USE_KDE + edtPict->setFilter(i18n("%1|Graphics").arg(format)); +#else + edtPict->setFilter(i18n("Graphics(%1)").arg(format)); + edtPict->setFilePreview(createPreview); +#endif + edtPict->setReadOnly(true); + connect(btnClear, SIGNAL(clicked()), this, SLOT(clearPicture())); + connect(edtPict, SIGNAL(textChanged(const QString&)), this, SLOT(pictSelected(const QString&))); + edtPict->setText(client->getPicture()); + pictSelected(client->getPicture()); + } + fill(); +} + +void ICQPicture::apply() +{ +} + +void ICQPicture::apply(Client *client, void *_data) +{ + if (client != m_client) + return; + QString pict = edtPict->text(); + log(L_DEBUG, "Pict: %s", qPrintable(pict)); + m_client->setPicture(pict); + m_client->data.owner.Picture.setStr(pict); + ICQUserData *data = m_client->toICQUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + if (lblPict->pixmap() == NULL) + pict.clear(); + if(pict != m_client->getPicture()) + { + data->PluginInfoTime.asULong() = time(NULL); + } +} + +bool ICQPicture::processEvent(Event *e) +{ + if (e->type() == eEventContact){ + EventContact *ec = static_cast(e); + if(ec->action() != EventContact::eChanged) + return false; + Contact *contact = ec->contact(); + if (contact->clientData.have(m_data)) + fill(); + } + return false; +} + +void ICQPicture::fill() +{ + setPict(m_client->userPicture(m_data)); +} + +void ICQPicture::clearPicture() +{ + edtPict->setText(QString::null); +} + +const unsigned short MAX_PICTURE_SIZE = 7168; + +void ICQPicture::pictSelected(const QString &file) +{ + if (file.isEmpty()){ + setPict(QImage()); + } else { + QFile f(file); + if (f.size() > MAX_PICTURE_SIZE){ + setPict(QImage()); + BalloonMsg::message(i18n("Picture can not be more than 7 kbytes"), edtPict); + } + setPict(QImage(file)); + } +} + +void ICQPicture::setPict(const QImage &img) +{ + if (img.isNull()){ + lblPict->setText(i18n("Picture is not available")); + return; + } + QPixmap pict = QPixmap::fromImage(img); + lblPict->setPixmap(pict); + lblPict->setMinimumSize(pict.size()); +} + diff --git a/plugins/icq/icqpicture.h b/plugins/icq/icqpicture.h new file mode 100644 index 0000000..178bf78 --- /dev/null +++ b/plugins/icq/icqpicture.h @@ -0,0 +1,50 @@ +/*************************************************************************** + icqpicture.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _ICQPICTURE_H +#define _ICQPICTURE_H + +#include "event.h" + +#include "ui_icqpicturebase.h" + +class ICQClient; +struct ICQUserData; + +class QImage; + +class ICQPicture : public QWidget, public Ui::ICQPictureBase, public SIM::EventReceiver +{ + Q_OBJECT +public: + ICQPicture(QWidget *parent, ICQUserData *data, ICQClient *client); +public slots: + void apply(); + void apply(SIM::Client*, void*); +protected slots: + void clearPicture(); + void pictSelected(const QString&); +protected: + virtual bool processEvent(SIM::Event *e); + void fill(); + void setPict(const QImage &img); + ICQUserData *m_data; + ICQClient *m_client; +}; + +#endif + diff --git a/plugins/icq/icqpicturebase.ui b/plugins/icq/icqpicturebase.ui new file mode 100644 index 0000000..adf3c0c --- /dev/null +++ b/plugins/icq/icqpicturebase.ui @@ -0,0 +1,123 @@ + + + + + ICQPictureBase + + + + 0 + 0 + 464 + 324 + + + + Form1 + + + + 11 + + + 6 + + + + + + &Picture + + + + 11 + + + 6 + + + + + + 7 + 7 + + + + + + + Qt::AlignCenter + + + false + + + + + + + &Clear + + + + + + + + 7 + 5 + + + + + + + + + + + + + EditFile + QWidget +
simgui/editfile.h
+ + -1 + -1 + + 0 + + 5 + 5 + + image0 +
+ + QWidget + QWidget +
QWidget
+ + -1 + -1 + + 0 + + 5 + 5 + + image1 + + text + +
+
+ + + 789c6dd2c10ac2300c00d07bbf2234b7229d1ddec44f503c0ae2a154410f53d0ed20e2bf6bdb656dd6861dd23d9a66591b0587fd1654235ebded6f0edcd53e419d87ae7b1f4f9b8f906d0bfe012317426a70b07bdc2f3ec77f8ed6b89559061a0343d06a124cc105596482585094bc0ae599b04646c9018926491b2205e140c485cace25755c175d0a967b622ff900b8cc9c7d29af594ea722d589167f813aa852ba07d94b9dce296e883fe7bb163f23896753 + + + 789c6dd2c10ac2300c00d07bbf2234b7229d1be245fc04c5a3201e4615f430059d0711ff5ddb2e6bb236ec90eed134cb5a19d8ef36602af5ecdbfeeac05dda0798d3abebde87e3faa374d3807fa0d633a52d38d8de6f679fe33fc776e196f53cd010188256a3600a292882096246517815ca99884606e18044a3a40d91824820924265a7923a2e8bcd05f33db1173e002913175f2a6be6d3294871a2d95fa00e8a94ee017b69d339d90df1e77c57ea072ede6758 + + +
diff --git a/plugins/icq/icqping.cpp b/plugins/icq/icqping.cpp new file mode 100644 index 0000000..b899d06 --- /dev/null +++ b/plugins/icq/icqping.cpp @@ -0,0 +1,40 @@ +/*************************************************************************** + icqping.cpp - description + ------------------- + begin : Sun Mar 10 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "log.h" + +#include "icqclient.h" + +using namespace SIM; + +const unsigned short ICQ_SNACxPING_ERROR = 0x0001; +const unsigned short ICQ_SNACxPING_REPORTxINTERVALL = 0x0002; +const unsigned short ICQ_SNACxPING_STATS = 0x0003; // not implemented +const unsigned short ICQ_SNACxPING_STATSxACK = 0x0004; // not implemented + +void ICQClient::snac_ping(unsigned short type, unsigned short) +{ + switch (type){ + case ICQ_SNACxPING_ERROR: + break; + case ICQ_SNACxPING_REPORTxINTERVALL: + break; + default: + log(L_WARN, "Unknown ping foodgroup type %04X", type); + } +} + diff --git a/plugins/icq/icqsearch.cpp b/plugins/icq/icqsearch.cpp new file mode 100644 index 0000000..10fafc7 --- /dev/null +++ b/plugins/icq/icqsearch.cpp @@ -0,0 +1,477 @@ +/*************************************************************************** + icqsearch.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "icons.h" +#include "icqsearch.h" +#include "icqclient.h" +#include "advsearch.h" +#include "aimsearch.h" +#include "simgui/intedit.h" +#include "log.h" +#include "contacts/contact.h" + +#include +#include +#include +#include + +using namespace std; +using namespace SIM; + +ICQSearch::ICQSearch(ICQClient *client, QWidget *parent) : QWidget(parent) +{ + setupUi(this); + m_client = client; + m_bAdv = false; + m_id_icq = 0; + m_id_aim = 0; + connect(this, SIGNAL(setAdd(bool)), topLevelWidget(), SLOT(setAdd(bool))); + connect(this, SIGNAL(addResult(QWidget*)), topLevelWidget(), SLOT(addResult(QWidget*))); + connect(this, SIGNAL(showResult(QWidget*)), topLevelWidget(), SLOT(showResult(QWidget*))); + if (client->m_bAIM){ + m_adv = new AIMSearch; + emit addResult(m_adv); + + edtAOL_UIN->setValidator(new QRegExpValidator(QRegExp("([ -]*[0-9]){4,13}[ -]*"), this)); + edtScreen->setValidator(new QRegExpValidator(QRegExp("[0-9A-Za-z]+"), this)); + connect(grpScreen, SIGNAL(toggled(bool)), this, SLOT(radioToggled(bool))); + connect(grpAOL_UIN, SIGNAL(toggled(bool)), this, SLOT(radioToggled(bool))); + grpUin->hide(); + grpAOL->hide(); + grpName->hide(); + }else{ + m_adv = new AdvSearch; + emit addResult(m_adv); + + edtUIN->setValidator(new QRegExpValidator(QRegExp("([ -]*[0-9]){4,13}[ -]*"), this)); + edtAOL->setValidator(new QRegExpValidator(QRegExp("[0-9A-Za-z]+"), this)); + connect(grpUin, SIGNAL(toggled(bool)), this, SLOT(radioToggled(bool))); + connect(grpAOL, SIGNAL(toggled(bool)), this, SLOT(radioToggled(bool))); + connect(grpName, SIGNAL(toggled(bool)), this, SLOT(radioToggled(bool))); + grpScreen->hide(); + grpAOL_UIN->hide(); + } + edtMail->setValidator(new EMailValidator(edtMail)); + connect(grpMail, SIGNAL(toggled(bool)), this, SLOT(radioToggled(bool))); + connect(btnAdvanced, SIGNAL(clicked()), this, SLOT(advClick())); + QIcon is = Icon("1rightarrow"); + btnAdvanced->setIcon(is); +} + +ICQSearch::~ICQSearch() +{ + if (m_adv) + delete m_adv; +} + +void ICQSearch::advDestroyed() +{ + m_adv = NULL; +} + +void ICQSearch::showEvent(QShowEvent *e) +{ + QWidget::showEvent(e); + emit setAdd(grpAOL->isChecked() || grpScreen->isChecked()); + if (m_adv && m_bAdv) + emit showResult(m_adv); +} + +void ICQSearch::radioToggled(bool) +{ + setAdv(false); + emit setAdd(grpAOL->isChecked() || grpScreen->isChecked()); +} + +void ICQSearch::advClick() +{ + if (!m_bAdv && (m_id_icq || m_id_aim)){ + m_id_icq = 0; + m_id_aim = 0; + emit searchDone(this); + } + setAdv(!m_bAdv); +} + +void ICQSearch::setAdv(bool bAdv) +{ + if (m_bAdv == bAdv) + return; + m_bAdv = bAdv; + QIcon is = Icon(m_bAdv ? "1leftarrow" : "1rightarrow"); + btnAdvanced->setIcon(is); + if (m_bAdv) + { + if (m_client->m_bAIM) + { + edtMail->setEnabled(false); + edtAOL_UIN->setEnabled(false); + edtScreen->setEnabled(false); + } + else + { + edtMail->setEnabled(true); + edtFirst->setEnabled(true); + edtLast->setEnabled(true); + edtNick->setEnabled(true); + lblFirst->setEnabled(true); + lblLast->setEnabled(true); + lblNick->setEnabled(true); + edtUIN->setEnabled(false); + edtAOL->setEnabled(false); + } + emit setAdd(false); + } + else + { + if (m_client->m_bAIM) + { + grpScreen->setChecked( true ); + grpAOL_UIN->setChecked( true ); + } + else + { + grpUin->setChecked( false ); + grpAOL->setChecked( false ); + grpName->setChecked( false ); + } + grpMail->setChecked( false ); + radioToggled(false); + } + emit showResult(m_bAdv ? m_adv : NULL); +} + +void ICQSearch::createContact(unsigned tmpFlags, Contact *&contact) +{ + if (m_client->m_bAIM){ + + if (grpScreen->isChecked() && !edtScreen->text().isEmpty()) + + add(edtScreen->text(), tmpFlags, contact); + + if (grpAOL_UIN->isChecked() && !edtAOL_UIN->text().isEmpty()) + + add(extractUIN(edtAOL_UIN->text()), tmpFlags, contact); + + }else{ + + if (grpAOL->isChecked() && !edtAOL->text().isEmpty()) + add(edtAOL->text(), tmpFlags, contact); + + } +} + +void ICQSearch::add(const QString &screen, unsigned tmpFlags, Contact *&contact) +{ + if (m_client->findContact(screen, NULL, false, contact)) + return; + m_client->findContact(screen, &screen, true, contact, NULL, false); + contact->setFlags(contact->getFlags() | tmpFlags); +} + +extern const ext_info *p_ages; +extern const ext_info *p_genders; +extern const ext_info *p_languages; +extern const ext_info *p_occupations; +extern const ext_info *p_interests; +extern const ext_info *p_pasts; +extern const ext_info *p_affilations; + +void ICQSearch::icq_search() +{ + m_bAdd = false; + switch (m_type){ + case UIN: + m_id_icq = m_client->findByUin(m_uin); + break; + case Mail: + m_id_icq = m_client->findByMail(m_mail); + break; + case Name: + m_id_icq = m_client->findWP(m_first, m_last, m_nick, + NULL, 0, 0, 0, NULL, NULL, 0, NULL, NULL, NULL, + 0, 0, NULL, 0, NULL, 0, NULL, 0, NULL, NULL, false); + break; + case Full: + m_id_icq = m_client->findWP(m_first, m_last, m_nick, + m_mail, m_age, m_gender, m_lang, + m_city, m_state, m_country, + m_company, m_depart, m_position, + m_occupation, m_past, m_past_text, + m_interests, m_interests_text, + m_affilations, m_affilations_text, 0, NULL, + m_keywords, m_bOnline); + break; + case None: + m_id_icq = 0; + break; + } +} + +const QString ICQSearch::extractUIN(const QString& str) +{ + if (str.isEmpty()) + return QString::null; + QString s = str; + return s.remove(' ').remove('-'); +} + +void ICQSearch::search() +{ + m_id_icq = 0; + m_id_aim = 0; + m_uins.clear(); + m_bAdd = false; + if (!m_client->m_bAIM && m_bAdv){ + m_type = Full; + setAdv(false); + AdvSearch *adv = static_cast(m_adv); + m_first = edtFirst->text(); + m_last = edtLast->text(); + m_nick = edtNick->text(); + m_mail = edtMail->text(); + m_age = getComboValue(adv->cmbAge, p_ages); + m_gender = getComboValue(adv->cmbGender, p_genders); + m_lang = getComboValue(adv->cmbLang, p_languages); + m_city = adv->edtCity->text(); + m_state = adv->edtState->text(); + m_country = getComboValue(adv->cmbCountry, getCountries(), getCountryCodes()); + m_company = adv->edtCompany->text(); + m_depart = adv->edtDepartment->text(); + m_position = adv->edtPosition->text(); + m_occupation= getComboValue(adv->cmbOccupation, p_occupations); + m_past = getComboValue(adv->cmbPast, p_pasts); + m_past_text = adv->edtPast->text(); + m_interests = getComboValue(adv->cmbInterests, p_interests); + m_interests_text = adv->edtInterests->text(); + m_affilations = getComboValue(adv->cmbAffilation, p_affilations); + m_affilations_text = adv->edtAffilation->text(); + m_keywords = adv->edtKeywords->text(); + m_bOnline = adv->chkOnline->isChecked(); + icq_search(); + }else if (m_client->m_bAIM && m_bAdv){ + setAdv(false); + AIMSearch *adv = static_cast(m_adv); + const char *country = NULL; + int nCountry = getComboValue(adv->cmbCountry, getCountries(), getCountryCodes()); + for (const ext_info *info = getCountryCodes(); info->szName; ++info){ + if (info->nCode == nCountry){ + country = info->szName; + break; + } + } + m_id_aim = m_client->aimInfoSearch( + adv->edtFirst->text(), + adv->edtLast->text(), + adv->edtMiddle->text(), + adv->edtMaiden->text(), + country, + adv->edtStreet->text(), + adv->edtCity->text(), + adv->edtNick->text(), + adv->edtZip->text(), + adv->edtState->text()); + } + else if (!m_client->m_bAIM && grpUin->isChecked() && !edtUIN->text().isEmpty()) + { + m_type = UIN; + m_uin = extractUIN(edtUIN->text()).toULong(); + icq_search(); + } + else if (grpMail->isChecked() && !edtMail->text().isEmpty()) + { + if (!m_client->m_bAIM) + { + m_type = Mail; + m_mail = edtMail->text(); + icq_search(); + } + m_id_aim = m_client->aimEMailSearch(edtMail->text()); + } + else if (!m_client->m_bAIM && grpName->isChecked() && + (!edtFirst->text().isEmpty() || !edtLast->text().isEmpty() || !edtNick->text().isEmpty())){ + m_type = Name; + m_first = edtFirst->text(); + m_last = edtLast->text(); + m_nick = edtNick->text(); + icq_search(); + m_id_aim = m_client->aimInfoSearch(edtFirst->text(), edtLast->text(), QString::null, QString::null, + QString::null, QString::null, QString::null, edtNick->text(), QString::null, QString::null); + } + if ((m_id_icq == 0) && (m_id_aim == 0)) + return; + addColumns(); +} + +void ICQSearch::addColumns() +{ + QStringList columns; + columns.append(QString::null); + columns.append(QString::null); + columns.append("nick"); + columns.append(i18n("Nick")); + columns.append("first"); + columns.append(i18n("First Name")); + columns.append("last"); + columns.append(i18n("Last Name")); + if (m_client->m_bAIM){ + columns.append("city"); + columns.append(i18n("City")); + columns.append("state"); + columns.append(i18n("State")); + columns.append("country"); + columns.append(i18n("Country")); + }else{ + columns.append("gender"); + columns.append(i18n("Gender")); + columns.append("age"); + columns.append(i18n("Age")); + columns.append("email"); + columns.append(i18n("E-Mail")); + } + emit setColumns(columns, 6, this); +} + +void ICQSearch::searchMail(const QString &mail) +{ + if (!m_client->m_bAIM){ + m_type = Mail; + m_mail = mail; + icq_search(); + } + m_id_aim = m_client->aimEMailSearch(mail); + addColumns(); +} + +void ICQSearch::searchName(const QString &first, const QString &last, const QString &nick) +{ + if (!m_client->m_bAIM){ + m_type = Name; + m_first = first; + m_last = last; + m_nick = nick; + icq_search(); + } + m_id_aim = m_client->aimInfoSearch(first, last, QString::null, QString::null, QString::null, + QString::null, QString::null, nick, QString::null, QString::null); + addColumns(); +} + +void ICQSearch::searchStop() +{ + m_id_icq = 0; + m_id_aim = 0; +} + +bool ICQSearch::processEvent(Event *e) +{ + if ((e->type() == eEventICQSearch) || (e->type() == eEventICQSearchDone)){ + EventSearchInternal *es = static_cast(e); + SearchResult *res = es->searchResult(); + if ((res->id != m_id_aim) && (res->id != m_id_icq) && (res->client != m_client)) + return false; + if (e->type() == eEventICQSearchDone){ + if (res->id == m_id_icq){ + m_id_icq = 0; + if (res->data.Uin.toULong() && m_bAdd) + icq_search(); + } + if (res->id == m_id_aim) + m_id_aim = 0; + if ((m_id_icq == 0) && (m_id_aim == 0)) + emit searchDone(this); + return false; + } + QString icon; + if (res->data.Uin.toULong()){ + icon = "ICQ_"; + switch (res->data.Status.toULong()){ + case STATUS_ONLINE: + icon += "online"; + break; + case STATUS_OFFLINE: + icon += "offline"; + break; + default: + icon += "inactive"; + } + if (m_uins.indexOf (res->data.Uin.toULong()) != -1) + return false; + m_bAdd = true; + m_uins.push_back(res->data.Uin.toULong()); + }else{ + icon = "AIM"; + } + QString gender; + switch (res->data.Gender.toULong()){ + case 1: + gender = i18n("Female"); + break; + case 2: + gender = i18n("Male"); + break; + } + QString age; + if (res->data.Age.toULong()) + age = QString::number(res->data.Age.toULong()); + QStringList l; + l.append(icon); + QString key = m_client->screen(&res->data); + if (res->data.Uin.toULong()){ + while (key.length() < 13) + key = '.' + key; + } + l.append(key); + l.append(m_client->screen(&res->data));; + if (m_client->m_bAIM){ + QString s; + l.append(res->data.Nick.str()); + l.append(res->data.FirstName.str()); + l.append(res->data.LastName.str()); + l.append(res->data.City.str()); + l.append(res->data.State.str()); + if (res->data.Country.toULong()){ + for (const ext_info *info = getCountries(); info->szName; info++){ + if (info->nCode == res->data.Country.toULong()){ + s = i18n(info->szName); + break; + } + } + } + l.append(s); + }else{ + l.append(res->data.Nick.str()); + l.append(res->data.FirstName.str()); + l.append(res->data.LastName.str()); + l.append(gender); + l.append(age); + l.append(res->data.EMail.str()); + } + emit addItem(l, this); + } + return false; +} + +void ICQSearch::createContact(const QString &name, unsigned tmpFlags, Contact *&contact) +{ + if (m_client->findContact(name, NULL, false, contact)) + return; + if (m_client->findContact(name, &name, true, contact, NULL, false) == NULL) + return; + contact->setFlags(contact->getFlags() | tmpFlags); +} + diff --git a/plugins/icq/icqsearch.h b/plugins/icq/icqsearch.h new file mode 100644 index 0000000..c020810 --- /dev/null +++ b/plugins/icq/icqsearch.h @@ -0,0 +1,104 @@ +/*************************************************************************** + icqsearch.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _ICQSEARCH_H +#define _ICQSEARCH_H + +#include "ui_icqsearchbase.h" +#include +#include +#include "event.h" + +class ICQClient; +class AdvSearch; +class AIMSearch; +class GroupRadioButton; + +class ICQSearch : public QWidget, public Ui::ICQSearchBase, public SIM::EventReceiver +{ + Q_OBJECT +public: + ICQSearch(ICQClient *client, QWidget *parent); + ~ICQSearch(); +signals: + void setAdd(bool); + void addResult(QWidget*); + void showResult(QWidget*); + void setColumns(const QStringList&, int, QWidget*); + void addItem(const QStringList&, QWidget*); + void searchDone(QWidget*); +protected slots: + void advDestroyed(); + void radioToggled(bool); + void advClick(); + void search(); + void searchStop(); + void searchMail(const QString&); + void searchName(const QString&, const QString&, const QString&); + void createContact(const QString&, unsigned tmpFlags, SIM::Contact *&contact); + void createContact(unsigned tmpFlags, SIM::Contact *&contact); +protected: + enum SearchType + { + None, + UIN, + Mail, + Name, + Full + }; + static inline const QString extractUIN(const QString& str); + virtual bool processEvent(SIM::Event *e); + void showEvent(QShowEvent*); + void setAdv(bool); + void icq_search(); + void addColumns(); + void add(const QString &screen, unsigned tmpFlags, SIM::Contact *&contact); + QList m_uins; + ICQClient *m_client; + QWidget *m_adv; + bool m_bAdv; + bool m_bAdd; + SearchType m_type; + unsigned short m_id_icq; + unsigned short m_id_aim; + unsigned long m_uin; + QString m_first; + QString m_last; + QString m_nick; + QString m_mail; + unsigned short m_age; + char m_gender; + unsigned short m_lang; + QString m_city; + QString m_state; + unsigned short m_country; + QString m_company; + QString m_depart; + QString m_position; + unsigned short m_occupation; + unsigned short m_past; + QString m_past_text; + unsigned short m_interests; + QString m_interests_text; + unsigned short m_affilations; + QString m_affilations_text; + QString m_keywords; + bool m_bOnline; +}; + +#endif + diff --git a/plugins/icq/icqsearchbase.ui b/plugins/icq/icqsearchbase.ui new file mode 100644 index 0000000..ca0f44b --- /dev/null +++ b/plugins/icq/icqsearchbase.ui @@ -0,0 +1,228 @@ + + + ICQSearchBase + + + + 0 + 0 + 227 + 606 + + + + Form1 + + + + 0 + + + + + &UIN + + + true + + + + 11 + + + + + + + + + + + &Screenname + + + true + + + false + + + + 11 + + + + + + + + + + + &E-Mail + + + true + + + false + + + + 11 + + + + + + + + + + + &Name + + + true + + + false + + + + 11 + + + + + First: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + false + + + + + + + + + + Last: + + + false + + + + + + + + + + Nick: + + + false + + + + + + + + + + + + + AOL s&creenname + + + true + + + false + + + + 11 + + + + + + + + + + + ICQ &UIN + + + true + + + false + + + + 11 + + + + + + + + + + + Advanced + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + RadioGroup + QGroupBox +
simgui/intedit.h
+ 1 +
+
+ + edtUIN + edtScreen + edtMail + edtFirst + edtLast + edtNick + edtAOL + edtAOL_UIN + btnAdvanced + + + +
diff --git a/plugins/icq/icqsecure.cpp b/plugins/icq/icqsecure.cpp new file mode 100644 index 0000000..61d5169 --- /dev/null +++ b/plugins/icq/icqsecure.cpp @@ -0,0 +1,228 @@ +/*************************************************************************** + icqsecure.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "icons.h" +#include "icqsecure.h" +#include "icqclient.h" +#include "simgui/ballonmsg.h" +#include "contacts/contact.h" + +#include +#include +#include + +using namespace SIM; + +ICQSecure::ICQSecure(QWidget *parent, ICQClient *client) : QWidget(parent) +{ + setupUi(this); + m_client = client; + connect(chkHideIP, SIGNAL(toggled(bool)), this, SLOT(hideIpToggled(bool))); + setListView(lstVisible); + setListView(lstInvisible); + fill(); + connect(lstVisible, SIGNAL(deleteItem(ListViewItem*)), this, SLOT(deleteVisibleItem(ListViewItem*))); + connect(lstInvisible, SIGNAL(deleteItem(ListViewItem*)), this, SLOT(deleteInvisibleItem(ListViewItem*))); +} + +void ICQSecure::deleteVisibleItem(ListViewItem *item) +{ + Contact *contact = getContacts()->contact(item->text(4).toUInt()); + if (contact) { + ICQUserData *data; + ClientDataIterator it(contact->clientData); + while ((data = m_client->toICQUserData(++it)) != NULL){ + data->VisibleId.asULong() = 0; + EventContact eContact(contact, EventContact::eChanged); + eContact.process(); + } + } +} + +void ICQSecure::deleteInvisibleItem(ListViewItem *item) +{ + Contact *contact = getContacts()->contact(item->text(4).toUInt()); + if (contact) { + ICQUserData *data; + ClientDataIterator it(contact->clientData); + while ((data = m_client->toICQUserData(++it)) != NULL){ + data->InvisibleId.asULong() = 0; + EventContact eContact(contact, EventContact::eChanged); + eContact.process(); + } + } +} + +void ICQSecure::apply() +{ + bool bStatusChanged = false; + if (chkHideIP->isChecked() != m_client->getHideIP()){ + bStatusChanged = true; + m_client->setHideIP(chkHideIP->isChecked()); + } + unsigned mode = 0; + if(btnDirectAllow->isChecked()) + mode = 1; + else if(btnDirectAuth->isChecked()) + mode = 2; + if (mode != m_client->getDirectMode()){ + bStatusChanged = true; + m_client->setDirectMode(mode); + } + if (bStatusChanged && (m_client->getState() == Client::Connected)) + m_client->snacService()->sendStatus(); + m_client->setIgnoreAuth(chkIgnoreAuth->isChecked()); + m_client->setUseMD5(chkUseMD5->isChecked()); +} + +void ICQSecure::apply(Client *client, void *_data) +{ + if (client != m_client) + return; + ICQUserData *data = m_client->toICQUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + data->WaitAuth.asBool() = chkAuth->isChecked(); + data->WebAware.asBool() = chkWeb->isChecked(); +} + +void ICQSecure::fill() +{ + chkAuth->setChecked(m_client->data.owner.WaitAuth.toBool()); + chkWeb->setChecked(m_client->data.owner.WebAware.toBool()); + chkHideIP->setChecked(m_client->getHideIP()); + chkIgnoreAuth->setChecked(m_client->getIgnoreAuth()); + chkUseMD5->setChecked(m_client->getUseMD5()); + + switch(m_client->getDirectMode()) + { + case 0: + btnDirectContact->setChecked(true); + break; + case 1: + btnDirectAllow->setChecked(true); + break; + case 2: + btnDirectAuth->setChecked(true); + break; + default: + break; + + } + fillListView(lstVisible, &ICQUserData::VisibleId); + fillListView(lstInvisible, &ICQUserData::InvisibleId); + hideIpToggled(m_client->getHideIP()); +} + +bool ICQSecure::processEvent(Event *e) +{ + if (e->type() == eEventClientChanged){ + EventClientChanged *ecc = static_cast(e); + if (ecc->client() == m_client) + fill(); + } else + if (e->type() == eEventContact){ + EventContact *ec = static_cast(e); + if(ec->action() != EventContact::eChanged) + return false; + fillListView(lstVisible, &ICQUserData::VisibleId); + fillListView(lstInvisible, &ICQUserData::InvisibleId); + } + return false; +} + +void ICQSecure::setListView(ListView *lst) +{ + //lst->setSorting(0); + lst->addColumn(i18n("UIN")); + lst->addColumn(i18n("Nick")); + lst->addColumn(i18n("Name")); + lst->addColumn(i18n("EMail")); + //lst->setColumnAlignment(0, Qt::AlignRight); + lst->setExpandingColumn(3); +} + +void ICQSecure::fillListView(ListView *lst, SIM::Data ICQUserData::* field) +{ + lst->clear(); + Contact *contact; + ContactList::ContactIterator it; + while ((contact = ++it) != NULL){ + ICQUserData *data; + ClientDataIterator it(contact->clientData, m_client); + while ((data = m_client->toICQUserData(++it)) != NULL){ + if ((data->*field).toULong()){ + QString firstName = contact->getFirstName(); + QString lastName = contact->getLastName(); + firstName = getToken(firstName, '/'); + lastName = getToken(lastName, '/'); + if (!lastName.isEmpty()){ + if (!firstName.isEmpty()) + firstName += ' '; + firstName += lastName; + } + QString mails; + QString emails = contact->getEMails(); + while (emails.length()){ + QString mailItem = getToken(emails, ';', false); + mailItem = getToken(mailItem, '/'); + if (!mails.isEmpty()) + mails += ", "; + mails += mailItem; + } + ListViewItem *item = new ListViewItem(lst); + item->setText(0,QString::number(data->Uin.toULong())); + item->setText(1,contact->getName()); + item->setText(2,firstName); + item->setText(3,mails); + item->setText(4,QString::number(contact->id())); + unsigned long status = STATUS_UNKNOWN; + unsigned style = 0; + QString statusIcon; + ((Client*)m_client)->contactInfo(data, status, style, statusIcon); + item->setPixmap(0, Pict(statusIcon)); + } + } + } +} + +void ICQSecure::hideIpToggled(bool bOn) +{ + if (bOn) { + btnDirectAuth->setChecked(true); + grpDirect->setEnabled(false); + } else { + switch(m_client->getDirectMode()) + { + case 0: + btnDirectContact->setChecked(true); + break; + case 1: + btnDirectAllow->setChecked(true); + break; + case 2: + btnDirectAuth->setChecked(true); + break; + default: + break; + + } + grpDirect->setEnabled(true); + } +} + + +// vim: set expandtab: + diff --git a/plugins/icq/icqsecure.h b/plugins/icq/icqsecure.h new file mode 100644 index 0000000..fbd6711 --- /dev/null +++ b/plugins/icq/icqsecure.h @@ -0,0 +1,49 @@ +/*************************************************************************** + icqsecure.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _ICQSECURE_H +#define _ICQSECURE_H + +#include "cfg.h" + +#include "simgui/listview.h" +#include "ui_icqsecurebase.h" + +class ICQClient; +struct ICQUserData; + +class ICQSecure : public QWidget, public Ui::Secure, public SIM::EventReceiver +{ + Q_OBJECT +public: + ICQSecure(QWidget *parent, ICQClient *client); +public slots: + void apply(); + void apply(SIM::Client*, void*); + void hideIpToggled(bool); + void deleteVisibleItem(ListViewItem *item); + void deleteInvisibleItem(ListViewItem *item); +protected: + virtual bool processEvent(SIM::Event *e); + void fill(); + void setListView(ListView*); + void fillListView(ListView *lst, SIM::Data ICQUserData::* field); + ICQClient *m_client; +}; + +#endif + diff --git a/plugins/icq/icqsecurebase.ui b/plugins/icq/icqsecurebase.ui new file mode 100644 index 0000000..ba534de --- /dev/null +++ b/plugins/icq/icqsecurebase.ui @@ -0,0 +1,170 @@ + + + Secure + + + + 0 + 0 + 441 + 324 + + + + Form1 + + + + 6 + + + 11 + + + + + 0 + + + + &Security + + + + 6 + + + 11 + + + + + My &authorization is required before users add me to Contact List + + + + + + + Don't show my &IP-address + + + + + + + + + + Allow other to view my &status from the Web + + + + + + + I&gnore user authorization + + + + + + + Always use &MD5 authentication + + + + + + + Direct connections + + + + + + Allow direct connection from user listed in &contact list + + + + + + + Allow &direct connection from any user + + + + + + + Allow direct connection from user &upon authorization + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + &Visible list + + + + 6 + + + 11 + + + + + + + + + &Invisible list + + + + 6 + + + 11 + + + + + + + + + + + + + ListView + QWidget +
simgui/listview.h
+
+
+ + +
diff --git a/plugins/icq/icqservice.cpp b/plugins/icq/icqservice.cpp new file mode 100644 index 0000000..0f51bad --- /dev/null +++ b/plugins/icq/icqservice.cpp @@ -0,0 +1,723 @@ +/*************************************************************************** + icqservice.cpp - description + ------------------- + begin : Sun Mar 10 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifdef WIN32 +#include +#else +#include +#include +#endif + +#include +#include +#include +#include +#include + +#include "log.h" + +#include "icqclient.h" +#include "icqservice.h" +#include "contacts/contact.h" + +using namespace std; +using namespace SIM; + +const unsigned short ICQ_SNACxSRV_ERROR = 0x0001; +const unsigned short ICQ_SNACxSRV_READYxCLIENT = 0x0002; +const unsigned short ICQ_SNACxSRV_READYxSERVER = 0x0003; +const unsigned short ICQ_SNACxSRV_SERVICExREQ = 0x0004; +const unsigned short ICQ_SNACxSRV_SERVICExRESP = 0x0005; +const unsigned short ICQ_SNACxSRV_REQxRATExINFO = 0x0006; +const unsigned short ICQ_SNACxSRV_RATExINFO = 0x0007; +const unsigned short ICQ_SNACxSRV_RATExACK = 0x0008; +const unsigned short ICQ_SNACxSRV_RATExDEL = 0x0009; /* Not implemented */ +const unsigned short ICQ_SNACxSRV_RATExCHANGE = 0x000A; +const unsigned short ICQ_SNACxSRV_PAUSE = 0x000B; +const unsigned short ICQ_SNACxSRV_PAUSExACK = 0x000C; +const unsigned short ICQ_SNACxSRV_RESUME = 0x000D; +const unsigned short ICQ_SNACxSRV_GETxUSERxINFO = 0x000E; +const unsigned short ICQ_SNACxSRV_NAMExINFO = 0x000F; +const unsigned short ICQ_SNACxSRV_EVIL = 0x0010; +const unsigned short ICQ_SNACxSRV_SETxIDLE = 0x0011; +const unsigned short ICQ_SNACxSRV_MIGRATE = 0x0012; +const unsigned short ICQ_SNACxSRV_MOTD = 0x0013; +const unsigned short ICQ_SNACxSRV_PRIVATY_FLAGS = 0x0014; /* Not implemented */ +const unsigned short ICQ_SNACxSRV_IMxICQ = 0x0017; +const unsigned short ICQ_SNACxSRV_ACKxIMxICQ = 0x0018; +const unsigned short ICQ_SNACxSRV_SETxSTATUS = 0x001E; +const unsigned short ICQ_SNACxSRV_EXT_STATUS = 0x0021; + +SnacIcqService::SnacIcqService(ICQClient* client) : SnacHandler(client, 0x0001) +{ +} + +SnacIcqService::~SnacIcqService() +{ +} + +bool SnacIcqService::process(unsigned short subtype, ICQBuffer* buf, unsigned short /*seq*/) //seq unused +{ + switch (subtype) + { + case ICQ_SNACxSRV_PAUSE: + log(L_DEBUG, "Server pause"); + m_client->m_bNoSend = true; + m_client->snac(ICQ_SNACxFOOD_SERVICE, ICQ_SNACxSRV_PAUSExACK); + m_client->socket()->writeBuffer() << ICQ_SNACxFOOD_SERVICE + << ICQ_SNACxFOOD_LOCATION + << ICQ_SNACxFOOD_BUDDY + << ICQ_SNACxFOOD_MESSAGE + << ICQ_SNACxFOOD_BOS + << ICQ_SNACxFOOD_PING + << ICQ_SNACxFOOD_LISTS + << ICQ_SNACxFOOD_VARIOUS + << ICQ_SNACxFOOD_LOGIN; + m_client->sendPacket(true); + break; + case ICQ_SNACxSRV_RESUME: + log(L_DEBUG, "Server resume"); + m_client->m_bNoSend = false; + m_client->snacICBM()->processSendQueue(); + break; + case ICQ_SNACxSRV_MIGRATE: + { + log(L_DEBUG, "Server migrate"); + m_client->m_bNoSend = true; + int i; + unsigned short cnt; + unsigned short food[0x17]; + + *buf >> cnt; + for(i = 0; i < cnt; i++) + { + *buf >> food[i]; + } + TlvList tlv(*buf); + Tlv *tlv_adr = tlv(0x05); + Tlv *tlv_cookie = tlv(0x06); + for(; i >= 0; i--) + { + + setServiceSocket(tlv_adr,tlv_cookie,food[i]); + } + break; + } + case ICQ_SNACxSRV_RATExCHANGE: + { + const char *msg_text = NULL; + unsigned short msg_code; + unsigned short class_id; + unsigned long window_size; + unsigned long clear_level; + unsigned long alert_level; + unsigned long limit_level; + unsigned long discon_level; + unsigned long current_level; + unsigned long max_level; + unsigned long last_send; + char current_state; + *buf >> msg_code + >> class_id + >> window_size + >> clear_level + >> alert_level + >> limit_level + >> discon_level + >> current_level + >> max_level + >> last_send + >> current_state; + if(subtype == ICQ_SNACxSRV_RATExCHANGE) + { + switch (msg_code) + { + case 0x0001: + msg_text = "Rate limits parameters changed"; + break; + case 0x0002: + msg_text = "Rate limits warning"; + break; + case 0x0003: + msg_text = "Rate limit hit"; + break; + case 0x0004: + msg_text = "Rate limit clear"; + break; + default: + msg_text = "Unknown"; + } + log(L_DEBUG, "%s", msg_text); + } + log(L_DEBUG, "grp: %02X, ws: %04lX, cl %04lX, al %04lX, ll %04lX, dl: %04lX, cur %04lX, ml %04lX", + class_id,window_size,clear_level,alert_level,limit_level,discon_level, + current_level,max_level); + if (--class_id < m_client->m_rates.size()){ + RateInfo &r = m_client->m_rates[class_id]; + r.m_winSize = window_size; + r.m_maxLevel = max_level; + r.m_minLevel = alert_level; + r.m_curLevel = current_level; + r.m_lastSend = QDateTime::currentDateTime(); + m_client->snacICBM()->processSendQueue(); + } + break; + } + case ICQ_SNACxSRV_RATExINFO: + { + bool bNew = m_client->m_rates.size() == 0; + m_client->m_rates.clear(); + unsigned short n_rates; + *buf >> n_rates; + unsigned n; + for(n = 0; n < n_rates; n++) + { + unsigned short class_id; + unsigned long window_size; + unsigned long clear_level; + unsigned long alert_level; + unsigned long limit_level; + unsigned long discon_level; + unsigned long current_level; + unsigned long max_level; + unsigned long last_send; + char current_state; + *buf >> class_id + >> window_size + >> clear_level + >> alert_level + >> limit_level + >> discon_level + >> current_level + >> max_level + >> last_send + >> current_state; + log(L_DEBUG, "grp: %02X, ws: %04lX, cl %04lX, al %04lX, ll %04lX, dl: %04lX, cur %04lX, ml %04lX, cs: %d", + class_id,window_size,clear_level,alert_level,limit_level,discon_level, + current_level,max_level, current_state); + RateInfo r; + r.m_winSize = window_size; + r.m_minLevel = alert_level; + r.m_maxLevel = max_level; + r.m_curLevel = current_level; + r.m_lastSend = QDateTime::currentDateTime(); + m_client->m_rates.push_back(r); + } + for(n = 0; n < n_rates; n++) + { + unsigned short class_id; + unsigned short pairs; + *buf >> class_id + >> pairs; + class_id--; + for(unsigned i = 0; i < pairs; i++) + { + unsigned long snac; + *buf >> snac; + if(class_id >= m_client->m_rates.size()) + continue; + RATE_MAP::iterator it = m_client->m_rate_grp.find(snac); + if (it != m_client->m_rate_grp.end()) + continue; + m_client->m_rate_grp.insert(RATE_MAP::value_type(snac, class_id)); + } + } + m_client->snac(ICQ_SNACxFOOD_SERVICE, ICQ_SNACxSRV_RATExACK); + m_client->socket()->writeBuffer() << 0x00010002L << 0x00030004L << 0x0005; + m_client->sendPacket(true); + if(!bNew) + break; + m_client->snac(ICQ_SNACxFOOD_SERVICE, ICQ_SNACxSRV_GETxUSERxINFO); + m_client->sendPacket(true); + m_client->listsRequest(); + m_client->locationRequest(); + log(L_DEBUG, "alpha"); + m_client->buddyRequest(); + log(L_DEBUG, "beta"); + m_client->snacICBM()->rightsRequest(); + log(L_DEBUG, "gamma"); + m_client->bosRequest(); + log(L_DEBUG, "delta"); + } + break; + case ICQ_SNACxSRV_MOTD: + break; + case ICQ_SNACxSRV_ACKxIMxICQ: + requestRateInfo(); + break; + case ICQ_SNACxSRV_EXT_STATUS: + { + QByteArray shash; + unsigned short nType; + char flags, size; + + *buf >> nType; + if(nType == 0) // SSBI ready + break; + if(nType == 2) // iChat message + break; + + *buf >> flags >> size; + shash.resize(size); + buf->unpack(shash.data(), shash.size()); + + QImage img(m_client->getPicture()); + if(img.isNull()) + break; + + QByteArray ba; + QBuffer l_buf(&ba); + if(!l_buf.open(QIODevice::WriteOnly)) + { + log(L_ERROR, "Can't open QByteArray for writing!"); + break; + } + if(!img.save(&l_buf, "JPEG")) { + log(L_ERROR, "Can't save QImage to QBuffer"); + break; + } + l_buf.close(); + QByteArray hash = QCryptographicHash::hash(ba.data(), QCryptographicHash::Md5); + + if(hash != shash) { + log(L_WARN, "The buddyIcon on server does not match the local one - updating"); + m_client->uploadBuddy(&m_client->data.owner); + break; + } + log(L_DEBUG, "SRV_EXT_STATUS"); + if(flags & FirstSend) + { + m_client->uploadBuddyIcon(1, img); + } + else + { + ICQUserData* data = &m_client->data.owner; + data->buddyHash.setBinary(hash); + /* + m_client->sendCapability(QString::null); + m_client->requestBuddy(data); + */ + } + + } + break; + case ICQ_SNACxSRV_NAMExINFO: + { + QString screen = buf->unpackScreen(); + if(screen.length() == 0){ + char n; + *buf >> n; + buf->incReadPos(n); + screen = buf->unpackScreen(); + } + if (screen.toULong() != m_client->data.owner.Uin.toULong()){ + log(L_WARN, "Not my name info (%s)", qPrintable(screen)); + break; + } + buf->incReadPos(4); + TlvList tlv(*buf); + Tlv *tlvIP = tlv(0x000A); + if (tlvIP) + set_ip(&m_client->data.owner.IP, htonl((uint32_t)(*tlvIP))); + break; + } + case ICQ_SNACxSRV_SERVICExRESP: + { + TlvList tlv(*buf); + Tlv *tlv_id = tlv(0x0D); + if (!tlv_id){ + log(L_WARN, "No service id in response"); + break; + } + Tlv *tlv_adr = tlv(0x05); + Tlv *tlv_cookie = tlv(0x06); + setServiceSocket(tlv_adr,tlv_cookie,(uint16_t)(*tlv_id)); + break; + } + case ICQ_SNACxSRV_READYxSERVER: + m_client->snac(ICQ_SNACxFOOD_SERVICE, ICQ_SNACxSRV_IMxICQ); + if (m_client->m_bAIM){ + m_client->socket()->writeBuffer() + << 0x00010003L + << 0x00130003L + << 0x00020001L + << 0x00030001L + << 0x00040001L + << 0x00060001L + << 0x00080001L + << 0x00090001L + << 0x000A0001L + << 0x000B0001L; + }else{ + m_client->socket()->writeBuffer() + << 0x00010004L + << 0x00130004L + << 0x00020001L + << 0x00030001L + << 0x00150001L + << 0x00040001L + << 0x00060001L + << 0x00090001L + << 0x000A0001L + << 0x000B0001L; + } + m_client->sendPacket(true); + break; + case ICQ_SNACxSRV_ERROR: + break; + case ICQ_SNACxSRV_EVIL: + { + unsigned short level; + buf->unpack(level); + QString from = buf->unpackScreen(); + m_client->data.owner.WarningLevel.asULong() = level; + if (from.isEmpty()) + from = i18n("anonymous"); + EventNotification::ClientNotificationData d; + d.client = m_client; + d.code = 0; + d.text = I18N_NOOP("You've been warned by %1"); + d.args = from; + d.flags = EventNotification::ClientNotificationData::E_INFO; + d.options = QString::null; + d.id = CmdShowWarning; + EventClientNotification e(d); + e.process(); + break; + } + default: + log(L_WARN, "Unknown service foodgroup type %04X", subtype); + } + return true; +} + +void SnacIcqService::requestRateInfo() +{ + m_client->snac(ICQ_SNACxFOOD_SERVICE, ICQ_SNACxSRV_REQxRATExINFO); + m_client->sendPacket(true); +} + +void SnacIcqService::addService(ServiceSocket* s) +{ + m_services.push_back(s); +} + +void SnacIcqService::deleteService(ServiceSocket* s) +{ + for(std::list::iterator it = m_services.begin(); it != m_services.end(); ++it) + { + if((*it) == s) + { + m_services.erase(it); + break; + } + } +} + +ServiceSocket* SnacIcqService::getService(unsigned short id) +{ + for(std::list::iterator it = m_services.begin(); it != m_services.end(); ++it) + { + if((*it)->id() == id) + { + return (*it); + } + } + log(L_WARN, "Service not found"); + return NULL; +} + +void SnacIcqService::clearServices() +{ + while(!m_services.empty()) + { + ServiceSocket *s = m_services.front(); + delete s; + } +} + +void SnacIcqService::setServiceSocket(Tlv *tlv_addr, Tlv *tlv_cookie, unsigned short service) +{ + ServiceSocket *s = getService(service); + if(!s) + { + return; + } + if (!tlv_addr){ + s->error_state("No address for service", 0); + return; + } + if (!tlv_cookie){ + s->error_state("No cookie for service", 0); + return; + } + unsigned short port = m_client->getPort(); + QByteArray addr(tlv_addr->byteArray()); + int idx = addr.indexOf(':'); + if(idx != -1) { + port = addr.mid(idx + 1).toUShort(); + addr = addr.left(idx); + } + if (s->connected()) + s->close(); + QByteArray ba = tlv_cookie->byteArray(); + ba.resize(ba.size()-1); + s->connect(addr, port, ba); +} + +void SnacIcqService::sendClientReady() +{ + snac(ICQ_SNACxSRV_READYxCLIENT); + m_client->socket()->writeBuffer() + << 0x00010004L << 0x0110164FL + << 0x00130004L << 0x0110164FL + << 0x00020001L << 0x0110164FL + << 0x00030001L << 0x0110164FL + << 0x00150001L << 0x0110164FL + << 0x00040001L << 0x0110164FL + << 0x00060001L << 0x0110164FL + << 0x00090001L << 0x0110164FL + << 0x000A0001L << 0x0110164FL + << 0x000B0001L << 0x0110164FL; + + m_client->sendPacket(true); +} + +void SnacIcqService::sendLogonStatus() +{ + if (m_client->getInvisible()) + m_client->sendInvisible(false); + m_client->sendContactList(); + + QDateTime now(QDateTime::currentDateTime()); + if (m_client->data.owner.PluginInfoTime.toULong() == 0) + m_client->data.owner.PluginInfoTime.asULong() = now.toTime_t(); + if (m_client->data.owner.PluginStatusTime.toULong() == 0) + m_client->data.owner.PluginStatusTime.asULong() = now.toTime_t(); + if (m_client->data.owner.InfoUpdateTime.toULong() == 0) + m_client->data.owner.InfoUpdateTime.asULong() = now.toTime_t(); + m_client->data.owner.OnlineTime.asULong() = now.toTime_t(); + if (getContacts()->owner()->getPhones() != m_client->data.owner.PhoneBook.str()) + { + m_client->data.owner.PhoneBook.str() = getContacts()->owner()->getPhones(); + m_client->data.owner.PluginInfoTime.asULong() = now.toTime_t(); + } + if (m_client->getPicture() != m_client->data.owner.Picture.str()){ + m_client->data.owner.Picture.str() = m_client->getPicture(); + m_client->data.owner.PluginInfoTime.asULong() = now.toTime_t(); + } + if (getContacts()->owner()->getPhoneStatus() != (int)m_client->data.owner.FollowMe.toULong()){ + m_client->data.owner.FollowMe.asULong() = getContacts()->owner()->getPhoneStatus(); + m_client->data.owner.PluginStatusTime.asULong() = now.toTime_t(); + } + + ICQBuffer directInfo(25); + fillDirectInfo(directInfo); + + snac(ICQ_SNACxSRV_SETxSTATUS); + m_client->socket()->writeBuffer().tlv(0x0006, m_client->getFullStatus()); + m_client->socket()->writeBuffer().tlv(0x0008, (unsigned short)0x0a06); + m_client->socket()->writeBuffer().tlv(0x000C, directInfo); + Buffer b; + b << (unsigned short)0x000e + << (unsigned short)0x0000 + << (unsigned short)0x0002 + << (unsigned short)0x0000; + + m_client->socket()->writeBuffer().tlv(0x001d, b); + m_client->socket()->writeBuffer().tlv(0x001f, (unsigned short)0); + m_client->sendPacket(true); + if (!m_client->getInvisible()) + m_client->sendInvisible(true); + sendIdleTime(); + m_client->m_status = m_client->m_logonStatus; +} + +void SnacIcqService::setInvisible() +{ + log(L_DEBUG, "SnacIcqService::setInvisible"); + if(m_client->getInvisible()) + m_client->sendInvisible(false); + snac(ICQ_SNACxSRV_SETxSTATUS); + m_client->socket()->writeBuffer().tlv(0x0006, m_client->getFullStatus()); + m_client->sendPacket(true); + if (!m_client->getInvisible()) + m_client->sendInvisible(true); +} + +void SnacIcqService::sendStatus(unsigned long statuscode) +{ + snac(ICQ_SNACxSRV_SETxSTATUS); + m_client->socket()->writeBuffer().tlv(0x0006, statuscode); + m_client->sendPacket(true); + sendIdleTime(); +} + +void SnacIcqService::sendStatus() +{ + log(L_DEBUG, "SnacIcqService::sendStatus"); + snac(ICQ_SNACxSRV_SETxSTATUS); + m_client->socket()->writeBuffer().tlv(0x0006, m_client->getFullStatus()); + m_client->sendPacket(true); + sendIdleTime(); +} + +void SnacIcqService::sendPluginInfoUpdate(unsigned plugin_id) +{ + log(L_DEBUG, "SnacIcqService::sendPluginInfoUpdate"); + snac(ICQ_SNACxSRV_SETxSTATUS); + m_client->socket()->writeBuffer().tlv(0x0006, m_client->getFullStatus()); + ICQBuffer directInfo(25); + fillDirectInfo(directInfo); + m_client->socket()->writeBuffer().tlv(0x000C, directInfo); + ICQBuffer b; + b << (char)2; + b.pack(m_client->data.owner.PluginInfoTime.toULong()); + b.pack((unsigned short)2); + b.pack((unsigned short)1); + b.pack((unsigned short)2); + b.pack((char*)m_client->plugins[plugin_id], sizeof(plugin)); + b.pack(m_client->data.owner.PluginInfoTime.toULong()); + b << (char)0; + m_client->socket()->writeBuffer().tlv(0x0011, b); + m_client->socket()->writeBuffer().tlv(0x0012, (unsigned short)0); + m_client->sendPacket(false); +} + +void SnacIcqService::sendPluginStatusUpdate(unsigned plugin_id, unsigned long status) +{ + log(L_DEBUG, "SnacIcqService::sendPluginInfoUpdate"); + snac(ICQ_SNACxSRV_SETxSTATUS); + m_client->socket()->writeBuffer().tlv(0x0006, m_client->fullStatus(m_client->m_logonStatus)); + ICQBuffer directInfo(25); + fillDirectInfo(directInfo); + m_client->socket()->writeBuffer().tlv(0x000C, directInfo); + ICQBuffer b; + b << (char)3; + b.pack(m_client->data.owner.PluginStatusTime.toULong()); + b.pack((unsigned short)0); + b.pack((unsigned short)1); + b.pack((unsigned short)1); + b.pack((char*)m_client->plugins[plugin_id], sizeof(plugin)); + b << (char)1; + b.pack(status); + b.pack(m_client->data.owner.PluginStatusTime.toULong()); + b.pack((unsigned short)0); + b.pack((unsigned short)0); + b.pack((unsigned short)1); + m_client->socket()->writeBuffer().tlv(0x0011, b); + m_client->socket()->writeBuffer().tlv(0x0012, (unsigned short)0); + m_client->sendPacket(false); +} + +void SnacIcqService::sendUpdate() +{ + if (m_nUpdates == 0) + return; + if (--m_nUpdates) + return; + m_client->data.owner.InfoUpdateTime.asULong() = QDateTime::currentDateTime().toTime_t(); + snac(ICQ_SNACxSRV_SETxSTATUS); + m_client->socket()->writeBuffer().tlv(0x0006, m_client->getFullStatus()); + ICQBuffer directInfo(25); + fillDirectInfo(directInfo); + m_client->socket()->writeBuffer().tlv(0x000C, directInfo); + m_client->sendPacket(false); +} + +void SnacIcqService::fillDirectInfo(ICQBuffer &directInfo) +{ + set_ip(&m_client->data.owner.RealIP, m_client->socket()->localHost()); + /* + if (m_client->getHideIP()){ + directInfo + << (unsigned long)0 + << (unsigned long)0; + }else{ + directInfo + << (unsigned long)htonl(get_ip(m_client->data.owner.RealIP)) + << (unsigned short)0 + << (unsigned short)m_client->data.owner.Port.toULong(); + } + + char mode = DIRECT_MODE_DIRECT; + unsigned long ip1 = get_ip(m_client->data.owner.IP); + unsigned long ip2 = get_ip(m_client->data.owner.RealIP); + if (ip1 && ip2 && (ip1 != ip2)) + mode = DIRECT_MODE_INDIRECT; + switch (m_client->socket()->socket()->mode()){ + case Socket::Indirect: + mode = DIRECT_MODE_INDIRECT; + break; + case Socket::Web: + mode = DIRECT_MODE_DENIED; + break; + default: + break; + } + */ + directInfo + << (unsigned long)0 + << (unsigned long)0 + << (char)0x00//mode + << (char)0x00 + << (char)ICQ_TCP_VERSION + << m_client->data.owner.DCcookie.toULong() + << 0x00000000L + << 0x00000000L + << 0x00000000L + << 0x00000000L + << 0x00000000L + << (unsigned short)0x0000; + + /* + directInfo + << 0x00000050L + << 0x00000003L + << m_client->data.owner.InfoUpdateTime.toULong() + << m_client->data.owner.PluginInfoTime.toULong() + << m_client->data.owner.PluginStatusTime.toULong() + << (unsigned short) 0x0000; + */ +} + +void SnacIcqService::sendIdleTime() +{ + // avoid traffic + if(!m_idleTime && m_client->getIdleTime() == 0) + return; + snac(ICQ_SNACxSRV_SETxIDLE); + if(m_client->getIdleTime()) { + unsigned long idle = QDateTime::currentDateTime().toTime_t() - m_client->getIdleTime(); + if (idle <= 0) + idle = 1; + m_client->socket()->writeBuffer() << idle; + m_idleTime = true; + } else { + m_client->socket()->writeBuffer() << (unsigned long)0; + m_idleTime = false; + } + m_client->sendPacket(false); +} + +void SnacIcqService::requestService(ServiceSocket *s) +{ + snac(ICQ_SNACxSRV_SERVICExREQ, true); + m_client->socket()->writeBuffer() << s->id(); + m_client->sendPacket(true); +} + diff --git a/plugins/icq/icqservice.h b/plugins/icq/icqservice.h new file mode 100644 index 0000000..704a811 --- /dev/null +++ b/plugins/icq/icqservice.h @@ -0,0 +1,47 @@ + +#ifndef _ICQSERVICE_H +#define _ICQSERVICE_H + +#include + +#include "snac.h" + +class ServiceSocket; +class Tlv; +class SnacIcqService : public SnacHandler +{ +public: + SnacIcqService(ICQClient* client); + virtual ~SnacIcqService(); + + virtual bool process(unsigned short subtype, ICQBuffer* buf, unsigned short seq); + void requestRateInfo(); + + void addService(ServiceSocket* s); + void deleteService(ServiceSocket* s); + ServiceSocket* getService(unsigned short id); + void clearServices(); + void setServiceSocket(Tlv *tlv_addr, Tlv *tlv_cookie, unsigned short service); + void sendClientReady(); + void sendLogonStatus(); + void setInvisible(); + void sendStatus(unsigned long statuscode); + void sendStatus(); + void sendUpdate(); + void sendPluginInfoUpdate(unsigned plugin_id); + void sendPluginStatusUpdate(unsigned plugin_id, unsigned long status); + void sendIdleTime(); + void requestService(ServiceSocket *s); + static const unsigned int FirstSend = 0x40; + +protected: + void fillDirectInfo(ICQBuffer &directInfo); + +private: + bool m_idleTime; + + std::list m_services; + unsigned int m_nUpdates; +}; + +#endif diff --git a/plugins/icq/icqssbi.cpp b/plugins/icq/icqssbi.cpp new file mode 100644 index 0000000..e00090f --- /dev/null +++ b/plugins/icq/icqssbi.cpp @@ -0,0 +1,358 @@ +/*************************************************************************** + icqssbi.cpp - description + ------------------- + begin : Sun Oct 17 2006 + copyright : (C) 2006 by Christian Ehrlicher + email : ch.ehrlicher@gmx.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include +#include + +#include "log.h" + +#include "icqclient.h" +#include "icqssbi.h" + +using namespace std; +using namespace SIM; + +const unsigned short ICQ_SNACxSSBI_ERROR = 0x0001; +const unsigned short ICQ_SNACxSSBI_UPLOAD = 0x0002; // cli -> srv +const unsigned short ICQ_SNACxSSBI_UPLOAD_ACK = 0x0003; // src -> cli +const unsigned short ICQ_SNACxSSBI_REQ_AIM = 0x0004; // cli -> srv +const unsigned short ICQ_SNACxSSBI_REQ_AIM_ACK = 0x0005; // src -> cli +const unsigned short ICQ_SNACxSSBI_REQ_ICQ = 0x0006; // cli -> srv +const unsigned short ICQ_SNACxSSBI_REQ_ICQ_ACK = 0x0007; // src -> cli + +SSBISocket *ICQClient::getSSBISocket() +{ + SSBISocket *s = static_cast(m_snacService->getService(ICQ_SNACxFOOD_SSBI)); + if (s == NULL){ + s = new SSBISocket(this); + snacService()->requestService(s); + } + return s; +} + +void ICQClient::requestBuddy(const ICQUserData *data) +{ + if(!data->buddyHash.toBinary().size()) + return; + SSBISocket *s = getSSBISocket(); + s->requestBuddy(screen(data), data->buddyID.toULong(), data->buddyHash.toBinary()); +} + +void ICQClient::uploadBuddyIcon(unsigned short refNumber, const QImage &img) +{ + SSBISocket *s = getSSBISocket(); + s->uploadBuddyIcon(refNumber, img); +} + +SSBISocket::SSBISocket(ICQClient *client) + : ServiceSocket(client, ICQ_SNACxFOOD_SSBI), m_refNumber(0), m_retryCount(3) +{} + +SSBISocket::~SSBISocket() +{} + +bool SSBISocket::error_state(const QString &err, unsigned code) +{ + bool bRet = ServiceSocket::error_state(err, code); + if(m_retryCount && (!m_img.isNull() || m_buddyRequests.count())) { + m_retryCount--; + QTimer::singleShot(5000, this, SLOT(requestService())); + return false; + } + return bRet; +} + +void SSBISocket::data(unsigned short food, unsigned short type, unsigned short seq) +{ + switch(food) { + case ICQ_SNACxFOOD_SERVICE: + snac_service(type, seq); + break; + case ICQ_SNACxFOOD_SSBI: + snac_ssbi(type, seq); + break; + default: + log(L_WARN, "Unknown foodgroup %d in SSBISocket", food); + break; + } +} + +// from icqservice.cpp +const unsigned short ICQ_SNACxSRV_READYxCLIENT = 0x0002; +const unsigned short ICQ_SNACxSRV_READYxSERVER = 0x0003; +const unsigned short ICQ_SNACxSRV_REQxRATExINFO = 0x0006; +const unsigned short ICQ_SNACxSRV_RATExINFO = 0x0007; +const unsigned short ICQ_SNACxSRV_RATExACK = 0x0008; +const unsigned short ICQ_SNACxSRV_IMxICQ = 0x0017; +const unsigned short ICQ_SNACxSRV_ACKxIMxICQ = 0x0018; + +void SSBISocket::snac_service(unsigned short type, unsigned short) +{ + switch(type) { + case ICQ_SNACxSRV_READYxSERVER: + snac(ICQ_SNACxFOOD_SERVICE, ICQ_SNACxSRV_IMxICQ); + socket()->writeBuffer() << 0x00010004L << 0x00100001L; + sendPacket(); + break; + case ICQ_SNACxSRV_ACKxIMxICQ: + snac(ICQ_SNACxFOOD_SERVICE, ICQ_SNACxSRV_REQxRATExINFO); + sendPacket(); + break; + case ICQ_SNACxSRV_RATExINFO: + snac(ICQ_SNACxFOOD_SERVICE, ICQ_SNACxSRV_RATExACK); + socket()->writeBuffer() << 0x00010002L << 0x00030004L << 0x0005; + sendPacket(); + snac(ICQ_SNACxFOOD_SERVICE, ICQ_SNACxSRV_READYxCLIENT); + socket()->writeBuffer() << 0x00010004L << 0x0010157fL << 0x00100001L << 0x0010157fL; + sendPacket(); + m_bConnected = true; + process(); + break; + default: + log(L_DEBUG, "Unknown service type %u", type); + break; + } +} + +void SSBISocket::snac_ssbi(unsigned short type, unsigned short seq) +{ + switch (type){ + case ICQ_SNACxSSBI_ERROR:{ + unsigned short error_code; + socket()->readBuffer() >> error_code; + log(L_WARN, "SSBI error (%04X,%04X)", seq, error_code); + break; + } + case ICQ_SNACxSSBI_UPLOAD_ACK: { + unsigned short unknown1, unknown2; + char size; + QByteArray ba; + + socket()->readBuffer() >> unknown1 >> unknown2; + socket()->readBuffer() >> size; + ba.resize(size); + socket()->readBuffer().unpack(ba.data(), size); + break; + } + case ICQ_SNACxSSBI_REQ_AIM_ACK: { + ICQUserData *data; + Contact *contact; + QString screen; + QByteArray hash, icon; + //uint16_t iconID, + uint16_t iconSize; + uint8_t unknown_byte; + //char iconFlags; + char hashSize; + + screen = socket()->readBuffer().unpackScreen(); + if(m_client->screen(&m_client->data.owner) == screen) + data = &m_client->data.owner; + else + data = m_client->findContact(screen, NULL, false, contact); + if(data) + { + // 3 unknown bytes + socket()->readBuffer() >> unknown_byte; + socket()->readBuffer() >> unknown_byte; + socket()->readBuffer() >> unknown_byte; + // then hash (should be 5 bytes) + socket()->readBuffer() >> hashSize; + hash.resize(hashSize); + socket()->readBuffer().unpack(hash.data(), hashSize); + socket()->readBuffer() >> iconSize; + // then icon size and the icon itself + icon.resize(iconSize); + if(iconSize == 0) + { + log(L_DEBUG, "Empty icon"); + process(); + break; + } + socket()->readBuffer().unpack(icon.data(), iconSize); + + QString filename = ICQClient::pictureFile(data); + QFile f(filename); + if(f.open(QIODevice::WriteOnly)) + f.write(icon); + else + log(L_WARN, QString("Can't open %1").arg(filename)); + f.close(); + } + //process(); + break; + } + case ICQ_SNACxSSBI_REQ_ICQ_ACK: { + ICQUserData *data; + Contact *contact; + QString screen; + QByteArray hash, icon; + //uint16_t iconID; + uint16_t iconSize; + uint8_t unknown_byte; + //char iconFlags; + char hashSize; + //char unknown1; + + screen = socket()->readBuffer().unpackScreen(); + if(m_client->screen(&m_client->data.owner) == screen) + data = &m_client->data.owner; + else + data = m_client->findContact(screen, NULL, false, contact); + if(data) { + // 3 unknown bytes + socket()->readBuffer() >> unknown_byte; + socket()->readBuffer() >> unknown_byte; + socket()->readBuffer() >> unknown_byte; + // then hash (should be 5 bytes) + socket()->readBuffer() >> hashSize; + hash.resize(hashSize); + socket()->readBuffer().unpack(hash.data(), hashSize); + socket()->readBuffer() >> iconSize; + // then icon size and the icon itself + icon.resize(iconSize); + if(iconSize == 0) + { + log(L_DEBUG, "Empty icon"); + process(); + break; + } + socket()->readBuffer().unpack(icon.data(), iconSize); + + QString filename = ICQClient::pictureFile(data); + QFile f(filename); + if(f.open(QIODevice::WriteOnly)) + f.write(icon); + else + log(L_WARN, QString("Can't open %1").arg(filename)); + f.close(); + } + process(); + break; + } + default: + log(L_WARN, "Unknown SSBI foodgroup type %04X", type); + break; + } +} + +void SSBISocket::process() +{ + if(!m_img.isNull()) { + //unsigned short ref = m_refNumber; //ref unused + QImage img = m_img; + m_refNumber = 0; + m_img = QImage(); + //uploadBuddyIcon(ref, img); + } + while(m_buddyRequests.count()) { + // implement me: we can also request more than one buddy at a time ! + ICQUserData *data; + Contact *contact; + QString screen = m_buddyRequests[0]; + m_buddyRequests.pop_front(); + if(m_client->screen(&m_client->data.owner) == screen) + data = &m_client->data.owner; + else + data = m_client->findContact(screen, NULL, false, contact); + if(data) { + requestBuddy(screen, data->buddyID.toULong(), data->buddyHash.toBinary()); + return; + } + } +} + +void SSBISocket::uploadBuddyIcon(unsigned short refNumber, const QImage &img) +{ + if(img.isNull()) { + log(L_ERROR, "Uploaded Buddy icon is empty!"); + return; + } + + if(!m_img.isNull()) { + log(L_WARN, "Already in upload mode"); + return; + } + + if(!connected()) { + // wait + m_img = img; + m_refNumber = refNumber; + return; + } + + QByteArray ba; + QBuffer buf(&ba); + unsigned short len; + if(!buf.open(QIODevice::WriteOnly)) + { + log(L_ERROR, "Can't open QByteArray for writing!"); + return; + } + if(!img.save(&buf, "JPEG")) + { + log(L_ERROR, "Can't save QImage to QBuffer"); + return; + } + buf.close(); + + len = ba.size(); + if(ba.size() > 0xffff) { + log(L_ERROR, "Image is to big (max: %d bytes)", 0xffff); + len = 0xffff; + } + + snac(ICQ_SNACxFOOD_SSBI, ICQ_SNACxSSBI_UPLOAD, true); + socket()->writeBuffer() << refNumber; + socket()->writeBuffer() << len; + socket()->writeBuffer().pack(ba.data(), len); + + sendPacket(true); +} + +void SSBISocket::requestBuddy(const QString &screen, unsigned short buddyID, const QByteArray &buddyHash) +{ + log(L_DEBUG, "SSBISocket::requestBuddy: %s", qPrintable(screen)); + if(!((buddyHash.size() == 0x05) || (buddyHash.size() == 0x10))) { + log(L_WARN, "Invalid buddyHash size (%d, id: %d) for %s", buddyHash.size(), buddyID, qPrintable(screen)); + return; + } + // buddyID == 1 -> jpeg + // buddyID == 8 -> xml/swf + if(!connected()) { + // wait + if(!m_buddyRequests.contains(screen)) + m_buddyRequests.append(screen); + return; + } + + char len = buddyHash.size(); + //snac(ICQ_SNACxFOOD_SSBI, m_client->m_bAIM ? ICQ_SNACxSSBI_REQ_AIM : ICQ_SNACxSSBI_REQ_ICQ, true); + snac(ICQ_SNACxFOOD_SSBI, ICQ_SNACxSSBI_REQ_AIM, true); + + socket()->writeBuffer().packScreen(screen); + socket()->writeBuffer() << (char)0x01 + << (char)0x00//(unsigned short)buddyID + << (char)0x01 + << (char)0x00; + socket()->writeBuffer().pack(&len, 1); + socket()->writeBuffer().pack(buddyHash.data(), len); + sendPacket(); +} + diff --git a/plugins/icq/icqssbi.h b/plugins/icq/icqssbi.h new file mode 100644 index 0000000..0795827 --- /dev/null +++ b/plugins/icq/icqssbi.h @@ -0,0 +1,32 @@ +#ifndef ICQSSBI_H +#define ICQSSBI_H + +#include +#include +#include "icqclient.h" + +class SSBISocket : public QObject, public ServiceSocket +{ + Q_OBJECT +public: + SSBISocket(ICQClient *client); + ~SSBISocket(); + void requestBuddy(const QString &screen, unsigned short buddyID, const QByteArray &buddyHash); + void uploadBuddyIcon(unsigned short refNumber, const QImage &img); +protected: + virtual bool error_state(const QString &err, unsigned code); + virtual const char *serviceSocketName() { return "SSBISocket"; } + virtual void data(unsigned short food, unsigned short type, unsigned short seq); + void snac_service(unsigned short type, unsigned short seq); + void snac_ssbi(unsigned short type, unsigned short seq); + void process(); + + QStringList m_buddyRequests; + QImage m_img; // image to upload + unsigned short m_refNumber; // the ref number for the image + unsigned m_retryCount; +protected slots: + void requestService() { m_client->snacService()->requestService(this); } +}; + +#endif // ICQSSBI_H diff --git a/plugins/icq/icqstatus.cpp b/plugins/icq/icqstatus.cpp new file mode 100644 index 0000000..7f3cc13 --- /dev/null +++ b/plugins/icq/icqstatus.cpp @@ -0,0 +1,63 @@ + +#include "icqstatus.h" + +ICQStatus::ICQStatus(const QString& id, const QString& name, bool hasText, const QString& defaultText, const QIcon& icon) : IMStatus(), + m_id(id), + m_name(name), + m_hasText(hasText), + m_text(defaultText), + m_icon(icon) +{ +} + +ICQStatus::~ICQStatus() +{ +} + +QString ICQStatus::id() const +{ + return m_id; +} + +QString ICQStatus::name() const +{ + return m_name; +} + +void ICQStatus::setText(const QString& t) +{ + m_text = t; +} + +QString ICQStatus::text() const +{ + return m_text; +} + +QIcon ICQStatus::icon() const +{ + return m_icon; +} + +QStringList ICQStatus::substatuses() +{ + return QStringList(); +} + +SIM::IMStatusPtr ICQStatus::substatus(const QString& id) +{ + return SIM::IMStatusPtr(); +} + +SIM::IMStatusPtr ICQStatus::clone() +{ + return SIM::IMStatusPtr(new ICQStatus(m_id, m_name, m_hasText, m_text, m_icon)); +} + +bool ICQStatus::hasText() const +{ + return m_hasText; +} + +// vim: set expandtab: + diff --git a/plugins/icq/icqstatus.h b/plugins/icq/icqstatus.h new file mode 100644 index 0000000..83a01af --- /dev/null +++ b/plugins/icq/icqstatus.h @@ -0,0 +1,38 @@ + +#ifndef ICQSTATUS_H +#define ICQSTATUS_H + +#include "contacts/imstatus.h" + +class ICQStatus : public SIM::IMStatus +{ +public: + ICQStatus(const QString& id, const QString& name, bool hasText, const QString& defaultText, const QIcon& icon); + virtual ~ICQStatus(); + + virtual QString id() const; + virtual QString name() const; + virtual bool hasText() const; + virtual void setText(const QString& t); + virtual QString text() const; + virtual QIcon icon() const; + + virtual QStringList substatuses(); + virtual SIM::IMStatusPtr substatus(const QString& id); + virtual SIM::IMStatusPtr clone(); + + +private: + QString m_id; + QString m_name; + bool m_hasText; + QString m_text; + QIcon m_icon; +}; + +typedef QSharedPointer ICQStatusPtr; + +#endif + +// vim: set expandtab: + diff --git a/plugins/icq/icqvarious.cpp b/plugins/icq/icqvarious.cpp new file mode 100644 index 0000000..1066720 --- /dev/null +++ b/plugins/icq/icqvarious.cpp @@ -0,0 +1,1833 @@ +/*************************************************************************** + icqvarious.cpp - description + ------------------- + begin : Sun Mar 10 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + + +#include +#include +#ifdef WIN32 +#include +#else +#include +#include +#endif + +#include +#include +#include +#include +#include + +#include + +#include "log.h" + +#include "icqclient.h" +#include "xml.h" + +using namespace std; +using namespace SIM; + +const unsigned short ICQ_SNACxVAR_ERROR = 0x0001; +const unsigned short ICQ_SNACxVAR_REQxSRV = 0x0002; +const unsigned short ICQ_SNACxVAR_DATA = 0x0003; + +const unsigned short ICQ_SRVxREQ_OFFLINE_MSG = 0x3C00; +const unsigned short ICQ_SRVxREQ_ACK_OFFLINE_MSG = 0x3E00; +const unsigned short ICQ_SRVxOFFLINE_MSG = 0x4100; +const unsigned short ICQ_SRVxEND_OFFLINE_MSG = 0x4200; +const unsigned short ICQ_SRVxREQ_MORE = 0xD007; +const unsigned short ICQ_SRVxANSWER_MORE = 0xDA07; + +const unsigned short ICQ_SRVxREQ_FULL_INFO = 0xB204; +const unsigned short ICQ_SRVxREQ_SHORT_INFO = 0xBA04; +const unsigned short ICQ_SRVxREQ_OWN_INFO = 0xD004; +const unsigned short ICQ_SRVxREQ_SEND_SMS = 0x8214; +const unsigned short ICQ_SRVxREQ_WP_UIN = 0x6905; +const unsigned short ICQ_SRVxREQ_WP_MAIL = 0x7305; +const unsigned short ICQ_SRVxREQ_WP_FULL = 0x5F05; +const unsigned short ICQ_SRVxREQ_CHANGE_PASSWD = 0x2E04; +const unsigned short ICQ_SRVxREQ_PERMISSIONS = 0x2404; +const unsigned short ICQ_SRVxREQ_XML_KEY = 0x9808; + +const unsigned short ICQ_SRVxGENERAL_INFO = 0xC800; +const unsigned short ICQ_SRVxMORE_INFO = 0xDC00; +const unsigned short ICQ_SRVxEMAIL_INFO = 0xEB00; +const unsigned short ICQ_SRVxWORK_INFO = 0xD200; +const unsigned short ICQ_SRVxABOUT_INFO = 0xE600; +const unsigned short ICQ_SRVxINTERESTS_INFO = 0xF000; +const unsigned short ICQ_SRVxBACKGROUND_INFO = 0xFA00; +const unsigned short ICQ_SRVxUNKNOWN_INFO = 0x0E01; + +const unsigned short ICQ_SRVxREQ_MODIFY_MAIN = 0xEA03; +const unsigned short ICQ_SRVxREQ_MODIFY_HOME = 0xFD03; +const unsigned short ICQ_SRVxREQ_MODIFY_ABOUT = 0x0604; +const unsigned short ICQ_SRVxREQ_MODIFY_WORK = 0xF303; +const unsigned short ICQ_SRVxREQ_MODIFY_MORE = 0xFD03; +const unsigned short ICQ_SRVxREQ_MODIFY_INTERESTS = 0x1004; +const unsigned short ICQ_SRVxREQ_MODIFY_BACKGROUND = 0x1A04; +const unsigned short ICQ_SRVxREQ_MODIFY_MAIL = 0x0B04; + +const unsigned short ICQ_SRVxREQ_PHONE_UPDATE = 0x5406; +const unsigned short ICQ_SRVxREQ_SET_CHAT_GROUP = 0x5807; +const unsigned short ICQ_SRVxREQ_RANDOM_CHAT = 0x4E07; + +const unsigned short ICQ_SRVxWP_SET = 0x3A0C; +const unsigned short ICQ_SRVxWP_SET_RESP = 0x3F0C; + +const unsigned short TLV_UIN = 0x0136; +const unsigned short TLV_FIRST_NAME = 0x0140; +const unsigned short TLV_LAST_NAME = 0x014A; +const unsigned short TLV_NICK = 0x0154; +const unsigned short TLV_EMAIL = 0x015E; +const unsigned short TLV_AGE_RANGE = 0x0168; +const unsigned short TLV_AGE = 0x0172; +const unsigned short TLV_GENDER = 0x017C; +const unsigned short TLV_LANGUAGE = 0x0186; +const unsigned short TLV_CITY = 0x0190; +const unsigned short TLV_STATE = 0x019A; +const unsigned short TLV_COUNTRY = 0x01A4; +const unsigned short TLV_WORK_COMPANY = 0x01AE; +const unsigned short TLV_WORK_DEPARTMENT = 0x01B8; +const unsigned short TLV_WORK_POSITION = 0x01C2; +const unsigned short TLV_WORK_OCCUPATION = 0x01CC; +const unsigned short TLV_AFFILATIONS = 0x01D6; +const unsigned short TLV_INTERESTS = 0x01EA; +const unsigned short TLV_PAST = 0x01FE; +const unsigned short TLV_HOMEPAGE_CATEGORY = 0x0212; +const unsigned short TLV_HOMEPAGE = 0x0213; +const unsigned short TLV_KEYWORDS = 0x0226; +const unsigned short TLV_SEARCH_ONLINE = 0x0230; +const unsigned short TLV_BIRTHDAY = 0x023A; +const unsigned short TLV_NOTES = 0x0258; +const unsigned short TLV_STREET = 0x0262; +const unsigned short TLV_ZIP = 0x026C; +const unsigned short TLV_PHONE = 0x0276; +const unsigned short TLV_FAX = 0x0280; +const unsigned short TLV_CELLULAR = 0x028A; +const unsigned short TLV_WORK_STREET = 0x0294; +const unsigned short TLV_WORK_CITY = 0x029E; +const unsigned short TLV_WORK_STATE = 0x02A8; +const unsigned short TLV_WORK_COUNTRY = 0x02B2; +const unsigned short TLV_WORK_ZIP = 0x02BC; +const unsigned short TLV_WORK_PHONE = 0x02C6; +const unsigned short TLV_WORK_FAX = 0x02D0; +const unsigned short TLV_WORK_HOMEPAGE = 0x02DA; +const unsigned short TLV_SHOW_WEB = 0x030C; +const unsigned short TLV_NEED_AUTH = 0x02F8; +const unsigned short TLV_TIMEZONE = 0x0316; +const unsigned short TLV_ORIGINALLY_CITY = 0x0320; +const unsigned short TLV_ORIGINALLY_STATE = 0x032A; +const unsigned short TLV_ORIGINALLY_COUNTRY = 0x0334; +const unsigned short TLV_RECV_ICQ_SPAM = 0x0348; + +const char SEARCH_STATE_OFFLINE = 0; +const char SEARCH_STATE_ONLINE = 1; +const char SEARCH_STATE_DISABLED = 2; + +const unsigned INFO_REQUEST_TIMEOUT = 60; + +class ServerRequest +{ +public: + ServerRequest(unsigned short id); + virtual ~ServerRequest() {} + unsigned short id() { return m_id; } + virtual bool answer(ICQBuffer&, unsigned short nSubType) = 0; + virtual void fail(unsigned short error_code = 0); +protected: + unsigned short m_id; +}; + +ServerRequest::ServerRequest(unsigned short id) +{ + m_id = id; +} + +ServerRequest *ICQClient::findServerRequest(unsigned short id) +{ + log(L_DEBUG,"Searching for event id %d (%p)", id, this); + for (list::iterator it = varRequests.begin(); it != varRequests.end(); ++it){ + if ((*it)->id() == id) + return *it; + } + return NULL; +} + +void ServerRequest::fail(unsigned short) +{ +} + +void ICQClient::clearServerRequests() +{ + log(L_DEBUG,"Clearing server requests (%p)", this); + for (list::iterator it_req = varRequests.begin(); it_req != varRequests.end(); ++it_req){ + (*it_req)->fail(); + delete *it_req; + } + varRequests.clear(); + list::iterator it; + for (it = infoRequests.begin(); it != infoRequests.end(); ++it){ + Contact *contact = getContacts()->contact(it->uin); + if (contact == NULL) + continue; + EventContact e(contact, EventContact::eFetchInfoFailed); + e.process(); + } + infoRequests.clear(); +} + +void ICQClient::snac_various(unsigned short type, unsigned short id) +{ + switch (type){ + case ICQ_SNACxVAR_ERROR:{ + unsigned short error_code; + socket()->readBuffer() >> error_code; + if (id == m_offlineMessagesRequestId) + { + log(L_WARN, "Server responded with error %04X for offline messages request.", error_code); + // We'll never get ICQ_SRVxEND_OFFLINE_MSG, so we finish initing here instead. + } + else + { + ServerRequest *req = findServerRequest(id); + if (req == NULL){ + log(L_WARN, "Various event ID %04X not found for error %04X", id, error_code); + break; + } + req->fail(error_code); + } + break; + } + case ICQ_SNACxVAR_DATA:{ + TlvList tlv(socket()->readBuffer()); + if (tlv(0x0001) == NULL){ + log(L_WARN, "Bad server response"); + break; + } + ICQBuffer msg(*tlv(1)); + unsigned short len, nType, nId; + unsigned long own_uin; + msg >> len >> own_uin >> nType; + msg.unpack(nId); + switch (nType){ + case ICQ_SRVxEND_OFFLINE_MSG: + serverRequest(ICQ_SRVxREQ_ACK_OFFLINE_MSG); + sendServerRequest(); + setChatGroup(); + addFullInfoRequest(data.owner.Uin.toULong()); + m_bReady = true; + snacICBM()->processSendQueue(); + break; + case ICQ_SRVxOFFLINE_MSG:{ + unsigned long uin; + unsigned char type, flag; + struct tm sendTM; + memset(&sendTM, 0, sizeof(sendTM)); + QByteArray message; + unsigned short year; + unsigned char month, day, hours, min; + msg.unpack(uin); + msg.unpack(year); + msg.unpack(month); + msg.unpack(day); + msg.unpack(hours); + msg.unpack(min); + msg.unpack(type); + msg.unpack(flag); + msg.unpackStr(message); + // ToDo: replace time_t & tm with QDateTime + #ifndef HAVE_TM_GMTOFF + sendTM.tm_sec = -timezone; + #else + time_t now = time (NULL); + sendTM = *localtime (&now); + sendTM.tm_sec = sendTM.tm_gmtoff - (sendTM.tm_isdst == 1 ? 3600 : 0); + #endif + sendTM.tm_year = year-1900; + sendTM.tm_mon = month-1; + sendTM.tm_mday = day; + sendTM.tm_hour = hours; + sendTM.tm_min = min; + sendTM.tm_isdst = -1; + time_t send_time = mktime(&sendTM); + MessageId id; + Message *m = parseMessage(type, QString::number(uin), message, msg, id, 0); + if (m){ + m->setTime(send_time); + messageReceived(m, QString::number(uin)); + } + break; + } + case ICQ_SRVxANSWER_MORE:{ + unsigned short nSubtype; + char nResult; + msg >> nSubtype >> nResult; + if ((nResult == 0x32) || (nResult == 0x14) || (nResult == 0x1E)){ + ServerRequest *req = findServerRequest(nId); + if (req == NULL){ + log(L_WARN, "Various event ID %04X not found (%X)", nId, nResult); + break; + } + req->fail(); + log(L_DEBUG, "removing server request %d (%p)", nId, this); + varRequests.remove(req); + delete req; + break; + } + ServerRequest *req = findServerRequest(nId); + if (req == NULL){ + log(L_WARN, "Various event ID %04X not found (%X)", nId, nResult); + break; + } + if (req->answer(msg, nSubtype)){ + log(L_DEBUG, "removing server request %d (%p)", nId, this); + varRequests.remove(req); + delete req; + } + break; + } + break; + default: + log(L_WARN, "Unknown SNAC(15,03) response type %04X", nType); + } + break; + } + default: + log(L_WARN, "Unknown various foodgroup type %04X", type); + } +} + +void ICQClient::serverRequest(unsigned short cmd, unsigned short seq) +{ + snac(ICQ_SNACxFOOD_VARIOUS, ICQ_SNACxVAR_REQxSRV, true, false); + socket()->writeBuffer().tlv(0x0001, 0); + socket()->writeBuffer().pack(data.owner.Uin.toULong()); + socket()->writeBuffer() << cmd; + socket()->writeBuffer().pack((unsigned short)(seq ? seq : m_nMsgSequence)); +} + +void ICQClient::sendServerRequest() +{ + ICQBuffer &b = socket()->writeBuffer(); + char *packet = b.data(b.packetStartPos()); + unsigned short packet_size = (unsigned short)(b.size() - b.packetStartPos()); + unsigned short size = (unsigned short)(packet_size - 0x14); + packet[0x12] = (char)((size >> 8) & 0xFF); + packet[0x13] = (char)(size & 0xFF); + size = (unsigned short)(packet_size - 0x16); + packet[0x14] = (char)(size & 0xFF); + packet[0x15] = (char)((size >> 8) & 0xFF); + sendPacket(true); +} + +void ICQClient::sendMessageRequest() +{ + serverRequest(ICQ_SRVxREQ_OFFLINE_MSG); + m_offlineMessagesRequestId = m_nMsgSequence; + sendServerRequest(); +} + +// _________________________________________________________________________________________ + +class FullInfoRequest : public ServerRequest +{ +public: + FullInfoRequest(ICQClient *client, unsigned short id, unsigned long uin); +protected: + virtual void fail(unsigned short error_code); + bool answer(ICQBuffer &b, unsigned short nSubtype); + QString unpack_list(ICQBuffer &b, Contact *contact); + unsigned m_nParts; + unsigned long m_uin; + ICQClient *m_client; +}; + +FullInfoRequest::FullInfoRequest(ICQClient *client, unsigned short id, unsigned long uin) + : ServerRequest(id) +{ + m_client = client; + m_nParts = 0; + m_uin = uin; +} + +void FullInfoRequest::fail(unsigned short) +{ + Contact *contact = NULL; + if (m_nParts){ + if (m_client->data.owner.Uin.toULong() == m_uin){ + EventClientChanged(m_client).process(); + }else{ + m_client->findContact(m_uin, NULL, false, contact); + if (contact){ + EventContact e(contact, EventContact::eChanged); + e.process(); + } + } + } + if (contact){ + EventContact e(contact, EventContact::eFetchInfoFailed); + e.process(); + } + m_client->removeFullInfoRequest(m_uin); +} + +QString FullInfoRequest::unpack_list(ICQBuffer &b, Contact *contact) +{ + QString res; + char n; + b >> n; + for (; n > 0; n--){ + unsigned short c; + b.unpack(c); + QByteArray s; + b >> s; + if (c == 0) continue; + if (res.length()) + res += ';'; + res += QString::number(c); + res += ','; + res += quoteChars(getContacts()->toUnicode(contact, s), ";"); + } + return res; +} + +bool FullInfoRequest::answer(ICQBuffer &b, unsigned short nSubtype) +{ + Contact *contact = NULL; + ICQUserData *data; + if (m_client->data.owner.Uin.toULong() == m_uin){ + data = &m_client->data.owner; + }else{ + data = m_client->findContact(m_uin, NULL, false, contact); + if (data == NULL){ + log(L_DEBUG, "Info request %lu not found", m_uin); + m_client->removeFullInfoRequest(m_uin); + return true; + } + } + switch (nSubtype){ + case ICQ_SRVxGENERAL_INFO:{ + unsigned short n; + char TimeZone; + char authFlag; /* ??? */ + char webAware; + char allowDC; + char hideEmail; + QByteArray Nick, FirstName, LastName, EMail, City, State; + QByteArray HomePhone, HomeFax, Address, PrivateCellular, Zip; + b + >> Nick + >> FirstName + >> LastName + >> EMail + >> City + >> State + >> HomePhone + >> HomeFax + >> Address + >> PrivateCellular + >> Zip; + + data->Nick.str() = getContacts()->toUnicode(contact, Nick); + data->FirstName.str() = getContacts()->toUnicode(contact, FirstName); + data->LastName.str() = getContacts()->toUnicode(contact, LastName); + data->EMail.str() = getContacts()->toUnicode(contact, EMail); + data->City.str() = getContacts()->toUnicode(contact, City); + data->State.str() = getContacts()->toUnicode(contact, State); + data->HomePhone.str() = getContacts()->toUnicode(contact, HomePhone); + data->HomeFax.str() = getContacts()->toUnicode(contact, HomeFax); + data->Address.str() = getContacts()->toUnicode(contact, Address); + data->PrivateCellular.str() = getContacts()->toUnicode(contact, PrivateCellular); + data->Zip.str() = getContacts()->toUnicode(contact, Zip); + log(L_DEBUG, "Address: %s(%s)", qPrintable(data->Address.str()), Address.toHex().data()); + b.unpack(n); + data->Country.asULong() = n; + + b + >> TimeZone + >> authFlag + >> webAware + >> allowDC + >> hideEmail; + data->TimeZone.asULong() = TimeZone; + data->WebAware.asBool() = (webAware != 0); + data->bNoDirect.asBool() = (allowDC == 0); // negate! + data->HiddenEMail.asBool() = (hideEmail != 0); + break; + } + case ICQ_SRVxMORE_INFO:{ + char c; + QByteArray Homepage; + b >> c; + data->Age.asULong() = c; + b >> c; + b >> c; + data->Gender.asULong() = c; + b >> Homepage; + data->Homepage.str() = getContacts()->toUnicode(contact, Homepage); + unsigned short year; + b.unpack(year); + data->BirthYear.asULong() = year; + b >> c; + data->BirthMonth.asULong() = c; + b >> c; + data->BirthDay.asULong() = c; + unsigned char lang[3]; + b + >> lang[0] + >> lang[1] + >> lang[2]; + data->Language.asULong() = (lang[2] << 16) + (lang[1] << 8) + lang[0]; + break; + } + case ICQ_SRVxEMAIL_INFO:{ + QString mail; + char c; + b >> c; + for (;c > 0;c--){ + char d; + b >> d; + QByteArray s; + b >> s; + if (mail.length()) + mail += ';'; + mail += quoteChars(getContacts()->toUnicode(contact, s), ";"); + mail += '/'; + if (d) + mail += '-'; + } + data->EMails.str() = mail; + break; + } + case ICQ_SRVxWORK_INFO:{ + unsigned short n; + QByteArray WorkCity, WorkState, WorkPhone, WorkFax, WorkAddress, WorkZip; + QByteArray WorkName, WorkDepartment, WorkPosition, WorkHomepage; + b + >> WorkCity + >> WorkState + >> WorkPhone + >> WorkFax + >> WorkAddress + >> WorkZip; + data->WorkCity.str() = getContacts()->toUnicode(contact, WorkCity); + data->WorkState.str() = getContacts()->toUnicode(contact, WorkState); + data->WorkPhone.str() = getContacts()->toUnicode(contact, WorkPhone); + data->WorkFax.str() = getContacts()->toUnicode(contact, WorkFax); + data->WorkAddress.str() = getContacts()->toUnicode(contact, WorkAddress); + data->WorkZip.str() = getContacts()->toUnicode(contact, WorkZip); + + b.unpack(n); + data->WorkCountry.asULong() = n; + b + >> WorkName + >> WorkDepartment + >> WorkPosition; + data->WorkName.str() = getContacts()->toUnicode(contact, WorkName); + data->WorkDepartment.str() = getContacts()->toUnicode(contact, WorkDepartment); + data->WorkPosition.str() = getContacts()->toUnicode(contact, WorkPosition); + + b.unpack(n); + data->Occupation.asULong() = n; + b >> WorkHomepage; + data->WorkHomepage.str() = getContacts()->toUnicode(contact, WorkHomepage); + break; + } + case ICQ_SRVxABOUT_INFO: { + QByteArray About; + b >> About; + data->About.str() = getContacts()->toUnicode(contact, About); + break; + } + case ICQ_SRVxINTERESTS_INFO: + data->Interests.str() = unpack_list(b, contact); + break; + case ICQ_SRVxBACKGROUND_INFO: + data->Backgrounds.str() = unpack_list(b, contact); + data->Affilations.str() = unpack_list(b, contact); + break; + case ICQ_SRVxUNKNOWN_INFO: + break; + default: + log(L_WARN, "Unknwon info type %04X for %lu", nSubtype, m_uin); + } + m_nParts++; + if (m_nParts >= 8){ + data->InfoFetchTime.asULong() = data->InfoUpdateTime.toULong() ? data->InfoUpdateTime.toULong() : 1; + if (contact != NULL){ + m_client->setupContact(contact, data); + EventContact e(contact, EventContact::eChanged); + e.process(); + }else{ + int tz; + // ToDo: replace time_t & tm with QDateTime +#ifndef HAVE_TM_GMTOFF + tz = - timezone; +#else + time_t now = time(NULL); + struct tm *tm = localtime(&now); + tz = tm->tm_gmtoff; + if (tm->tm_isdst) tz -= (60 * 60); +#endif + tz = - tz / (30 * 60); + m_client->setupContact(getContacts()->owner(), data); + if (data->TimeZone.toULong() != (unsigned)tz){ + data->TimeZone.asULong() = tz; + m_client->setMainInfo(data); + } + EventContact eContact(getContacts()->owner(), EventContact::eChanged); + eContact.process(); + EventClientChanged(m_client).process(); + } + m_client->removeFullInfoRequest(m_uin); + return true; + } + return false; +} + +unsigned ICQClient::processInfoRequest() +{ + if ((getState() != Connected) || infoRequests.empty()) + return 0; + for (list::iterator it = infoRequests.begin(); it != infoRequests.end(); ++it){ + if (it->request_id) + continue; + unsigned delay = delayTime(SNAC(ICQ_SNACxFOOD_VARIOUS, ICQ_SNACxVAR_REQxSRV)); + if (delay) + return delay; + unsigned long uin = it->uin; + serverRequest(ICQ_SRVxREQ_MORE); + socket()->writeBuffer() << ((uin == data.owner.Uin.toULong()) ? ICQ_SRVxREQ_OWN_INFO : ICQ_SRVxREQ_FULL_INFO); + socket()->writeBuffer().pack(uin); + sendServerRequest(); + it->request_id = m_nMsgSequence; + it->start_time = time(NULL); + log(L_DEBUG, "add server request %d (%p)", m_nMsgSequence, this); + varRequests.push_back(new FullInfoRequest(this, m_nMsgSequence, uin)); + } + return 0; +} + +void ICQClient::checkInfoRequest() +{ + // ToDo: replace time_t & tm with QDateTime + time_t now = time(NULL); + for (list::iterator it = infoRequests.begin(); it != infoRequests.end(); ){ + if ((it->request_id == 0) || ((time_t)(it->start_time + INFO_REQUEST_TIMEOUT) < now)){ + ++it; + continue; + } + ServerRequest *req = findServerRequest(it->request_id); + if (req){ + req->fail(); + }else{ + infoRequests.erase(it); + } + it = infoRequests.begin(); + } +} + +void ICQClient::addFullInfoRequest(unsigned long uin) +{ + for (list::iterator it = infoRequests.begin(); it != infoRequests.end(); ++it){ + if (it->uin == uin) + return; + } + InfoRequest r; + r.uin = uin; + r.request_id = 0; + r.start_time = 0; + infoRequests.push_back(r); + snacICBM()->processSendQueue(); +} + +void ICQClient::removeFullInfoRequest(unsigned long uin) +{ + list::iterator it; + for (it = infoRequests.begin(); it != infoRequests.end(); ++it){ + if (it->uin == uin){ + infoRequests.erase(it); + break; + } + } +} + +// _________________________________________________________________________________________ + +class SearchWPRequest : public ServerRequest +{ +public: + SearchWPRequest(ICQClient *client, unsigned short id); +protected: + virtual void fail(unsigned short error_code); + bool answer(ICQBuffer &b, unsigned short nSubtype); + ICQClient *m_client; +}; + +SearchWPRequest::SearchWPRequest(ICQClient *client, unsigned short id) + : ServerRequest(id) +{ + m_client = client; +} + +void SearchWPRequest::fail(unsigned short) +{ + SearchResult res; + res.id = m_id; + res.client = m_client; + load_data(ICQProtocol::icqUserData, &res.data, NULL); + EventSearchDone(&res).process(); + free_data(ICQProtocol::icqUserData, &res.data); +} + +bool SearchWPRequest::answer(ICQBuffer &b, unsigned short nSubType) +{ + QByteArray Nick, FirstName, LastName, EMail; + SearchResult res; + res.id = m_id; + res.client = m_client; + load_data(ICQProtocol::icqUserData, &res.data, NULL); + + unsigned short n; + b >> n; + b.unpack(res.data.Uin.asULong()); + char waitAuth; + unsigned short state; + char gender; + unsigned short age; + b + >> Nick + >> FirstName + >> LastName + >> EMail + >> waitAuth; + res.data.Nick.str() = getContacts()->toUnicode(NULL, Nick); + res.data.FirstName.str() = getContacts()->toUnicode(NULL, FirstName); + res.data.LastName.str() = getContacts()->toUnicode(NULL, LastName); + res.data.EMail.str() = getContacts()->toUnicode(NULL, EMail); + + b.unpack(state); + b >> gender; + b.unpack(age); + + if (waitAuth) + res.data.WaitAuth.asBool() = true; + switch (state){ + case SEARCH_STATE_OFFLINE: + res.data.Status.asULong() = STATUS_OFFLINE; + break; + case SEARCH_STATE_ONLINE: + res.data.Status.asULong() = STATUS_ONLINE; + break; + case SEARCH_STATE_DISABLED: + res.data.Status.asULong() = STATUS_UNKNOWN; + break; + } + res.data.Gender.asULong() = gender; + res.data.Age.asULong() = age; + + if (res.data.Uin.toULong() != m_client->data.owner.Uin.toULong()){ + EventSearch(&res).process(); + } + free_data(ICQProtocol::icqUserData, &res.data); + + if (nSubType == 0xAE01){ + unsigned long all; + b >> all; + load_data(ICQProtocol::icqUserData, &res.data, NULL); + res.data.Uin.asULong() = all; + EventSearchDone(&res).process(); + free_data(ICQProtocol::icqUserData, &res.data); + return true; + } + return false; +} + +unsigned short ICQClient::findByUin(unsigned long uin) +{ + if (getState() != Connected) + return USHRT_MAX; + serverRequest(ICQ_SRVxREQ_MORE); + socket()->writeBuffer() + << ICQ_SRVxREQ_WP_UIN; + socket()->writeBuffer().tlvLE(TLV_UIN, uin); + sendServerRequest(); + varRequests.push_back(new SearchWPRequest(this, m_nMsgSequence)); + return m_nMsgSequence; +} + +unsigned short ICQClient::findByMail(const QString &_mail) +{ + if (getState() != Connected) + return USHRT_MAX; + const QByteArray mail = getContacts()->fromUnicode(NULL, _mail); + + serverRequest(ICQ_SRVxREQ_MORE); + socket()->writeBuffer() << ICQ_SRVxREQ_WP_MAIL; + socket()->writeBuffer().tlvLE(TLV_EMAIL, mail.data()); + sendServerRequest(); + varRequests.push_back(new SearchWPRequest(this, m_nMsgSequence)); + return m_nMsgSequence; +} + +void ICQClient::packTlv(unsigned short tlv, unsigned short code, const QString &_keywords) +{ + if ((code == 0) && _keywords.isEmpty()) + return; + QByteArray data = getContacts()->fromUnicode(NULL, _keywords); + + ICQBuffer b; + b.pack(code); + b << data; + socket()->writeBuffer().tlvLE(tlv, b); +} + +void ICQClient::packTlv(unsigned short tlv, const QString &_data) +{ + if(_data.isEmpty()) + return; + const QByteArray data = getContacts()->fromUnicode(NULL, _data); + socket()->writeBuffer().tlvLE(tlv, data.data()); +} + +void ICQClient::packTlv(unsigned short tlv, unsigned short data) +{ + if(data == 0) + return; + socket()->writeBuffer().tlvLE(tlv, data); +} + +unsigned short ICQClient::findWP(const QString &szFirst, const QString &szLast, const QString &szNick, + const QString &szEmail, char age, char nGender, + unsigned short nLanguage, const QString &szCity, const QString &szState, + unsigned short nCountryCode, + const QString &szCoName, const QString &szCoDept, const QString &szCoPos, + unsigned short nOccupation, + unsigned short nPast, const QString &szPast, + unsigned short nInterests, const QString &szInterests, + unsigned short nAffilation, const QString &szAffilation, + unsigned short nHomePage, const QString &szHomePage, + const QString &szKeyWords, bool bOnlineOnly) +{ + if (getState() != Connected) + return USHRT_MAX; + serverRequest(ICQ_SRVxREQ_MORE); + socket()->writeBuffer() << ICQ_SRVxREQ_WP_FULL; + + unsigned long nMinAge = 0; + unsigned long nMaxAge = 0; + switch (age){ + case 1: + nMinAge = 18; + nMaxAge = 22; + break; + case 2: + nMinAge = 23; + nMaxAge = 29; + break; + case 3: + nMinAge = 30; + nMaxAge = 39; + break; + case 4: + nMinAge = 40; + nMaxAge = 49; + break; + case 5: + nMinAge = 50; + nMaxAge = 59; + break; + case 6: + nMinAge = 60; + nMaxAge = 120; + break; + } + + packTlv(TLV_CITY, szCity); + packTlv(TLV_STATE, szState); + packTlv(TLV_WORK_COMPANY, szCoName); + packTlv(TLV_WORK_DEPARTMENT, szCoDept); + packTlv(TLV_WORK_POSITION, szCoPos); + packTlv(TLV_AGE_RANGE, (nMaxAge << 16) + nMinAge); + packTlv(TLV_GENDER, nGender); + packTlv(TLV_LANGUAGE, nLanguage); + packTlv(TLV_COUNTRY, nCountryCode); + packTlv(TLV_WORK_OCCUPATION, nOccupation); + packTlv(TLV_PAST, nPast, szPast); + packTlv(TLV_INTERESTS, nInterests, szInterests); + packTlv(TLV_AFFILATIONS, nAffilation, szAffilation); + packTlv(TLV_HOMEPAGE, nHomePage, szHomePage); + packTlv(TLV_FIRST_NAME, szFirst); + packTlv(TLV_LAST_NAME, szLast); + packTlv(TLV_NICK, szNick); + packTlv(TLV_KEYWORDS, szKeyWords); + packTlv(TLV_EMAIL, szEmail); + if (bOnlineOnly) + socket()->writeBuffer().tlvLE(TLV_SEARCH_ONLINE, (char)1); + + sendServerRequest(); + varRequests.push_back(new SearchWPRequest(this, m_nMsgSequence)); + return m_nMsgSequence; +} + +// ______________________________________________________________________________________ + +class SetMainInfoRequest : public ServerRequest +{ +public: + SetMainInfoRequest(ICQClient *client, unsigned short id, ICQUserData *data); +protected: + bool answer(ICQBuffer &b, unsigned short nSubtype); + QString m_nick; + QString m_firstName; + QString m_lastName; + QString m_city; + QString m_state; + QString m_address; + QString m_zip; + QString m_email; + QString m_homePhone; + QString m_homeFax; + QString m_privateCellular; + bool m_hiddenEMail; + unsigned m_country; + unsigned m_tz; + ICQClient *m_client; +}; + +SetMainInfoRequest::SetMainInfoRequest(ICQClient *client, unsigned short id, ICQUserData *data) + : ServerRequest(id) +{ + m_client = client; + m_nick = data->Nick.str(); + m_firstName = data->FirstName.str(); + m_lastName = data->LastName.str(); + m_city = data->City.str(); + m_state = data->State.str(); + m_address = data->Address.str(); + m_zip = data->Zip.str(); + m_email = data->EMail.str(); + m_homePhone = data->HomePhone.str(); + m_homeFax = data->HomeFax.str(); + m_privateCellular = data->PrivateCellular.str(); + m_country = data->Country.toULong(); + m_tz = data->TimeZone.toULong(); + m_hiddenEMail = data->HiddenEMail.toBool(); +} + +bool SetMainInfoRequest::answer(ICQBuffer&, unsigned short) +{ + m_client->data.owner.Nick.str() = m_nick; + m_client->data.owner.FirstName.str() = m_firstName; + m_client->data.owner.LastName.str() = m_lastName; + m_client->data.owner.City.str() = m_city; + m_client->data.owner.State.str() = m_state; + m_client->data.owner.Address.str() = m_address; + m_client->data.owner.Zip.str() = m_zip; + m_client->data.owner.EMail.str() = m_email; + m_client->data.owner.HomePhone.str() = m_homePhone; + m_client->data.owner.HomeFax.str() = m_homeFax; + m_client->data.owner.PrivateCellular.str() = m_privateCellular; + m_client->data.owner.Country.asULong() = m_country; + m_client->data.owner.TimeZone.asULong() = m_tz; + m_client->data.owner.HiddenEMail.asBool() = m_hiddenEMail; + EventClientChanged(m_client).process(); + m_client->snacService()->sendUpdate(); + return true; +} + +// ****************************************** +// static helper functions +// ****************************************** +static Tlv makeSString(unsigned id, const QString &str) +{ + QByteArray cstr = getContacts()->fromUnicode(NULL, str); + unsigned len = cstr.length() + 1; // including '\0' + QByteArray ba( len + 2, '\0' ); + ba[0] = (char)((len ) & 0xff); + ba[1] = (char)((len >> 8) & 0xff); + memcpy( ba.data() + 2, cstr, len ); + return Tlv(id, ba.size(), ba.data()); +} + +static Tlv makeBCombo(unsigned id, unsigned long y, unsigned long m, unsigned long d) +{ + unsigned short buf[4]; + buf[0] = (unsigned short)(y); + buf[1] = (unsigned short)(m); + buf[2] = (unsigned short)(d); + buf[3] = '\0'; + + return Tlv( id, 6, (const char*)buf ); +} + +static Tlv makeECombo(unsigned id, const QString &str) +{ + QByteArray cstr = getContacts()->fromUnicode(NULL, str); + unsigned len = cstr.length() + 1; // including '\0' + QByteArray ba( len + 3, '\0' ); + ba[0] = (char)((len ) & 0xff); + ba[1] = (char)((len >> 8) & 0xff); + memcpy( ba.data() + 2, cstr, len ); + ba[ (int)len + 2 ] = '\0'; // permission (don't use in icq directories) + return Tlv( id, ba.size(), ba.data() ); +} + +static QList makeICombo(unsigned id, const QString &str) +{ + QList list; + if ( str.isEmpty() ) + return list; + + QByteArray cstr = getContacts()->fromUnicode(NULL, str); + int cur = 0; + int idx = 0; + do { + idx = cstr.indexOf( ',', cur ); + if( idx == -1 ) + break; + + int cat = cstr.mid( cur, idx - cur ).toULong(); + cur = idx + 1; + + int start_pos = cur; + // Now looking for ";" with even number of slashes before it + do { + idx = cstr.indexOf( ';', cur ); + if ( idx == -1 ) { + idx = cstr.length(); // If no ";' will use whole string + } + else{ + // If found then count slashes before it + int slash_count = 0; + while ( (idx > slash_count) && (cstr.mid(idx-1-slash_count,1) == "\\") ){ + slash_count++ ; + } + if ( slash_count % 2 != 0 ) // If there are odd number of slashes, looking for another ";" + { + cur = idx+1; + idx = -1; + } + } + } while (idx == -1); + + QByteArray data = cstr.mid( start_pos, idx - start_pos ); + cur = idx + 1; + + int len = data.length(); + + QByteArray ba( len + 4, '\0' ); + ba[0] = (char)((cat ) & 0xff); + ba[1] = (char)((cat >> 8) & 0xff); + ba[2] = (char)((len ) & 0xff); + ba[3] = (char)((len >> 8) & 0xff); + memcpy( ba.data() + 4, data.data(), len ); + + list.append( Tlv( id, ba.size(), ba.data() ) ); + } while( idx != cstr.length() ); + return list; +} + +static Tlv makeUInt32(unsigned id, unsigned long d) +{ + char data[4]; + + data[0] = (char)((d >> 0) & 0xff); + data[1] = (char)((d >> 8) & 0xff); + data[2] = (char)((d >> 16) & 0xff); + data[3] = (char)((d >> 24) & 0xff); + return Tlv( id, 4, data ); +} + +static Tlv makeUInt16(unsigned id, unsigned short d) +{ + char data[2]; + + data[0] = (char)((d >> 0) & 0xff); + data[1] = (char)((d >> 8) & 0xff); + return Tlv( id, 2, data ); +} + +static Tlv makeUInt8(unsigned id, unsigned char d) +{ + char data[1]; + + data[0] = (char)((d >> 0) & 0xff); + return Tlv( id, 1, data ); +} + +static QString getSString(const char *tlvData) +{ + unsigned len; + const unsigned char *data = (const unsigned char*)tlvData; + len = data[0] | ( data[1] << 8 ); + QString ret = getContacts()->toUnicode(NULL, QByteArray::fromRawData(&tlvData[2], len)); + return ret; +} + +static void getBCombo(const char *tlvData, unsigned long &y, unsigned long &m, unsigned long &d) +{ + unsigned short *buf = (unsigned short*)tlvData; + y = buf[0]; + m = buf[1]; + d = buf[2]; +} + +static QString getECombo(const char *tlvData) +{ + unsigned len; + const unsigned char *data = (const unsigned char*)tlvData; + len = data[0] | ( data[1] << 8 ); + QString ret = getContacts()->toUnicode(NULL, QByteArray::fromRawData( &tlvData[2], len)); + return ret; +} + +static QString getICombo(const char *tlvData, const QString &o) +{ + QString ret; + QString others = o; + const unsigned char *data = (const unsigned char*)tlvData; + + unsigned cat = data[0] | ( data[1] << 8 ); + ret = QString::number( cat ) + ',' + getSString( &tlvData[2] ); + if( others.isEmpty() ) + return ret; + return others + ';' + ret; +} + +static unsigned long getUInt32(const char *tlvData) +{ + unsigned long ret; + const unsigned char *data = (const unsigned char*)tlvData; + ret = data[0] | ( data[1] << 8 ) | ( data[2] << 16 ) | ( data[3] << 24 ); + return ret; +} + +static unsigned short getUInt16(const char *tlvData) +{ + unsigned short ret; + const unsigned char *data = (const unsigned char*)tlvData; + ret = data[0] | ( data[1] << 8 ); + return ret; +} + +static char getUInt8(const char *tlvData) +{ + unsigned char ret; + ret = tlvData[0]; + return ret; +} + +class ChangeInfoRequest : public ServerRequest +{ +public: + ChangeInfoRequest(ICQClient *client, unsigned short id, const QList &clientInfoTLVs); +protected: + bool answer(ICQBuffer &b, unsigned short nSubtype); + ICQClient *m_client; + QList m_clientInfoTLVs; +}; + +ChangeInfoRequest::ChangeInfoRequest(ICQClient *client, unsigned short id, const QList &clientInfoTLVs) + : ServerRequest(id), m_client(client), m_clientInfoTLVs(clientInfoTLVs) +{ +} + +bool ChangeInfoRequest::answer(ICQBuffer&, unsigned short) +{ + bool bFirstAffilation = true; + bool bFirstInterest = true; + bool bFirstBackground = true; + for( int i = 0; i < m_clientInfoTLVs.count(); i++ ) { + Tlv *tlv = &m_clientInfoTLVs[i]; + switch(tlv->Num()) { + case TLV_FIRST_NAME: + m_client->data.owner.FirstName.str() = getSString(tlv->Data()); + break; + case TLV_LAST_NAME: + m_client->data.owner.LastName.str() = getSString(tlv->Data()); + break; + case TLV_NICK: + m_client->data.owner.Nick.str() = getSString(tlv->Data()); + break; + case TLV_EMAIL: + m_client->data.owner.EMail.str() = getECombo(tlv->Data()); + break; + case TLV_AGE: + m_client->data.owner.Age.asULong() = getUInt16(tlv->Data()); + break; + case TLV_GENDER: + m_client->data.owner.Gender.asULong() = getUInt8(tlv->Data()); + break; + case TLV_LANGUAGE: + m_client->data.owner.Language.asULong() = getUInt16(tlv->Data()); + break; + case TLV_CITY: + m_client->data.owner.City.str() = getSString(tlv->Data()); + break; + case TLV_STATE: + m_client->data.owner.State.str() = getSString(tlv->Data()); + break; + case TLV_COUNTRY: + m_client->data.owner.Country.asULong() = getUInt16(tlv->Data()); + break; + case TLV_WORK_COMPANY: + m_client->data.owner.WorkName.str() = getSString(tlv->Data()); + break; + case TLV_WORK_DEPARTMENT: + m_client->data.owner.WorkDepartment.str() = getSString(tlv->Data()); + break; + case TLV_WORK_POSITION: + m_client->data.owner.WorkPosition.str() = getSString(tlv->Data()); + break; + case TLV_WORK_OCCUPATION: + m_client->data.owner.Occupation.asULong() = getUInt16(tlv->Data()); + break; + case TLV_AFFILATIONS: { + if( bFirstAffilation ) { + m_client->data.owner.Affilations.clear(); + bFirstAffilation = false; + } + m_client->data.owner.Affilations.str() = getICombo(tlv->Data(), m_client->data.owner.Affilations.str()); + break; + } + case TLV_INTERESTS: + if( bFirstInterest ) { + m_client->data.owner.Interests.clear(); + bFirstInterest = false; + } + m_client->data.owner.Interests.str() = getICombo(tlv->Data(), m_client->data.owner.Interests.str()); + break; + case TLV_PAST: { + if( bFirstBackground ) { + m_client->data.owner.Backgrounds.clear(); + bFirstBackground = false; + } + m_client->data.owner.Backgrounds.str() = getICombo(tlv->Data(), m_client->data.owner.Backgrounds.str()); + break; + } +// 530 0x0212 icombo User homepage category/keywords + case TLV_HOMEPAGE: + m_client->data.owner.Homepage.str() = getSString(tlv->Data()); + break; + case TLV_BIRTHDAY: { + getBCombo(tlv->Data(), m_client->data.owner.BirthYear.asULong(), + m_client->data.owner.BirthMonth.asULong(), + m_client->data.owner.BirthDay.asULong()); + break; + } + case TLV_NOTES: + m_client->data.owner.About.str() = getSString(tlv->Data()); + break; + case TLV_STREET: + m_client->data.owner.Address.str() = getSString(tlv->Data()); + break; + case TLV_ZIP: { + QString str; + str.sprintf("%lu", getUInt32(tlv->Data())); + m_client->data.owner.Zip.str() = str; + break; + } + case TLV_PHONE: + m_client->data.owner.HomePhone.str() = getSString(tlv->Data()); + break; + case TLV_FAX: + m_client->data.owner.HomeFax.str() = getSString(tlv->Data()); + break; + case TLV_CELLULAR: + m_client->data.owner.PrivateCellular.str() = getSString(tlv->Data()); + break; + case TLV_WORK_STREET: + m_client->data.owner.WorkAddress.str() = getSString(tlv->Data()); + break; + case TLV_WORK_CITY: + m_client->data.owner.WorkCity.str() = getSString(tlv->Data()); + break; + case TLV_WORK_STATE: + m_client->data.owner.WorkState.str() = getSString(tlv->Data()); + break; + case TLV_WORK_COUNTRY: + m_client->data.owner.WorkCountry.asULong() = getUInt16((tlv->Data())); + break; + case TLV_WORK_ZIP: { + QString str; + str.sprintf("%lu", getUInt32(tlv->Data())); + m_client->data.owner.WorkZip.str() = str; + break; + } + case TLV_WORK_PHONE: + m_client->data.owner.WorkPhone.str() = getSString(tlv->Data()); + break; + case TLV_WORK_FAX: + m_client->data.owner.WorkFax.str() = getSString(tlv->Data()); + break; + case TLV_WORK_HOMEPAGE: + m_client->data.owner.WorkHomepage.str() = getSString(tlv->Data()); + break; + case TLV_SHOW_WEB: + m_client->data.owner.WebAware.asBool() = getUInt8(tlv->Data()); + break; + case TLV_NEED_AUTH: + m_client->data.owner.WaitAuth.asBool() = !getUInt8(tlv->Data()); + break; + case TLV_TIMEZONE: + m_client->data.owner.TimeZone.asBool() = getUInt8(tlv->Data()); + break; + /* + 800 0x0320 sstring User originally from city + 810 0x032A sstring User originally from state + 820 0x0334 uint16 User originally from country (code) + */ + default: + break; + } + } + m_client->snacService()->sendStatus(); + EventClientChanged(m_client).process(); + return true; +} + +void ICQClient::setMainInfo(ICQUserData *d) +{ + serverRequest(ICQ_SRVxREQ_MORE); + socket()->writeBuffer() << ICQ_SRVxREQ_MODIFY_MAIN + << d->Nick.str() + << d->FirstName.str() + << d->LastName.str() + << d->EMail.str() + << d->City.str() + << d->State.str() + << d->HomePhone.str() + << d->HomeFax.str() + << d->Address.str() + << d->PrivateCellular.str() + << d->Zip.str(); + socket()->writeBuffer().pack((unsigned short)(d->Country.toULong())); + socket()->writeBuffer().pack((char)(d->TimeZone.toULong())); + socket()->writeBuffer().pack((char)(d->HiddenEMail.toBool())); + sendServerRequest(); + + varRequests.push_back(new SetMainInfoRequest(this, m_nMsgSequence, d)); +} + +void ICQClient::setClientInfo(void *_data) +{ + if (getState() != Connected) + return; + + ICQUserData *d = toICQUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + + if (m_bAIM){ + d->ProfileFetch.asBool() = true; + data.owner.About.str() = d->About.str(); + setAIMInfo(d); + setProfile(d); + return; + } + + QList clientInfoTLVs; + + if (d->FirstName.str() != data.owner.FirstName.str()) + clientInfoTLVs.append(makeSString(TLV_FIRST_NAME, d->FirstName.str())); + + if (d->LastName.str() != data.owner.LastName.str()) + clientInfoTLVs.append(makeSString(TLV_LAST_NAME, d->LastName.str())); + + if (d->Nick.str() != data.owner.Nick.str()) + clientInfoTLVs.append(makeSString(TLV_NICK, d->Nick.str())); + + if (d->EMail.str() != data.owner.EMail.str()) + clientInfoTLVs.append(makeECombo(TLV_EMAIL, d->EMail.str())); + + if (d->Age.toULong() != data.owner.Age.toULong()) + clientInfoTLVs.append(makeUInt16(TLV_AGE, d->Age.toULong())); + + if (d->Gender.toULong() != data.owner.Gender.toULong()) + clientInfoTLVs.append(makeUInt8(TLV_GENDER, d->Gender.toULong())); + + if (d->Language.toULong() != data.owner.Language.toULong()) + clientInfoTLVs.append(makeUInt16(TLV_LANGUAGE, d->Language.toULong())); + + if (d->City.str() != data.owner.City.str()) + clientInfoTLVs.append(makeSString(TLV_CITY, d->City.str())); + + if (d->State.str() != data.owner.State.str()) + clientInfoTLVs.append(makeSString(TLV_STATE, d->State.str())); + + if (d->Country.toULong() != data.owner.Country.toULong()) + clientInfoTLVs.append(makeUInt16(TLV_COUNTRY, d->Country.toULong())); + + if (d->WorkName.str() != data.owner.WorkName.str()) + clientInfoTLVs.append(makeSString(TLV_WORK_COMPANY, d->WorkName.str())); + + if (d->WorkDepartment.str() != data.owner.WorkDepartment.str()) + clientInfoTLVs.append(makeSString(TLV_WORK_DEPARTMENT, d->WorkDepartment.str())); + + if (d->WorkPosition.str() != data.owner.WorkPosition.str()) + clientInfoTLVs.append(makeSString(TLV_WORK_POSITION, d->WorkPosition.str())); + + if (d->Occupation.toULong() != data.owner.Occupation.toULong()) + clientInfoTLVs.append(makeUInt16(TLV_WORK_OCCUPATION, d->Occupation.toULong())); + + if (d->Affilations.str() != data.owner.Affilations.str()) + clientInfoTLVs += makeICombo(TLV_AFFILATIONS, d->Affilations.str()); + + if (d->Interests.str() != data.owner.Interests.str()) + clientInfoTLVs += makeICombo(TLV_INTERESTS, d->Interests.str()); + + if (d->Backgrounds.str() != data.owner.Backgrounds.str()) + clientInfoTLVs += makeICombo(TLV_PAST, d->Backgrounds.str()); + +// 530 0x0212 icombo User homepage category/keywords + + if (d->Homepage.str() != data.owner.Homepage.str()) + clientInfoTLVs.append(makeSString(TLV_HOMEPAGE, d->Homepage.str())); + + if (d->BirthDay.toULong() != data.owner.BirthDay.toULong() || + d->BirthMonth.toULong() != data.owner.BirthMonth.toULong() || + d->BirthYear.toULong() != data.owner.BirthYear.toULong()) { + clientInfoTLVs.append(makeBCombo(TLV_BIRTHDAY, d->BirthYear.toULong(), d->BirthMonth.toULong(), d->BirthDay.toULong())); + } + + if (d->About.str() != data.owner.About.str()) + clientInfoTLVs.append(makeSString(TLV_NOTES, d->About.str())); + + if (d->Address.str() != data.owner.Address.str()) + clientInfoTLVs.append(makeSString(TLV_STREET, d->Address.str())); + + if (d->Zip.str() != data.owner.Zip.str()) + clientInfoTLVs.append(makeUInt32(TLV_ZIP, QString(d->Zip.str()).toULong())); + + if (d->HomePhone.str() != data.owner.HomePhone.str()) + clientInfoTLVs.append(makeSString(TLV_PHONE, d->HomePhone.str())); + + if (d->HomeFax.str() != data.owner.HomeFax.str()) + clientInfoTLVs.append(makeSString(TLV_FAX, d->HomeFax.str())); + + if (d->PrivateCellular.str() != data.owner.PrivateCellular.str()) + clientInfoTLVs.append(makeSString(TLV_CELLULAR, d->PrivateCellular.str())); + + if (d->WorkAddress.str() != data.owner.WorkAddress.str()) + clientInfoTLVs.append(makeSString(TLV_WORK_STREET, d->WorkAddress.str())); + + if (d->WorkCity.str() != data.owner.WorkCity.str()) + clientInfoTLVs.append(makeSString(TLV_WORK_CITY, d->WorkCity.str())); + + if (d->WorkState.str() != data.owner.WorkState.str()) + clientInfoTLVs.append(makeSString(TLV_WORK_STATE, d->WorkState.str())); + + if (d->WorkCountry.toULong() != data.owner.WorkCountry.toULong()) + clientInfoTLVs.append(makeUInt16(TLV_WORK_COUNTRY, d->WorkCountry.toULong())); + + if (d->WorkZip.str() != data.owner.WorkZip.str()) + clientInfoTLVs.append(makeUInt32(TLV_WORK_ZIP, QString(d->WorkZip.str()).toULong())); + + if (d->WorkPhone.str() != data.owner.WorkPhone.str()) + clientInfoTLVs.append(makeSString(TLV_WORK_PHONE, d->WorkPhone.str())); + + if (d->WorkFax.str() != data.owner.WorkFax.str()) + clientInfoTLVs.append(makeSString(TLV_WORK_FAX, d->WorkFax.str())); + + if (d->WorkHomepage.str() != data.owner.WorkHomepage.str()) + clientInfoTLVs.append(makeSString(TLV_WORK_HOMEPAGE, d->WorkHomepage.str())); + + if (d->WebAware.toBool() != data.owner.WebAware.toBool()) + clientInfoTLVs.append(makeUInt8(TLV_SHOW_WEB, d->WebAware.toBool())); + + if (d->WaitAuth.toBool() != data.owner.WaitAuth.toBool()) + clientInfoTLVs.append(makeUInt8(TLV_NEED_AUTH, d->WaitAuth.toBool() ? 0 : 1)); + + if (d->TimeZone.toULong() != data.owner.TimeZone.toULong()) + clientInfoTLVs.append(makeUInt8(TLV_TIMEZONE, d->TimeZone.toULong())); + /* + 800 0x0320 sstring User originally from city + 810 0x032A sstring User originally from state + 820 0x0334 uint16 User originally from country (code) + */ + uploadBuddy(&data.owner); + if (!clientInfoTLVs.isEmpty()) { + serverRequest(ICQ_SRVxREQ_MORE); + socket()->writeBuffer() << ICQ_SRVxWP_SET; + for( int i =0; i < clientInfoTLVs.count(); i++ ) { + Tlv *tlv = &clientInfoTLVs[i]; + socket()->writeBuffer().tlvLE( tlv->Num(), *tlv, tlv->Size() ); + } + sendServerRequest(); + varRequests.push_back(new ChangeInfoRequest(this, m_nMsgSequence, clientInfoTLVs)); + } + + setChatGroup(); + //snacService()->sendStatus(); +} + +class SetPasswordRequest : public ServerRequest +{ +public: + SetPasswordRequest(ICQClient *client, unsigned short id, const QString &pwd); +protected: + bool answer(ICQBuffer &b, unsigned short nSubtype); + virtual void fail(unsigned short error_code); + QString m_pwd; + ICQClient *m_client; +}; + +SetPasswordRequest::SetPasswordRequest(ICQClient *client, unsigned short id, const QString &pwd) + : ServerRequest(id), m_pwd(pwd), m_client(client) +{} + +bool SetPasswordRequest::answer(ICQBuffer&, unsigned short) +{ + m_client->setPassword(m_pwd); + log(L_DEBUG, "Password change success"); + EventNotification::ClientNotificationData d; + d.client = m_client; + d.code = 0; + d.text = I18N_NOOP("Password successfuly changed"); + d.args = QString::null; + d.flags = EventNotification::ClientNotificationData::E_INFO; + d.options = QString::null; + d.id = CmdPasswordSuccess; + EventClientNotification e(d); + e.process(); + return true; +} + +void SetPasswordRequest::fail(unsigned short error_code) +{ + log(L_DEBUG, "Password change fail: %X", error_code); + EventNotification::ClientNotificationData d; + d.client = m_client; + d.code = 0; + d.text = I18N_NOOP("Change password fail"); + d.args = QString::null; + d.flags = EventNotification::ClientNotificationData::E_ERROR; + d.options = QString::null; + d.id = CmdPasswordFail; + EventClientNotification e(d); + e.process(); +} + +void ICQClient::changePassword(const QString &new_pswd) +{ + QString pwd = new_pswd; + unsigned short passlen = htons(pwd.length() + 1); + serverRequest(ICQ_SRVxREQ_MORE); + socket()->writeBuffer() + << ICQ_SRVxREQ_CHANGE_PASSWD + << passlen + << (const char*)getContacts()->fromUnicode(NULL, pwd).data() + << (unsigned char)0x00; + sendServerRequest(); + varRequests.push_back(new SetPasswordRequest(this, m_nMsgSequence, new_pswd)); +} + +class SMSRequest : public ServerRequest +{ +public: + SMSRequest(ICQClient *client, unsigned short id); + virtual bool answer(ICQBuffer&, unsigned short nSubType); + virtual void fail(unsigned short error_code); +protected: + ICQClient *m_client; +}; + +#if 0 +const char *translations[] = + { + I18N_NOOP("The Cellular network is currently unable to send your message to the recipient. Please try again later."), + I18N_NOOP("INVALID NUMBER"), + I18N_NOOP("RATE LIMIT") + }; +#endif + +SMSRequest::SMSRequest(ICQClient *client, unsigned short id) + : ServerRequest(id) +{ + m_client = client; +} + +bool SMSRequest::answer(ICQBuffer &b, unsigned short code) +{ + if (code == 0x0100) + { + if (m_client->snacICBM()->smsQueue.empty()) + return true; + QByteArray errStr = b.data(b.readPos()); + SendMsg &s = m_client->snacICBM()->smsQueue.front(); + SMSMessage *sms = static_cast(s.msg); + m_client->snacICBM()->smsQueue.erase(m_client->snacICBM()->smsQueue.begin()); + sms->setError(errStr.data()); + EventMessageSent(sms).process(); + delete sms; + }else{ + b.incReadPos(6); + QByteArray provider; + QByteArray answer_QCString; + b.unpackStr(provider); + b.unpackStr(answer_QCString); +// FIXME + std::string answer = (const char *)answer_QCString; + string::iterator s = answer.begin(); + auto_ptr top(XmlNode::parse(s, answer.end())); + QString error = I18N_NOOP("SMS send fail"); + QString network; + if (top.get()){ + XmlNode *n = top.get(); + if (n && n->isBranch()){ + XmlBranch *msg = static_cast(n); + XmlLeaf *l = msg->getLeaf("deliverable"); + if (l && (l->getValue() == "Yes")){ + error = QString::null; + l = msg->getLeaf("network"); + if (l) + network = QString(l->getValue().c_str()); + }else{ + XmlBranch *param = msg->getBranch("param"); + if (param){ + XmlLeaf *l = param->getLeaf("error"); + if (l) + error = QString(l->getValue().c_str()); + } + } + } + } + + if (error.isEmpty()){ + if (!m_client->snacICBM()->smsQueue.empty()){ + SendMsg &s = m_client->snacICBM()->smsQueue.front(); + SMSMessage *sms = static_cast(s.msg); + sms->setNetwork(network); + if ((sms->getFlags() & MESSAGE_NOHISTORY) == 0){ + SMSMessage m; + m.setContact(sms->contact()); + m.setText(s.part); + m.setPhone(sms->getPhone()); + m.setNetwork(network); + EventSent(&m).process(); + } + } + }else{ + if (!m_client->snacICBM()->smsQueue.empty()){ + SendMsg &s = m_client->snacICBM()->smsQueue.front(); + s.msg->setError(error); + EventMessageSent(s.msg).process(); + delete s.msg; + m_client->snacICBM()->smsQueue.erase(m_client->snacICBM()->smsQueue.begin()); + } + } + } + m_client->snacICBM()->processSendQueue(); + return true; +} + +void SMSRequest::fail(unsigned short) +{ + if (m_client->snacICBM()->smsQueue.empty()) + return; + SendMsg &s = m_client->snacICBM()->smsQueue.front(); + Message *sms = s.msg; + sms->setError(I18N_NOOP("SMS send fail")); + m_client->snacICBM()->smsQueue.erase(m_client->snacICBM()->smsQueue.begin()); + EventMessageSent(sms).process(); + delete sms; + m_client->m_sendSmsId = 0; + m_client->snacICBM()->processSendQueue(); +} + +const unsigned MAX_SMS_LEN_LATIN1 = 160; +const unsigned MAX_SMS_LEN_UNICODE = 70; + +static const char *w_days[] = + { + "Sun", + "Mon", + "Tue", + "Wed", + "Thu", + "Fri", + "Say" + }; + +static const char *months[] = + { + I18N_NOOP("Jan"), + I18N_NOOP("Feb"), + I18N_NOOP("Mar"), + I18N_NOOP("Apr"), + I18N_NOOP("May"), + I18N_NOOP("Jun"), + I18N_NOOP("Jul"), + I18N_NOOP("Aug"), + I18N_NOOP("Sep"), + I18N_NOOP("Oct"), + I18N_NOOP("Nov"), + I18N_NOOP("Dec") + }; + +unsigned ICQClient::processSMSQueue() +{ + if (m_sendSmsId) + return 0; + for (;;){ + if (snacICBM()->smsQueue.empty()) + break; + unsigned delay = delayTime(SNAC(ICQ_SNACxFOOD_VARIOUS, ICQ_SNACxVAR_REQxSRV)); + if (delay) + return delay; + SendMsg &s = snacICBM()->smsQueue.front(); + if (s.text.isEmpty() || (!(s.flags & SEND_1STPART) && (s.msg->getFlags() & MESSAGE_1ST_PART))){ + EventMessageSent(s.msg).process(); + delete s.msg; + snacICBM()->smsQueue.erase(snacICBM()->smsQueue.begin()); + continue; + } + SMSMessage *sms = static_cast(s.msg); + QString text = s.text; + QString part = getPart(text, MAX_SMS_LEN_LATIN1); + if (!isLatin(part)){ + text = s.text; + part = getPart(text, MAX_SMS_LEN_UNICODE); + } + s.text = text; + s.part = part; + + QString nmb = "+"; + QString phone = sms->getPhone(); + for (int i = 0; i < (int)(phone.length()); i++){ + QChar c = phone[i]; + if ((c >= '0') && (c <= '9')) + nmb += c; + } + XmlBranch xmltree("icq_sms_message"); + xmltree.pushnode(new XmlLeaf("destination",nmb.toUtf8().data())); + xmltree.pushnode(new XmlLeaf("text",part.toUtf8().data())); + xmltree.pushnode(new XmlLeaf("codepage","1252")); + xmltree.pushnode(new XmlLeaf("encoding","utf8")); + xmltree.pushnode(new XmlLeaf("senders_UIN",QString::number(data.owner.Uin.toULong()).toLatin1().data())); + xmltree.pushnode(new XmlLeaf("senders_name","")); + xmltree.pushnode(new XmlLeaf("delivery_receipt","Yes")); + + // ToDo: replace time_t & tm with QDateTime + char timestr[30]; + time_t t = time(NULL); + struct tm *tm; + tm = gmtime(&t); + snprintf(timestr, sizeof(timestr), "%s, %02u %s %04u %02u:%02u:%02u GMT", + w_days[tm->tm_wday], tm->tm_mday, months[tm->tm_mon], tm->tm_year + 1900, + tm->tm_hour, tm->tm_min, tm->tm_sec); + xmltree.pushnode(new XmlLeaf("time",string(timestr))); + string msg = xmltree.toString(0); + + serverRequest(ICQ_SRVxREQ_MORE); + socket()->writeBuffer() << ICQ_SRVxREQ_SEND_SMS + << 0x00010016L << 0x00000000L << 0x00000000L + << 0x00000000L << 0x00000000L << (unsigned long)(msg.size()); + socket()->writeBuffer() << msg.c_str(); + sendServerRequest(); + varRequests.push_back(new SMSRequest(this, m_nMsgSequence)); + m_sendSmsId = m_nMsgSequence; + break; + } + return 0; +} + +void ICQClient::clearSMSQueue() +{ + for (list::iterator it = snacICBM()->smsQueue.begin(); it != snacICBM()->smsQueue.end(); ++it){ + it->msg->setError(I18N_NOOP("Client go offline")); + EventMessageSent(it->msg).process(); + delete it->msg; + } + snacICBM()->smsQueue.clear(); + m_sendSmsId = 0; +} + +void ICQClient::setChatGroup() +{ + if ((getState() != Connected) || (getRandomChatGroup() == getRandomChatGroupCurrent())) + return; + serverRequest(ICQ_SRVxREQ_MORE); + socket()->writeBuffer() << (unsigned short)ICQ_SRVxREQ_SET_CHAT_GROUP; + if (getRandomChatGroup()){ + socket()->writeBuffer().pack((unsigned short)getRandomChatGroup()); + socket()->writeBuffer() + << 0x00000310L + << 0x00000000L + << 0x00000000L + << 0x00000000L + << (char)4 + << (char)ICQ_TCP_VERSION + << 0x00000000L + << 0x00000050L + << 0x00000003L + << (unsigned short)0 + << (char)0; + }else{ + socket()->writeBuffer() << (unsigned short)0; + } + sendServerRequest(); + setRandomChatGroupCurrent(getRandomChatGroup()); +} + +class RandomChatRequest : public ServerRequest +{ +public: + RandomChatRequest(ICQClient *client, unsigned short id); +protected: + virtual void fail(unsigned short error_code); + bool answer(ICQBuffer &b, unsigned short nSubtype); + ICQClient *m_client; +}; + + +RandomChatRequest::RandomChatRequest(ICQClient *client, unsigned short id) + : ServerRequest(id) +{ + m_client = client; +} + +bool RandomChatRequest::answer(ICQBuffer &b, unsigned short) +{ + unsigned long uin; + b.unpack(uin); +// currently unhandled +// Event e(EventRandomChat, (void*)uin); +// e.process(); + return true; +} + +void RandomChatRequest::fail(unsigned short) +{ +// currently unhandled +// Event e(EventRandomChat, NULL); +// e.process(); +} + +void ICQClient::searchChat(unsigned short group) +{ + if (getState() != Connected){ +// currently unhandled +// Event e(EventRandomChat, NULL); +// e.process(); + return; + } + serverRequest(ICQ_SRVxREQ_MORE); + socket()->writeBuffer() << (unsigned short)ICQ_SRVxREQ_RANDOM_CHAT; + socket()->writeBuffer().pack(group); + sendServerRequest(); + varRequests.push_back(new RandomChatRequest(this, m_nMsgSequence)); +} diff --git a/plugins/icq/interestsinfo.cpp b/plugins/icq/interestsinfo.cpp new file mode 100644 index 0000000..6fc83a5 --- /dev/null +++ b/plugins/icq/interestsinfo.cpp @@ -0,0 +1,244 @@ +/*************************************************************************** + interestsinfo.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "interestsinfo.h" +#include "icqclient.h" +#include "contacts/contact.h" + +#include +#include + +using namespace SIM; + +InterestsInfo::InterestsInfo(QWidget *parent, ICQUserData *data, unsigned contact, ICQClient *client) : QWidget(parent) +{ + setupUi(this); + m_data = data; + m_client = client; + m_contact = contact; + if (m_data){ + edtBg1->setReadOnly(true); + edtBg2->setReadOnly(true); + edtBg3->setReadOnly(true); + edtBg4->setReadOnly(true); + disableWidget(cmbBg1); + disableWidget(cmbBg2); + disableWidget(cmbBg3); + disableWidget(cmbBg4); + }else{ + connect(cmbBg1, SIGNAL(activated(int)), this, SLOT(cmbChanged(int))); + connect(cmbBg2, SIGNAL(activated(int)), this, SLOT(cmbChanged(int))); + connect(cmbBg3, SIGNAL(activated(int)), this, SLOT(cmbChanged(int))); + connect(cmbBg4, SIGNAL(activated(int)), this, SLOT(cmbChanged(int))); + } + fill(); +} + +void InterestsInfo::apply() +{ +} + +void InterestsInfo::apply(Client *client, void *_data) +{ + if (client != m_client) + return; + ICQUserData *data = m_client->toICQUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + QString info[4]; + info[0] = getInfo(cmbBg1, edtBg1); + info[1] = getInfo(cmbBg2, edtBg2); + info[2] = getInfo(cmbBg3, edtBg3); + info[3] = getInfo(cmbBg4, edtBg4); + QString res; + for (unsigned i = 0; i < 4; i++){ + if (info[i].isEmpty()) + continue; + if (!res.isEmpty()) + res += ';'; + res += info[i]; + } + data->Interests.str() = res; +} + +bool InterestsInfo::processEvent(Event *e) +{ + if (e->type() == eEventContact){ + EventContact *ec = static_cast(e); + if(ec->action() != EventContact::eChanged) + return false; + Contact *contact = ec->contact(); + if (contact->clientData.have(m_data)) + fill(); + } + if ((e->type() == eEventClientChanged) && (m_data == 0)){ + EventClientChanged *ecc = static_cast(e); + if (ecc->client() == m_client) + fill(); + } + return false; +} + +static const ext_info interests[] = + { + { I18N_NOOP("Art"), 100 }, + { I18N_NOOP("Cars"), 101 }, + { I18N_NOOP("Celebrity Fans"), 102 }, + { I18N_NOOP("Collections"), 103 }, + { I18N_NOOP("Computers"), 104 }, + { I18N_NOOP("Culture & Literature"), 105 }, + { I18N_NOOP("Fitness"), 106 }, + { I18N_NOOP("Games"), 107 }, + { I18N_NOOP("Hobbies"), 108 }, + { I18N_NOOP("ICQ - Providing Help"), 109 }, + { I18N_NOOP("Internet"), 110 }, + { I18N_NOOP("Lifestyle"), 111 }, + { I18N_NOOP("Movies/TV"), 112 }, + { I18N_NOOP("Music"), 113 }, + { I18N_NOOP("Outdoor Activities"), 114 }, + { I18N_NOOP("Parenting"), 115 }, + { I18N_NOOP("Pets/Animals"), 116 }, + { I18N_NOOP("Religion"), 117 }, + { I18N_NOOP("Science/Technology"), 118 }, + { I18N_NOOP("Skills"), 119 }, + { I18N_NOOP("Sports"), 120 }, + { I18N_NOOP("Web Design"), 121 }, + { I18N_NOOP("Nature and Environment"), 122 }, + { I18N_NOOP("News & Media"), 123 }, + { I18N_NOOP("Government"), 124 }, + { I18N_NOOP("Business & Economy"), 125 }, + { I18N_NOOP("Mystics"), 126 }, + { I18N_NOOP("Travel"), 127 }, + { I18N_NOOP("Astronomy"), 128 }, + { I18N_NOOP("Space"), 129 }, + { I18N_NOOP("Clothing"), 130 }, + { I18N_NOOP("Parties"), 131 }, + { I18N_NOOP("Women"), 132 }, + { I18N_NOOP("Social science"), 133 }, + { I18N_NOOP("60's"), 134 }, + { I18N_NOOP("70's"), 135 }, + { I18N_NOOP("80's"), 136 }, + { I18N_NOOP("50's"), 137 }, + { I18N_NOOP("Finance and corporate"), 138 }, + { I18N_NOOP("Entertainment"), 139 }, + { I18N_NOOP("Consumer electronics"), 140 }, + { I18N_NOOP("Retail stores"), 141 }, + { I18N_NOOP("Health and beauty"), 142 }, + { I18N_NOOP("Media"), 143 }, + { I18N_NOOP("Household products"), 144 }, + { I18N_NOOP("Mail order catalog"), 145 }, + { I18N_NOOP("Business services"), 146 }, + { I18N_NOOP("Audio and visual"), 147 }, + { I18N_NOOP("Sporting and athletic"), 148 }, + { I18N_NOOP("Publishing"), 149 }, + { I18N_NOOP("Home automation"), 150 }, + { "", 0 } + }; + +const ext_info *p_interests = interests; + +void InterestsInfo::fill() +{ + ICQUserData *data = m_data; + if (data == NULL) data = &m_client->data.owner; + unsigned i = 0; + QString str = data->Interests.str(); + while (str.length()){ + QString info = getToken(str, ';', false); + QString n = getToken(info, ','); + unsigned short category = n.toUShort(); + switch (i){ + case 0: + edtBg1->setText(unquoteChars(info,";")); + initCombo(cmbBg1, category, interests); + break; + case 1: + edtBg2->setText(unquoteChars(info,";")); + initCombo(cmbBg2, category, interests); + break; + case 2: + edtBg3->setText(unquoteChars(info,";")); + initCombo(cmbBg3, category, interests); + break; + case 3: + edtBg4->setText(unquoteChars(info,";")); + initCombo(cmbBg4, category, interests); + break; + } + i++; + } + for (; i < 4; i++){ + switch (i){ + case 0: + initCombo(cmbBg1, 0, interests); + break; + case 1: + initCombo(cmbBg2, 0, interests); + break; + case 2: + initCombo(cmbBg3, 0, interests); + break; + case 3: + initCombo(cmbBg4, 0, interests); + break; + } + } + if (m_data == NULL) + cmbChanged(0); +} + +QString InterestsInfo::getInfo(QComboBox *cmb, QLineEdit *edt) +{ + unsigned n = getComboValue(cmb, interests); + if (n == 0) + return QString::null; + QString res = QString::number(n) + ','; + res += quoteChars(edt->text(), ";"); + return res; +} + +void InterestsInfo::cmbChanged(int) +{ + QComboBox *cmbs[4] = { cmbBg1, cmbBg2, cmbBg3, cmbBg4 }; + QLineEdit *edts[4] = { edtBg1, edtBg2, edtBg3, edtBg4 }; + unsigned n = 0; + for (unsigned i = 0; i < 4; i++){ + unsigned short value = getComboValue(cmbs[i], interests); + if (value){ + if (i != n){ + cmbs[n]->setEnabled(true); + edts[n]->setEnabled(true); + initCombo(cmbs[n], value, interests, true); + edts[n]->setText(edts[i]->text()); + } + edts[n]->setEnabled(true); + edts[n]->setReadOnly(false); + n++; + } + } + if (n >= 4) + return; + cmbs[n]->setEnabled(true); + disableWidget(edts[n]); + cmbs[n]->setCurrentIndex(0); + edts[n]->setText(QString::null); + for (n++; n < 4; n++){ + disableWidget(cmbs[n]); + disableWidget(edts[n]); + initCombo(cmbs[n], 0, interests, true); + edts[n]->setText(QString::null); + } +} + diff --git a/plugins/icq/interestsinfo.h b/plugins/icq/interestsinfo.h new file mode 100644 index 0000000..9a01b70 --- /dev/null +++ b/plugins/icq/interestsinfo.h @@ -0,0 +1,46 @@ +/*************************************************************************** + interestsinfo.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _INTERESTSINFO_H +#define _INTERESTSINFO_H + +#include "event.h" +#include "ui_interestsinfobase.h" + +class ICQClient; +struct ICQUserData; + +class InterestsInfo : public QWidget, public Ui::InterestsInfoBase, public SIM::EventReceiver +{ + Q_OBJECT +public: + InterestsInfo(QWidget *parent, ICQUserData *data, unsigned contact, ICQClient *client); +public slots: + void apply(); + void apply(SIM::Client*, void*); + void cmbChanged(int); +protected: + virtual bool processEvent(SIM::Event *e); + void fill(); + QString getInfo(QComboBox *cmb, QLineEdit *edt); + ICQUserData *m_data; + unsigned m_contact; + ICQClient *m_client; +}; + +#endif + diff --git a/plugins/icq/interestsinfobase.ui b/plugins/icq/interestsinfobase.ui new file mode 100644 index 0000000..e555872 --- /dev/null +++ b/plugins/icq/interestsinfobase.ui @@ -0,0 +1,129 @@ + + + + + InterestsInfoBase + + + + 0 + 0 + 398 + 266 + + + + Form2 + + + + 11 + + + 6 + + + + + + &Interests + + + + 11 + + + 6 + + + + + + + + 0 + + + 6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Vertical + + + + + + + + + + + + QWidget + QWidget +
QWidget
+ + -1 + -1 + + 0 + + 5 + 5 + + image0 +
+
+ + cmbBg1 + edtBg1 + cmbBg2 + edtBg2 + cmbBg3 + edtBg3 + cmbBg4 + edtBg4 + + + + 789c6dd2c10ac2300c00d07bbf2234b7229d1be245fc04c5a3201e4615f430059d0711ff5ddb2e6bb236ec90eed134cb5a19d8ef36602af5ecdbfeeac05dda0798d3abebde87e3faa374d3807fa0d633a52d38d8de6f679fe33fc776e196f53cd010188256a3600a292882096246517815ca99884606e18044a3a40d91824820924265a7923a2e8bcd05f33db1173e002913175f2a6be6d3294871a2d95fa00e8a94ee017b69d339d90df1e77c57ea072ede6758 + + +
diff --git a/plugins/icq/moreinfo.cpp b/plugins/icq/moreinfo.cpp new file mode 100644 index 0000000..7ba1f51 --- /dev/null +++ b/plugins/icq/moreinfo.cpp @@ -0,0 +1,258 @@ +/*************************************************************************** + moreinfo.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "icons.h" +#include "moreinfo.h" +#include "icqclient.h" + +#include "contacts/contact.h" +#include "simgui/datepicker.h" + +#include +#include +#include +#include +#include + +using namespace SIM; + +MoreInfo::MoreInfo(QWidget *parent, ICQUserData *data, unsigned contact, ICQClient *client) : QWidget(parent) +{ + setupUi(this); + m_data = data; + m_client = client; + m_contact = contact; + btnHomePage->setIcon(Icon("home")); + connect(btnHomePage, SIGNAL(clicked()), this, SLOT(goUrl())); + spnAge->setSpecialValueText(" "); + spnAge->setRange(0, 100); + connect(cmbLang1, SIGNAL(activated(int)), this, SLOT(setLang(int))); + connect(cmbLang2, SIGNAL(activated(int)), this, SLOT(setLang(int))); + connect(cmbLang3, SIGNAL(activated(int)), this, SLOT(setLang(int))); + connect(edtDate, SIGNAL(changed()), this, SLOT(birthDayChanged())); + if (m_data){ + disableWidget(spnAge); + edtHomePage->setReadOnly(true); + disableWidget(cmbGender); + disableWidget(edtDate); + disableWidget(cmbLang1); + disableWidget(cmbLang2); + disableWidget(cmbLang3); + }else{ + connect(edtHomePage, SIGNAL(textChanged(const QString&)), this, SLOT(urlChanged(const QString&))); + } + fill(); +} + +void MoreInfo::apply() +{ +} + +bool MoreInfo::processEvent(Event *e) +{ + if (e->type() == eEventContact){ + EventContact *ec = static_cast(e); + if(ec->action() != EventContact::eChanged) + return false; + Contact *contact = ec->contact(); + if (contact->clientData.have(m_data)) + fill(); + } else + if ((e->type() == eEventClientChanged) && (m_data == 0)){ + EventClientChanged *ecc = static_cast(e); + if (ecc->client() == m_client) + fill(); + } + return false; +} + +const ext_info genders[] = + { + { I18N_NOOP("Female"), 1 }, + { I18N_NOOP("Male"), 2 }, + { "", 0 } + }; + +const ext_info *p_genders = genders; + +const ext_info languages[] = + { + {I18N_NOOP("Arabic"), 1}, + {I18N_NOOP("Bhojpuri"), 2}, + {I18N_NOOP("Bulgarian"), 3}, + {I18N_NOOP("Burmese"), 4}, + {I18N_NOOP("Cantonese"), 5}, + {I18N_NOOP("Catalan"), 6}, + {I18N_NOOP("Chinese"), 7}, + {I18N_NOOP("Croatian"), 8}, + {I18N_NOOP("Czech"), 9}, + {I18N_NOOP("Danish"), 10}, + {I18N_NOOP("Dutch"), 11}, + {I18N_NOOP("English"), 12}, + {I18N_NOOP("Esperanto"), 13}, + {I18N_NOOP("Estonian"), 14}, + {I18N_NOOP("Farsi"), 15}, + {I18N_NOOP("Finnish"), 16}, + {I18N_NOOP("French"), 17}, + {I18N_NOOP("Gaelic"), 18}, + {I18N_NOOP("German"), 19}, + {I18N_NOOP("Greek"), 20}, + {I18N_NOOP("Hebrew"), 21}, + {I18N_NOOP("Hindi"), 22}, + {I18N_NOOP("Hungarian"), 23}, + {I18N_NOOP("Icelandic"), 24}, + {I18N_NOOP("Indonesian"), 25}, + {I18N_NOOP("Italian"), 26}, + {I18N_NOOP("Japanese"), 27}, + {I18N_NOOP("Khmer"), 28}, + {I18N_NOOP("Korean"), 29}, + {I18N_NOOP("Lao"), 30}, + {I18N_NOOP("Latvian"), 31}, + {I18N_NOOP("Lithuanian"), 32}, + {I18N_NOOP("Malay"), 33}, + {I18N_NOOP("Norwegian"), 34}, + {I18N_NOOP("Polish"), 35}, + {I18N_NOOP("Portuguese"), 36}, + {I18N_NOOP("Romanian"), 37}, + {I18N_NOOP("Russian"), 38}, + {I18N_NOOP("Serbian"), 39}, + {I18N_NOOP("Slovak"), 40}, + {I18N_NOOP("Slovenian"), 41}, + {I18N_NOOP("Somali"), 42}, + {I18N_NOOP("Spanish"), 43}, + {I18N_NOOP("Swahili"), 44}, + {I18N_NOOP("Swedish"), 45}, + {I18N_NOOP("Tagalog"), 46}, + {I18N_NOOP("Tatar"), 47}, + {I18N_NOOP("Thai"), 48}, + {I18N_NOOP("Turkish"), 49}, + {I18N_NOOP("Ukrainian"), 50}, + {I18N_NOOP("Urdu"), 51}, + {I18N_NOOP("Vietnamese"), 52}, + {I18N_NOOP("Yiddish"), 53}, + {I18N_NOOP("Yoruba"), 54}, + {I18N_NOOP("Afrikaans"), 55}, + {I18N_NOOP("Persian"), 57}, + {I18N_NOOP("Albanian"), 58}, + {I18N_NOOP("Armenian"), 59}, + {I18N_NOOP("Kyrgyz"), 123}, + {I18N_NOOP("Maltese"), 125}, + {"", 0} + }; + +const ext_info *p_languages = languages; + +void MoreInfo::fill() +{ + ICQUserData *data = m_data; + if (data == NULL) + data = &m_client->data.owner; + edtHomePage->setText(data->Homepage.str()); + initCombo(cmbGender, data->Gender.toULong(), genders); + if (spnAge->text() == "0") + spnAge->setSpecialValueText(QString::null); + + if (data->BirthYear.toULong()>0 && data->BirthMonth.toULong()>0 && data->BirthDay.toULong()>0) { + QDate date; + date.setYMD(data->BirthYear.toULong(), data->BirthMonth.toULong(), data->BirthDay.toULong()); + edtDate->setDate(date); + birthDayChanged(); + } + + unsigned l = data->Language.toULong(); + char l1 = (char)(l & 0xFF); + l = l >> 8; + char l2 = (char)(l & 0xFF); + l = l >> 8; + char l3 = (char)(l & 0xFF); + initCombo(cmbLang1, l1, languages); + initCombo(cmbLang2, l2, languages); + initCombo(cmbLang3, l3, languages); + setLang(0); + urlChanged(edtHomePage->text()); +} + +void MoreInfo::birthDayChanged() +{ + int day = edtDate->getDate().day(); + int month = edtDate->getDate().month(); + int year = edtDate->getDate().year(); + if (year){ + QDate now = QDate::currentDate(); + int age = now.year() - year; + if ((now.month() < month) || ((now.month() == month) && (now.day() < day))) age--; + if (age < 100){ + spnAge->setValue(age); + }else{ + spnAge->setValue(0); + } + }else{ + spnAge->setValue(0); + } +} + +void MoreInfo::goUrl() +{ + QString url = edtHomePage->text(); + if (url.isEmpty()) + return; + if(!url.startsWith("http://")) + url = "http://" + url; + EventGoURL e(url); + e.process(); +} + +void MoreInfo::setLang(int) +{ + unsigned l[3], sl[3]; + l[0] = cmbLang1->currentIndex(); + l[1] = cmbLang2->currentIndex(); + l[2] = cmbLang3->currentIndex(); + unsigned j = 0; + for (unsigned i = 0; i < 3; i++) + if (l[i]) + sl[j++] = l[i]; + for (; j < 3; j++) + sl[j] = 0; + cmbLang1->setCurrentIndex(sl[0]); + cmbLang2->setCurrentIndex(sl[1]); + cmbLang3->setCurrentIndex(sl[2]); + cmbLang2->setEnabled(sl[0] != 0); + cmbLang3->setEnabled(sl[1] != 0); +} + +void MoreInfo::apply(Client *client, void *_data) +{ + if (client != m_client) + return; + ICQUserData *data = m_client->toICQUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + data->Homepage.str() = edtHomePage->text(); + data->Gender.asULong() = getComboValue(cmbGender, genders); + data->BirthMonth.asULong() = edtDate->getDate().month(); + data->BirthDay.asULong() = edtDate->getDate().day(); + data->BirthYear.asULong() = edtDate->getDate().year(); + unsigned l1 = getComboValue(cmbLang1, languages); + unsigned l2 = getComboValue(cmbLang2, languages); + unsigned l3 = getComboValue(cmbLang3, languages); + data->Language.asULong() = (l3 << 16) | (l2 << 8) | l1; +} + +void MoreInfo::urlChanged(const QString &text) +{ + btnHomePage->setEnabled(!text.isEmpty()); +} + diff --git a/plugins/icq/moreinfo.h b/plugins/icq/moreinfo.h new file mode 100644 index 0000000..0202565 --- /dev/null +++ b/plugins/icq/moreinfo.h @@ -0,0 +1,48 @@ +/*************************************************************************** + moreinfo.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _MOREINFO_H +#define _MOREINFO_H + +#include "ui_moreinfobase.h" + +#include "event.h" +class ICQClient; +struct ICQUserData; + +class MoreInfo : public QWidget, public Ui::MoreInfoBase, public SIM::EventReceiver +{ + Q_OBJECT +public: + MoreInfo(QWidget *parent, ICQUserData *data, unsigned contact, ICQClient *client); +public slots: + void apply(); + void apply(SIM::Client*, void*); + void goUrl(); + void urlChanged(const QString&); + void setLang(int); + void birthDayChanged(); +protected: + virtual bool processEvent(SIM::Event *e); + void fill(); + ICQUserData *m_data; + unsigned m_contact; + ICQClient *m_client; +}; + +#endif + diff --git a/plugins/icq/moreinfobase.ui b/plugins/icq/moreinfobase.ui new file mode 100644 index 0000000..ee95ef6 --- /dev/null +++ b/plugins/icq/moreinfobase.ui @@ -0,0 +1,335 @@ + + + + + MoreInfoBase + + + + 0 + 0 + 352 + 246 + + + + Form3 + + + + 11 + + + 6 + + + + + + &More info + + + + 11 + + + 6 + + + + + + 0 + 5 + + + + QFrame::HLine + + + QFrame::Sunken + + + QFrame::HLine + + + + + + + 0 + + + 6 + + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Horizontal + + + + + + + Age: + + + false + + + + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Horizontal + + + + + + + + + Homepage: + + + Qt::AlignVCenter|Qt::AlignRight + + + false + + + + + + + 0 + + + 6 + + + + + + + + + 0 + 0 + + + + + 22 + 22 + + + + + + + + + + + + + Gender: + + + Qt::AlignVCenter|Qt::AlignRight + + + false + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Vertical + + + + + + + 0 + + + 6 + + + + + Birth date: + + + false + + + + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Horizontal + + + + + + + + + + &Languages + + + + 11 + + + 6 + + + + + Spoken languages: + + + false + + + + + + + + + + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Vertical + + + + + + + + + + + + QWidget + QWidget +
QWidget
+ + -1 + -1 + + 0 + + 5 + 5 + + image0 + + text + +
+ + DatePicker + QWidget +
simgui/datepicker.h
+ + -1 + -1 + + 0 + + 0 + 1 + + image1 +
+
+ + edtHomePage + btnHomePage + cmbGender + spnAge + TabWidget2 + cmbLang1 + cmbLang2 + cmbLang3 + + + + 789c6dd2c10ac2300c00d07bbf2234b7229d1be245fc04c5a3201e4615f430059d0711ff5ddb2e6bb236ec90eed134cb5a19d8ef36602af5ecdbfeeac05dda0798d3abebde87e3faa374d3807fa0d633a52d38d8de6f679fe33fc776e196f53cd010188256a3600a292882096246517815ca99884606e18044a3a40d91824820924265a7923a2e8bcd05f33db1173e002913175f2a6be6d3294871a2d95fa00e8a94ee017b69d339d90df1e77c57ea072ede6758 + + + 789c6dd2c10ac2300c00d07bbf2234b7229d1ddec44f503c0ae2a154410f53d0ed20e2bf6bdb656dd6861dd23d9a66591b0587fd1654235ebded6f0edcd53e419d87ae7b1f4f9b8f906d0bfe012317426a70b07bdc2f3ec77f8ed6b89559061a0343d06a124cc105596482585094bc0ae599b04646c9018926491b2205e140c485cace25755c175d0a967b622ff900b8cc9c7d29af594ea722d589167f813aa852ba07d94b9dce296e883fe7bb163f23896753 + + +
diff --git a/plugins/icq/pastinfo.cpp b/plugins/icq/pastinfo.cpp new file mode 100644 index 0000000..96d126e --- /dev/null +++ b/plugins/icq/pastinfo.cpp @@ -0,0 +1,311 @@ +/*************************************************************************** + pastinfo.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "pastinfo.h" +#include "icqclient.h" +#include "contacts/contact.h" + +#include +#include + +using namespace SIM; + +PastInfo::PastInfo(QWidget *parent, ICQUserData *data, unsigned contact, ICQClient *client) : QWidget(parent) +{ + setupUi(this); + m_data = data; + m_client = client; + m_contact = contact; + if (m_data){ + edtBg1->setReadOnly(true); + edtBg2->setReadOnly(true); + edtBg3->setReadOnly(true); + edtAf1->setReadOnly(true); + edtAf2->setReadOnly(true); + edtAf3->setReadOnly(true); + disableWidget(cmbBg1); + disableWidget(cmbBg2); + disableWidget(cmbBg3); + disableWidget(cmbAf1); + disableWidget(cmbAf2); + disableWidget(cmbAf3); + }else{ + connect(cmbBg1, SIGNAL(activated(int)), this, SLOT(cmbBgChanged(int))); + connect(cmbBg2, SIGNAL(activated(int)), this, SLOT(cmbBgChanged(int))); + connect(cmbBg3, SIGNAL(activated(int)), this, SLOT(cmbBgChanged(int))); + connect(cmbAf1, SIGNAL(activated(int)), this, SLOT(cmbAfChanged(int))); + connect(cmbAf2, SIGNAL(activated(int)), this, SLOT(cmbAfChanged(int))); + connect(cmbAf3, SIGNAL(activated(int)), this, SLOT(cmbAfChanged(int))); + } + fill(); +} + +void PastInfo::apply() +{ +} + +bool PastInfo::processEvent(Event *e) +{ + if (e->type() == eEventContact){ + EventContact *ec = static_cast(e); + if(ec->action() != EventContact::eChanged) + return false; + Contact *contact = ec->contact(); + if (contact->clientData.have(m_data)) + fill(); + } else + if ((e->type() == eEventClientChanged) && (m_data == 0)){ + EventClientChanged *ecc = static_cast(e); + if (ecc->client() == m_client) + fill(); + } + return false; +} + +static const ext_info pasts[] = + { + { I18N_NOOP("Elementary School"), 300 }, + { I18N_NOOP("High School"), 301 }, + { I18N_NOOP("College"), 302 }, + { I18N_NOOP("University"), 303 }, + { I18N_NOOP("Military"), 304 }, + { I18N_NOOP("Past Work Place"), 305 }, + { I18N_NOOP("Past Organization"), 306 }, + { I18N_NOOP("Other"), 399 }, + { "", 0 } + }; + +const ext_info *p_pasts = pasts; + +static const ext_info affilations[] = + { + { I18N_NOOP("Alumni Org."), 200 }, + { I18N_NOOP("Charity Org."), 201 }, + { I18N_NOOP("Club/Social Org."), 202 }, + { I18N_NOOP("Community Org."), 203 }, + { I18N_NOOP("Cultural Org."), 204 }, + { I18N_NOOP("Fan Clubs"), 205 }, + { I18N_NOOP("Fraternity/Sorority"), 206 }, + { I18N_NOOP("Hobbyists Org."), 207 }, + { I18N_NOOP("International Org."), 208 }, + { I18N_NOOP("Nature and Environment Org."), 209 }, + { I18N_NOOP("Professional Org."), 210 }, + { I18N_NOOP("Scientific/Technical Org."), 211 }, + { I18N_NOOP("Self Improvement Group"), 212 }, + { I18N_NOOP("Spiritual/Religious Org."), 213 }, + { I18N_NOOP("Sports Org."), 214 }, + { I18N_NOOP("Support Org."), 215 }, + { I18N_NOOP("Trade and Business Org."), 216 }, + { I18N_NOOP("Union"), 217 }, + { I18N_NOOP("Volunteer Org."), 218 }, + { I18N_NOOP("Other"), 299 }, + { "", 0 } + }; + +const ext_info *p_affilations = affilations; + +void PastInfo::fill() +{ + ICQUserData *data = m_data; + if (data == NULL) + data = &m_client->data.owner; + unsigned i = 0; + QString str = data->Backgrounds.str(); + while (str.length()){ + QString info = getToken(str, ';', false); + QString n = getToken(info, ','); + unsigned short category = n.toUShort(); + switch (i){ + case 0: + edtBg1->setText(info); + initCombo(cmbBg1, category, pasts); + break; + case 1: + edtBg2->setText(info); + initCombo(cmbBg2, category, pasts); + break; + case 2: + edtBg3->setText(info); + initCombo(cmbBg3, category, pasts); + break; + } + i++; + } + for (; i < 4; i++){ + switch (i){ + case 0: + initCombo(cmbBg1, 0, pasts); + break; + case 1: + initCombo(cmbBg2, 0, pasts); + break; + case 2: + initCombo(cmbBg3, 0, pasts); + break; + } + } + i = 0; + str = data->Affilations.str(); + while (str.length()){ + QString info = getToken(str, ';', false); + QString n = getToken(info, ','); + unsigned short category = n.toUShort(); + switch (i){ + case 0: + edtAf1->setText(info); + initCombo(cmbAf1, category, affilations); + break; + case 1: + edtAf2->setText(info); + initCombo(cmbAf2, category, affilations); + break; + case 2: + edtAf3->setText(info); + initCombo(cmbAf3, category, affilations); + break; + } + i++; + } + for (; i < 4; i++){ + switch (i){ + case 0: + initCombo(cmbAf1, 0, affilations); + break; + case 1: + initCombo(cmbAf2, 0, affilations); + break; + case 2: + initCombo(cmbAf3, 0, affilations); + break; + } + } + if (m_data == NULL){ + cmbBgChanged(0); + cmbAfChanged(0); + } +} + +void PastInfo::cmbBgChanged(int) +{ + QComboBox *cmbs[3] = { cmbBg1, cmbBg2, cmbBg3 }; + QLineEdit *edts[3] = { edtBg1, edtBg2, edtBg3 }; + unsigned n = 0; + for (unsigned i = 0; i < 3; i++){ + unsigned short value = getComboValue(cmbs[i], pasts); + if (value){ + if (i != n){ + cmbs[n]->setEnabled(true); + edts[n]->setEnabled(true); + initCombo(cmbs[n], value, pasts, true); + edts[n]->setText(edts[i]->text()); + } + edts[n]->setEnabled(true); + edts[n]->setReadOnly(false); + n++; + } + } + if (n >= 3) + return; + cmbs[n]->setEnabled(true); + disableWidget(edts[n]); + cmbs[n]->setCurrentIndex(0); + edts[n]->setText(QString::null); + for (n++; n < 3; n++){ + disableWidget(cmbs[n]); + disableWidget(edts[n]); + initCombo(cmbs[n], 0, pasts, true); + edts[n]->setText(QString::null); + } +} + +void PastInfo::cmbAfChanged(int) +{ + QComboBox *cmbs[3] = { cmbAf1, cmbAf2, cmbAf3 }; + QLineEdit *edts[3] = { edtAf1, edtAf2, edtAf3 }; + unsigned n = 0; + for (unsigned i = 0; i < 3; i++){ + unsigned short value = getComboValue(cmbs[i], affilations); + if (value){ + if (i != n){ + cmbs[n]->setEnabled(true); + edts[n]->setEnabled(true); + initCombo(cmbs[n], value, affilations, true); + edts[n]->setText(edts[i]->text()); + } + edts[n]->setEnabled(true); + edts[n]->setReadOnly(false); + n++; + } + } + if (n >= 3) + return; + cmbs[n]->setEnabled(true); + disableWidget(edts[n]); + cmbs[n]->setCurrentIndex(0); + edts[n]->setText(QString::null); + for (n++; n < 3; n++){ + disableWidget(cmbs[n]); + disableWidget(edts[n]); + initCombo(cmbs[n], 0, affilations, true); + edts[n]->setText(QString::null); + } +} + + +void PastInfo::apply(Client *client, void *_data) +{ + if (client != m_client) + return; + ICQUserData *data = m_client->toICQUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + QString bg[3]; + bg[0] = getInfo(cmbBg1, edtBg1, pasts); + bg[1] = getInfo(cmbBg2, edtBg2, pasts); + bg[2] = getInfo(cmbBg3, edtBg3, pasts); + QString res; + for (unsigned i = 0; i < 3; i++){ + if (bg[i].isEmpty()) + continue; + if (!res.isEmpty()) + res += ';'; + res += bg[i]; + } + data->Backgrounds.str() = res; + res = QString::null; + QString af[3]; + af[0] = getInfo(cmbAf1, edtAf1, affilations); + af[1] = getInfo(cmbAf2, edtAf2, affilations); + af[2] = getInfo(cmbAf3, edtAf3, affilations); + for (unsigned i = 0; i < 3; i++){ + if (af[i].isEmpty()) + continue; + if (!res.isEmpty()) + res += ';'; + res += af[i]; + } + data->Affilations.str() = res; +} + +QString PastInfo::getInfo(QComboBox *cmb, QLineEdit *edt, const ext_info *info) +{ + unsigned n = getComboValue(cmb, info); + if (n == 0) + return QString::null; + QString res = QString::number(n) + ','; + res += quoteChars(edt->text(), ",;"); + return res; +} + diff --git a/plugins/icq/pastinfo.h b/plugins/icq/pastinfo.h new file mode 100644 index 0000000..db6b11b --- /dev/null +++ b/plugins/icq/pastinfo.h @@ -0,0 +1,49 @@ +/*************************************************************************** + pastinfo.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _PASTINFO_H +#define _PASTINFO_H + +#include "country.h" +#include "event.h" + +#include "ui_pastinfobase.h" + +class ICQClient; +struct ICQUserData; + +class PastInfo : public QWidget, public Ui::PastInfoBase, public SIM::EventReceiver +{ + Q_OBJECT +public: + PastInfo(QWidget *parent, ICQUserData *data, unsigned contact, ICQClient *client); +public slots: + void apply(); + void apply(SIM::Client*, void*); + void cmbAfChanged(int); + void cmbBgChanged(int); +protected: + virtual bool processEvent(SIM::Event *e); + QString getInfo(QComboBox *cmb, QLineEdit *edt, const SIM::ext_info*); + void fill(); + ICQUserData *m_data; + unsigned m_contact; + ICQClient *m_client; +}; + +#endif + diff --git a/plugins/icq/pastinfobase.ui b/plugins/icq/pastinfobase.ui new file mode 100644 index 0000000..c41c09e --- /dev/null +++ b/plugins/icq/pastinfobase.ui @@ -0,0 +1,185 @@ + + + + + PastInfoBase + + + + 0 + 0 + 316 + 263 + + + + Form1 + + + + 11 + + + 6 + + + + + + A&ffilation + + + + 11 + + + 6 + + + + + Organization, Affiliation, Group: + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Vertical + + + + + + + + &Background + + + + 11 + + + 6 + + + + + Past background: + + + false + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Vertical + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + QWidget + QWidget +
QWidget
+ + -1 + -1 + + 0 + + 5 + 5 + + image0 + + text + +
+
+ + cmbAf1 + edtAf1 + cmbAf2 + edtAf2 + cmbAf3 + edtAf3 + TabWidget2 + cmbBg1 + edtBg1 + cmbBg2 + edtBg2 + cmbBg3 + edtBg3 + + + + 789c6dd2c10ac2300c00d07bbf2234b7229d1be245fc04c5a3201e4615f430059d0711ff5ddb2e6bb236ec90eed134cb5a19d8ef36602af5ecdbfeeac05dda0798d3abebde87e3faa374d3807fa0d633a52d38d8de6f679fe33fc776e196f53cd010188256a3600a292882096246517815ca99884606e18044a3a40d91824820924265a7923a2e8bcd05f33db1173e002913175f2a6be6d3294871a2d95fa00e8a94ee017b69d339d90df1e77c57ea072ede6758 + + +
diff --git a/plugins/icq/polling.cpp b/plugins/icq/polling.cpp new file mode 100644 index 0000000..712104b --- /dev/null +++ b/plugins/icq/polling.cpp @@ -0,0 +1,401 @@ +/*************************************************************************** + polling.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include + +#include + +#include "fetch.h" +#include "log.h" + +#include "icqclient.h" +#include "polling.h" + +using namespace std; +using namespace SIM; + +const unsigned short HTTP_PROXY_VERSION = 0x0443; + +const unsigned short HTTP_PROXY_HELLO = 2; +const unsigned short HTTP_PROXY_LOGIN = 3; +const unsigned short HTTP_PROXY_UNK1 = 4; +const unsigned short HTTP_PROXY_FLAP = 5; +const unsigned short HTTP_PROXY_CONNECT = 6; +const unsigned short HTTP_PROXY_UNK2 = 7; + +class HttpPacket +{ + COPY_RESTRICTED(HttpPacket) +public: + HttpPacket(const char *data, unsigned short size, unsigned short type, unsigned long nSock); + ~HttpPacket(); + char *data; + unsigned short size; + unsigned short type; + unsigned long nSock; +}; + +HttpPacket::HttpPacket(const char *_data, unsigned short _size, unsigned short _type, unsigned long _nSock) +{ + size = _size; + type = _type; + nSock = _nSock; + data = NULL; + if (size){ + data = new char[size]; + memcpy(data, _data, size); + } +} + +HttpPacket::~HttpPacket() +{ + if (data) delete[] data; +} + +// ___________________________________________________________________________________ + +static char ANSWER_ERROR[] = "Bad answer"; + +class HttpRequest : public FetchClient +{ +public: + HttpRequest(HttpPool *pool); + void send(); +protected: + virtual bool done(unsigned code, Buffer &data, const QString &headers); + virtual HttpPacket *packet() = 0; + virtual QString url() = 0; + virtual void data_ready(ICQBuffer*) = 0; + HttpPool *m_pool; +}; + +HttpRequest::HttpRequest(HttpPool *pool) +{ + m_pool = pool; +} + +void HttpRequest::send() +{ + HttpPacket *p = packet(); + ICQBuffer *postData = NULL; + if (p){ + postData = new ICQBuffer; + unsigned short len = (unsigned short)(p->size + 12); + *postData + << len + << HTTP_PROXY_VERSION + << p->type + << 0x00000000L + << p->nSock; + if (p->size) + postData->pack(p->data, p->size); + m_pool->queue.remove(p); + delete p; + } + char headers[] = "Cache-control: no-store, no-cache\n" + "Pragma: no-cache"; + fetch(url(), headers, postData); +} + +bool HttpRequest::done(unsigned code, Buffer &data, const QString &) +{ + if (code != 200){ + log(L_DEBUG, "Res: %u %s", code, qPrintable(url())); + m_pool->error(ANSWER_ERROR); + return false; + } + ICQBuffer d(data); + data_ready(&d); + return true; +} + +unsigned long HttpPool::localHost() +{ + return 0; +} + +void HttpPool::pause(unsigned time) +{ + QTimer::singleShot(time * 1000, this, SLOT(timeout())); +} + +void HttpPool::timeout() +{ + if (notify) + notify->write_ready(); +} + +// ______________________________________________________________________________________ + +class HelloRequest : public HttpRequest +{ +public: + HelloRequest(HttpPool *poll, bool bAIM); +protected: + virtual HttpPacket *packet(); + virtual QString url(); + virtual void data_ready(ICQBuffer*); + bool m_bAIM; +}; + +HelloRequest::HelloRequest(HttpPool *poll, bool bAIM) + : HttpRequest(poll) +{ + m_bAIM = bAIM; + send(); +} + +HttpPacket *HelloRequest::packet() +{ + return NULL; +} + +QString HelloRequest::url() +{ + return m_bAIM ? "http://aimhttp.oscar.aol.com/hello" : "http://http.proxy.icq.com/hello"; +} + +void HelloRequest::data_ready(ICQBuffer *bIn) +{ + m_pool->hello = NULL; + bIn->incReadPos(12); + unsigned long SID[4]; + (*bIn) >> SID[0] >> SID[1] >> SID[2] >> SID[3]; + char b[34]; + snprintf(b, sizeof(b), "%08lx%08lx%08lx%08lx", SID[0], SID[1], SID[2], SID[3]); + m_pool->sid = b; + bIn->unpackStr(m_pool->m_host); + m_pool->request(); +} + +// ______________________________________________________________________________________ + +class MonitorRequest : public HttpRequest +{ +public: + MonitorRequest(HttpPool *pool); +protected: + virtual HttpPacket *packet(); + virtual QString url(); + virtual void data_ready(ICQBuffer*); +}; + +MonitorRequest::MonitorRequest(HttpPool *pool) + : HttpRequest(pool) +{ + send(); +} + +HttpPacket *MonitorRequest::packet() +{ + return NULL; +} + +QString MonitorRequest::url() +{ + QString sURL; + sURL = "http://"; + sURL += m_pool->m_host; + sURL += "/monitor?sid="; + sURL += m_pool->sid; + return sURL; +} + +void MonitorRequest::data_ready(ICQBuffer *bIn) +{ + m_pool->monitor = NULL; + m_pool->readn = 0; + while (bIn->readPos() < (unsigned)bIn->size()){ + unsigned short len, ver, type; + (*bIn) >> len >> ver >> type; + bIn->incReadPos(8); + len -= 12; + if (len > (bIn->size() - bIn->readPos())){ + m_pool->error(ANSWER_ERROR); + return; + } + if (ver != HTTP_PROXY_VERSION){ + m_pool->error(ANSWER_ERROR); + return; + } + switch (type){ + case HTTP_PROXY_FLAP: + if (len){ + unsigned short nSock; + bIn->incReadPos(-2); + *bIn >> nSock; + if (nSock == m_pool->nSock){ + char *data = bIn->data(bIn->readPos()); + m_pool->readData.pack(data, len); + m_pool->readn += len; + } + bIn->incReadPos(len); + } + break; + case HTTP_PROXY_UNK1: + case HTTP_PROXY_UNK2: + if (len) + bIn->incReadPos(len); + break; + default: + m_pool->error(ANSWER_ERROR); + return; + } + } + m_pool->request(); +} + +// ______________________________________________________________________________________ + +class PostRequest : public HttpRequest +{ +public: + PostRequest(HttpPool *proxy); +protected: + virtual HttpPacket *packet(); + virtual QString url(); + virtual void data_ready(ICQBuffer *b); +}; + +PostRequest::PostRequest(HttpPool *proxy) + : HttpRequest(proxy) +{ + send(); +} + +HttpPacket *PostRequest::packet() +{ + if (m_pool->queue.size()) + return m_pool->queue.front(); + return NULL; +} + +QString PostRequest::url() +{ + QString sURL; + sURL = "http://"; + sURL += m_pool->m_host; + sURL += "/data?sid="; + sURL += m_pool->sid; + sURL += "&seq="; + char b[15]; + snprintf(b, sizeof(b), "%u", ++m_pool->seq); + sURL += b; + return sURL; +} + +void PostRequest::data_ready(ICQBuffer*) +{ + m_pool->post = NULL; + m_pool->request(); +} + +// ______________________________________________________________________________________ + +HttpPool::HttpPool(bool bAIM) +{ + m_bAIM = bAIM; + hello = NULL; + monitor = NULL; + post = NULL; + state = None; + seq = 0; + readn = 0; + nSock = 0; +} + +HttpPool::~HttpPool() +{ + if (hello) delete hello; + if (monitor) delete monitor; + if (post) delete post; + for (list::iterator it = queue.begin(); it != queue.end(); ++it) + delete *it; +} + +int HttpPool::read(char *buf, unsigned size) +{ + unsigned tail = readData.size() - readData.readPos(); + if (size > tail) size = tail; + if (size == 0) return 0; + readData.unpack(buf, size); + if (readData.readPos() == (unsigned)readData.size()) + readData.init(0); + return size; +} + +void HttpPool::write(const char *buf, unsigned size) +{ + queue.push_back(new HttpPacket(buf, (unsigned short)size, HTTP_PROXY_FLAP, nSock)); + request(); +} + +void HttpPool::close() +{ + readData.init(0); +} + +void HttpPool::connect(const QString &host, unsigned short port) +{ + state = None; + ICQBuffer b; + unsigned short len = host.length(); + b << len << host.toLocal8Bit().data() << port; + nSock++; + queue.push_back(new HttpPacket(b.data(0), (unsigned short)(b.size()), HTTP_PROXY_LOGIN, nSock)); + if (sid.length()){ + unsigned char close_packet[] = { 0x2A, 0x04, 0x14, 0xAB, 0x00, 0x00 }; + queue.push_back(new HttpPacket((char*)close_packet, sizeof(close_packet), HTTP_PROXY_FLAP, 1)); + queue.push_back(new HttpPacket(NULL, 0, HTTP_PROXY_CONNECT, 1)); + } + request(); +} + +void HttpPool::request() +{ + if (sid.length() == 0){ + if (hello == NULL) + hello = new HelloRequest(this, m_bAIM); + return; + } + if (monitor == NULL) + monitor = new MonitorRequest(this); + if (queue.size() && (post == NULL)) + post = new PostRequest(this); + if (readn && notify){ + if (state == None){ + state = Connected; + notify->connect_ready(); + } + readn = 0; + notify->read_ready(); + } +} + +Socket *ICQClient::createSocket() +{ + m_bHTTP = getUseHTTP(); + if (getAutoHTTP()){ + m_bHTTP = m_bFirstTry; + if (!m_bFirstTry) + m_bFirstTry = true; + } + if (m_bHTTP) + return new HttpPool(m_bAIM); + return NULL; +} + diff --git a/plugins/icq/polling.h b/plugins/icq/polling.h new file mode 100644 index 0000000..8e64f72 --- /dev/null +++ b/plugins/icq/polling.h @@ -0,0 +1,78 @@ +/*************************************************************************** + polling.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _POLLING_H +#define _POLLING_H + +#include +#include "socket/socket.h" + +class HttpRequest; +class HttpPacket; + +class HttpPool : public QObject, public SIM::Socket +{ + Q_OBJECT +public: + HttpPool(bool bAIM); + ~HttpPool(); + virtual void connect(const QString &host, unsigned short port); + virtual int read(char *buf, unsigned size); + virtual void write(const char *buf, unsigned size); + virtual void close(); + virtual Mode mode() const { return Web; } + virtual bool isEncrypted(){ return false; } + virtual bool startEncryption(){ return false; } +protected slots: + void timeout(); +protected: + enum State + { + None, + Connected + }; + State state; + + QString sid; + QString m_host; + QString m_url; + + std::list queue; + unsigned seq; + unsigned readn; + Buffer readData; + + HttpRequest *hello; + HttpRequest *monitor; + HttpRequest *post; + + unsigned short nSock; + void request(); + virtual unsigned long localHost(); + virtual void pause(unsigned); + + bool m_bAIM; + + friend class HttpRequest; + friend class HelloRequest; + friend class MonitorRequest; + friend class PostRequest; +}; + + +#endif + diff --git a/plugins/icq/rtf.ll b/plugins/icq/rtf.ll new file mode 100644 index 0000000..141ba75 --- /dev/null +++ b/plugins/icq/rtf.ll @@ -0,0 +1,1044 @@ +%{ + /*************************************************************************** + rtf.ll - description + ------------------- + begin : Sun Mar 10 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + + /*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include + +#include +#include +#include + +#include + +#include "unquot.h" +#include "log.h" + +#include "icqclient.h" + +#define UP 1 +#define DOWN 2 +#define CMD 3 +#define TXT 4 +#define HEX 5 +#define IMG 6 +#define UNICODE_CHAR 7 +#define SKIP 8 +#define SLASH 9 +#define S_TXT 10 + +#define YY_NEVER_INTERACTIVE 1 +#define YY_ALWAYS_INTERACTIVE 0 +#define YY_MAIN 0 + +%} + +%option nounput +%option nostack +%option prefix="rtf" + +%% + +"{" { return UP; } +"}" { return DOWN; } +"\\"[\\\{\}] { return SLASH; } +"\\u"[0-9]{3,7}[ ]?"?" { return UNICODE_CHAR; } +"\\"[A-Za-z]+[0-9]*[ ]? { return CMD; } +"\\'"[0-9A-Fa-f][0-9A-Fa-f] { return HEX; } +"<##"[^>]+">" { return IMG; } +[^\\{}<]+ { return TXT; } +. { return TXT; } +%% + +using namespace std; +using namespace SIM; + +struct FontDef +{ + int charset; + QString taggedName; + QString nonTaggedName; +}; + +class RTF2HTML; + +enum TagEnum +{ + TAG_ALL = 0, + TAG_FONT_SIZE, + TAG_FONT_COLOR, + TAG_FONT_FAMILY, + TAG_BG_COLOR, + TAG_BOLD, + TAG_ITALIC, + TAG_UNDERLINE +}; + +class ParStyle +{ +public: + ParStyle() { dir = DirLTR; } + void clearFormatting(); + +public: + enum {DirLTR, DirRTL} dir; +}; + +void ParStyle::clearFormatting() +{ + // For now, do nothing. + // dir is not a formatting item. +} + +class Level +{ +public: + Level(RTF2HTML *_p); + Level(const Level&); + void setText(const char* str); + void setFontTbl() { m_bFontTbl = true; } + void setColors() { m_bColors = true; resetColors(); } + void setRed(unsigned char val) { setColor(val, &m_nRed); } + void setGreen(unsigned char val) { setColor(val, &m_nGreen); } + void setBlue(unsigned char val) { setColor(val, &m_nBlue); } + void setFont(unsigned nFont); + void setEncoding(unsigned nFont); + void setFontName(); + void setFontColor(unsigned short color); + void setFontBgColor(unsigned short color); + void setFontSizeHalfPoints(unsigned short sizeInHalfPoints); + void setFontSize(unsigned short sizeInPoints); + void setBold(bool); + void setItalic(bool); + void setUnderline(bool); + void startParagraph(); + bool isParagraphOpen() const; + void clearParagraphFormatting(); + void setParagraphDirLTR(); + void setParagraphDirRTL(); + void addLineBreak(); + void setAnsiCodePage(unsigned short cp); + void flush(); + void reset(); + void resetTag(TagEnum tag); +protected: + QString text; + void Init(); + RTF2HTML *p; + void resetColors() { m_nRed = m_nGreen = m_nBlue = 0; m_bColorInit = false; } + void setColor(unsigned char val, unsigned char *p) + { *p = val; m_bColorInit=true; } + + // Marks the position in m_tags where this level begun. + unsigned m_nTagsStartPos; + + // True when parsing the fonts table + bool m_bFontTbl; + // True when parsing the colors table. + bool m_bColors; + // True when inside a 'fname' block. + bool m_bFontName; + // False until we get the tagged font name. + bool m_bTaggedFontNameOk; + + unsigned char m_nRed; + unsigned char m_nGreen; + unsigned char m_nBlue; + bool m_bColorInit; + unsigned m_nFont; // 1-based + unsigned m_nEncoding; + unsigned m_nFontColor; // 1-based + unsigned m_nFontSize; + unsigned m_nFontBgColor; // 1-based + bool m_bBold; + bool m_bItalic; + bool m_bUnderline; +}; + +class OutTag +{ +public: + OutTag(TagEnum _tag, unsigned _param) : tag(_tag), param(_param) {} + TagEnum tag; + unsigned param; +}; + +class RTF2HTML +{ + friend class Level; + +public: + RTF2HTML(); + QString Parse(const char *rtf, const char *encoding); + +// Paragraph-specific functions: + + // Appends a string with formatting into the paragraph buffer. +#if defined __GNUC__ + void PrintUnquoted(const char *str, ...) + __attribute__ ((__format__ (printf, 2, 3))); +#else + void PrintUnquoted(const char *str, ...); +#endif + // Quotes and appends a string to the paragraph buffer. + void PrintQuoted(const QString &str); + // Writes down the tags from oTags into the paragraph buffer. + void FlushOutTags(); + // Retrieves the top not-yet-written tag. + OutTag* getTopOutTag(TagEnum tagType); + // Writes down the paragraph buffer and resets the paragraph state. + void FlushParagraph(); + //sets the codepage found in the rtf stream + void setAnsiCodePage(unsigned short cp); + +// Document-wide functions: + + void PutTag(TagEnum n) + { + tags.push(n); + } + +protected: + +// Paragraph members + + // The paragraph's HTML buffer. + QString sParagraph; + // True if the paragraph was opened explicitly. + bool bExplicitParagraph; + // Whether we have an empty paragraph which we haven't flushed yet. + // We do not haste with flushing it, since it might be the last + // (empty) paragraph in the RTF message, which we want to discard. + // This last paragraph is not appended by the user, but by the + // client itself, to keep the official ICQ client's sanity, + // and there's no reason our users should see it. + bool bPendingEmptyParagraph; + // Defines the paragraph's formatting. + ParStyle parStyle; + // Tags which weren't yet printed out. + vector oTags; + +// Document members + + // The document HTML buffer. + QString s; + // Fonts table. + vector fonts; + // Colors table. + vector colors; + // Stack of tags (across all levels, not just current level) + stack tags; + +// RTF parser internals + + const char *rtf_ptr; + const char *encoding; + Level cur_level; + stack levels; +}; + +RTF2HTML::RTF2HTML() + : cur_level(this) +{ + rtf_ptr = NULL; + bExplicitParagraph = false; + bPendingEmptyParagraph = false; +} + +OutTag* RTF2HTML::getTopOutTag(TagEnum tagType) +{ + vector::iterator it, it_end; + for(it = oTags.begin(), it_end = oTags.end(); it != it_end; ++it) + if (it->tag == tagType) + return &(*it); + return NULL; +} + +void RTF2HTML::FlushOutTags() +{ + vector::iterator iter; + for (iter = oTags.begin(); iter != oTags.end(); iter++) + { + OutTag &t = *iter; + switch (t.tag){ + case TAG_FONT_COLOR: + { + // RTF colors are 1-based; colors[] is a 0-based array. + if (t.param > colors.size() || t.param == 0) + break; + QColor &c = colors[t.param-1]; + PrintUnquoted("", c.red(), c.green(), c.blue()); + } + break; + case TAG_FONT_SIZE: + PrintUnquoted("", t.param); + break; + case TAG_FONT_FAMILY: + { + if (t.param > fonts.size() || t.param == 0) + break; + FontDef &f = fonts[t.param-1]; + QString name = (!f.nonTaggedName.isEmpty()) ? f.nonTaggedName : f.taggedName; + PrintUnquoted("", qPrintable(name)); + } + break; + case TAG_BG_COLOR: + { + if (t.param > colors.size() || t.param == 0) + break; + QColor &c = colors[t.param-1]; + PrintUnquoted("", c.red(), c.green(), c.blue()); + break; + } + case TAG_BOLD: + PrintUnquoted(""); + break; + case TAG_ITALIC: + PrintUnquoted(""); + break; + case TAG_UNDERLINE: + PrintUnquoted(""); + break; + default: + break; + } + } + oTags.clear(); +} + +// This function will close the already-opened tag 'tag'. It will take +// care of closing the tags which 'tag' contains first (ie. it will unroll +// the stack till the point where 'tag' is). +void Level::resetTag(TagEnum tag) +{ + // A stack which'll keep tags we had to close in order to reach 'tag'. + // After we close 'tag', we will reopen them. + stack s; + + while (p->tags.size() > m_nTagsStartPos){ // Don't go further than the point where this level starts. + + TagEnum nTag = p->tags.top(); + + /* A tag will be located in oTags if it still wasn't printed out. + A tag will get printed out only if necessary (e.g. will + be optimized away). + Thus, for each tag we remove from the actual tag stack, we also + try to remove a yet-to-be-printed tag, and only if there are no + yet-to-be-printed tags left, we start closing the tags we pop. + The tags have one space - needed for umlaute (�) and .utf8() + */ + if (p->oTags.empty()){ + switch (nTag){ + case TAG_FONT_COLOR: + case TAG_FONT_SIZE: + case TAG_BG_COLOR: + case TAG_FONT_FAMILY: + p->PrintUnquoted(""); + break; + case TAG_BOLD: + p->PrintUnquoted(""); + break; + case TAG_ITALIC: + p->PrintUnquoted(""); + break; + case TAG_UNDERLINE: + p->PrintUnquoted(""); + break; + default: + break; + } + }else{ + p->oTags.pop_back(); + } + + p->tags.pop(); + if (nTag == tag) break; // if we reached the tag we were looking to close. + s.push(nTag); // remember to reopen this tag + } + + if (tag == TAG_ALL) return; + + while (!s.empty()){ + TagEnum nTag = s.top(); + switch (nTag){ + case TAG_FONT_COLOR:{ + unsigned nFontColor = m_nFontColor; + m_nFontColor = 0; + setFontColor(nFontColor); + break; + } + case TAG_FONT_SIZE:{ + unsigned nFontSize = m_nFontSize; + m_nFontSize = 0; + setFontSize(nFontSize); + break; + } + case TAG_BG_COLOR:{ + unsigned nFontBgColor = m_nFontBgColor; + m_nFontBgColor = 0; + setFontBgColor(nFontBgColor); + break; + } + case TAG_FONT_FAMILY:{ + unsigned nFont = m_nFont; + m_nFont = 0; + setFont(nFont); + break; + } + case TAG_BOLD:{ + bool nBold = m_bBold; + m_bBold = false; + setBold(nBold); + break; + } + case TAG_ITALIC:{ + bool nItalic = m_bItalic; + m_bItalic = false; + setItalic(nItalic); + break; + } + case TAG_UNDERLINE:{ + bool nUnderline = m_bUnderline; + m_bUnderline = false; + setUnderline(nUnderline); + break; + } + default: + break; + } + s.pop(); + } +} + +Level::Level(RTF2HTML *_p) : + p(_p), + m_bFontTbl(false), + m_bColors(false), + m_bFontName(false), + m_bTaggedFontNameOk(false), + m_nFont(0), + m_nEncoding(0) +{ + m_nTagsStartPos = p->tags.size(); + Init(); +} + +Level::Level(const Level &l) : + p(l.p), + m_bFontTbl(l.m_bFontTbl), + m_bColors(l.m_bColors), + m_bFontName(false), + m_bTaggedFontNameOk(l.m_bTaggedFontNameOk), + m_nFont(l.m_nFont), + m_nEncoding(l.m_nEncoding) +{ + m_nTagsStartPos = p->tags.size(); + Init(); +} + +void Level::Init() +{ + m_nFontColor = 0; + m_nFontBgColor = 0; + m_nFontSize = 0; + m_bFontName = false; + m_bBold = false; + m_bItalic = false; + m_bUnderline = false; +} + +void RTF2HTML::PrintUnquoted(const char *str, ...) +{ + char buff[1024]; + va_list ap; + va_start(ap, str); + vsnprintf(buff, sizeof(buff), str, ap); + va_end(ap); + sParagraph += buff; +} + +void RTF2HTML::PrintQuoted(const QString &str) +{ + sParagraph += quoteString(str); +} + +void RTF2HTML::FlushParagraph() +{ + if (bPendingEmptyParagraph) + { + s += "


"; + bPendingEmptyParagraph = false; + } + + if (!sParagraph.isEmpty()) + { + s += "

"; + s += sParagraph; + s += "

"; + } + else + { + if (bExplicitParagraph) + // Delay the empty paragraph for later appending. + // If this empty paragraph happens to be the last one + // in the message, we'll end up discarding it -- which + // is a good thing (since it's just a compatibility hack + // for the official ICQ client). + bPendingEmptyParagraph = true; + } + + // Clear up the paragraph members + sParagraph = ""; +} + +void RTF2HTML::setAnsiCodePage(unsigned short cp) +{ + for (const ENCODING *c = getContacts()->getEncodings(); c->language; c++){ + if (!c->bMain) + continue; + if ((unsigned)c->cp_code == cp){ + encoding = c->codec; + return; + } + } +} + +void Level::setFont(unsigned nFont) +{ + if (nFont <= 0) + return; + + if (m_bFontTbl){ + if (nFont > p->fonts.size() +1){ + log(L_WARN, "Invalid font index (%u) while parsing font table.", nFont); + return; + } + if (nFont > p->fonts.size()){ + FontDef f; + f.charset = 0; + p->fonts.push_back(f); + } + m_nFont = nFont; + } + else + { + if (nFont > p->fonts.size()) + { + log(L_WARN, "Invalid font index (%u)",nFont); + return; + } + if (m_nFont == nFont) + return; + m_nFont = nFont; + if (m_nFont) resetTag(TAG_FONT_FAMILY); + m_nEncoding = p->fonts[nFont-1].charset; + p->oTags.push_back(OutTag(TAG_FONT_FAMILY, nFont)); + p->PutTag(TAG_FONT_FAMILY); + } +} + +void Level::setFontName() +{ + // This function is only valid during font table parsing. + if (m_bFontTbl){ + if ((m_nFont > 0) && (m_nFont <= p->fonts.size())) + // Be prepared to accept a font name. + m_bFontName = true; + } +} + +void Level::setEncoding(unsigned nEncoding) +{ + if (m_bFontTbl){ + if ((m_nFont > 0) && (m_nFont <= p->fonts.size())) + p->fonts[m_nFont-1].charset = nEncoding; + return; + } + m_nEncoding = nEncoding; +} + +void Level::setBold(bool bBold) +{ + if (m_bBold == bBold) return; + if (m_bBold) resetTag(TAG_BOLD); + m_bBold = bBold; + if (!m_bBold) return; + p->oTags.push_back(OutTag(TAG_BOLD, 0)); + p->PutTag(TAG_BOLD); +} + +void Level::setItalic(bool bItalic) +{ + if (m_bItalic == bItalic) return; + if (m_bItalic) resetTag(TAG_ITALIC); + m_bItalic = bItalic; + if (!m_bItalic) return; + p->oTags.push_back(OutTag(TAG_ITALIC, 0)); + p->PutTag(TAG_ITALIC); +} + +void Level::setUnderline(bool bUnderline) +{ + if (m_bUnderline == bUnderline) return; + if (m_bUnderline) resetTag(TAG_UNDERLINE); + m_bUnderline = bUnderline; + if (!m_bUnderline) return; + p->oTags.push_back(OutTag(TAG_UNDERLINE, 0)); + p->PutTag(TAG_UNDERLINE); +} + +void Level::setFontColor(unsigned short nColor) +{ + if (m_nFontColor == nColor) return; + if (m_nFontColor) resetTag(TAG_FONT_COLOR); + if (nColor > p->colors.size()) return; + m_nFontColor = nColor; + p->oTags.push_back(OutTag(TAG_FONT_COLOR, m_nFontColor)); + p->PutTag(TAG_FONT_COLOR); +} + +void Level::setFontBgColor(unsigned short nColor) +{ + if (m_nFontBgColor == nColor) return; + if (m_nFontBgColor != 0) resetTag(TAG_BG_COLOR); + if (nColor > p->colors.size()) return; + m_nFontBgColor = nColor; + p->oTags.push_back(OutTag(TAG_BG_COLOR, m_nFontBgColor)); + p->PutTag(TAG_BG_COLOR); +} + +void Level::setFontSizeHalfPoints(unsigned short nSize) +{ + setFontSize(nSize / 2); +} + +void Level::setFontSize(unsigned short nSize) +{ + if (m_nFontSize == nSize) + return; + if (m_nFontSize) + resetTag(TAG_FONT_SIZE); + p->oTags.push_back(OutTag(TAG_FONT_SIZE, nSize)); + p->PutTag(TAG_FONT_SIZE); + m_nFontSize = nSize; +} + +void Level::startParagraph() +{ + // Whatever tags we have open now, close them. + // We cannot carry let character formatting tags wrap paragraphs, + // since a formatting tag can close at any time and we cannot + // close the paragraph any time we want. + resetTag(TAG_ALL); + + // Flush the current paragraph HTML to the document HTML. + p->FlushParagraph(); + + // Mark this new paragraph as an explicit one (from \par etc.). + p->bExplicitParagraph = true; + + // Restore character formatting + p->oTags.push_back(OutTag(TAG_FONT_SIZE, m_nFontSize)); + p->PutTag(TAG_FONT_SIZE); + p->oTags.push_back(OutTag(TAG_FONT_COLOR, m_nFontColor)); + p->PutTag(TAG_FONT_COLOR); + p->oTags.push_back(OutTag(TAG_FONT_FAMILY, m_nFont)); + p->PutTag(TAG_FONT_FAMILY); + if (m_nFontBgColor != 0) + { + p->oTags.push_back(OutTag(TAG_BG_COLOR, m_nFontBgColor)); + p->PutTag(TAG_BG_COLOR); + } + if (m_bBold) + { + p->oTags.push_back(OutTag(TAG_BOLD, 0)); + p->PutTag(TAG_BOLD); + } + if (m_bItalic) + { + p->PutTag(TAG_ITALIC); + p->oTags.push_back(OutTag(TAG_ITALIC, 0)); + } + if (m_bUnderline) + { + p->oTags.push_back(OutTag(TAG_UNDERLINE, 0)); + p->PutTag(TAG_UNDERLINE); + } +} + +bool Level::isParagraphOpen() const +{ + return p->bExplicitParagraph; +} + +void Level::clearParagraphFormatting() +{ + // implicitly start a paragraph + if (!isParagraphOpen()) + startParagraph(); + // Since we don't implement any of the paragraph formatting tags (e.g. alignment), + // we don't clean up anything here. Note that \pard does NOT clean character + // formatting (such as font size, font weight, italics...). + p->parStyle.clearFormatting(); +} + +void Level::setParagraphDirLTR() +{ + // implicitly start a paragraph + if (!isParagraphOpen()) + startParagraph(); + p->parStyle.dir = ParStyle::DirLTR; +} + +void Level::setParagraphDirRTL() +{ + // implicitly start a paragraph + if (!isParagraphOpen()) + startParagraph(); + p->parStyle.dir = ParStyle::DirRTL; +} + +void Level::addLineBreak() +{ + p->PrintUnquoted("
"); +} + +void Level::setAnsiCodePage(unsigned short cp) +{ + p->setAnsiCodePage(cp); +} + +void Level::reset() +{ + resetTag(TAG_ALL); + if (m_bColors){ + if (m_bColorInit){ + QColor c(m_nRed, m_nGreen, m_nBlue); + p->colors.push_back(c); + resetColors(); + } + return; + } +} + +void Level::setText(const char *str) +{ + if (m_bColors) + { + reset(); + } + else if (m_bFontTbl) + { + if ((m_nFont <= 0) || (m_nFont > p->fonts.size())) + return; + + FontDef& def = p->fonts[m_nFont-1]; + + char *pp = (char *)strchr(str, ';'); + unsigned size; + if (pp != NULL) + size = (pp - str); + else + size = strlen(str); + + if (m_bFontName) + { + def.nonTaggedName += QString::fromLatin1(str, size); + // We know we have the entire name + if (pp != NULL) + m_bFontName = false; + } + else if (!m_bTaggedFontNameOk) + { + def.taggedName += QString::fromLatin1(str, size); + if (pp != NULL) + m_bTaggedFontNameOk = true; + } + } + else + { + for (; *str; str++) + if ((unsigned char)(*str) >= ' ') break; + if (!*str) return; + p->FlushOutTags(); + text += str; + } +} + +void Level::flush() +{ + if (text.length() == 0) + return; + const char *encoding = NULL; + if (m_nEncoding){ + for (const ENCODING *c = getContacts()->getEncodings(); c->language; c++){ + if (!c->bMain) + continue; + if ((unsigned)c->rtf_code == m_nEncoding){ + encoding = c->codec; + break; + } + } + } + if (encoding == NULL) + encoding = p->encoding; + QTextCodec *codec = getContacts()->getCodecByName(encoding); + p->PrintQuoted(codec->toUnicode(text.toLocal8Bit())); + text = ""; +} + +const unsigned FONTTBL = 0; +const unsigned COLORTBL = 1; +const unsigned RED = 2; +const unsigned GREEN = 3; +const unsigned BLUE = 4; +const unsigned CF = 5; +const unsigned FS = 6; +const unsigned HIGHLIGHT = 7; +const unsigned PARD = 8; +const unsigned PAR = 9; +const unsigned I = 10; +const unsigned B = 11; +const unsigned UL = 12; +const unsigned F = 13; +const unsigned FCHARSET = 14; +const unsigned FNAME = 15; +const unsigned ULNONE = 16; +const unsigned LTRPAR = 17; +const unsigned RTLPAR = 18; +const unsigned LINE = 19; +const unsigned ANSICPG = 20; + +static char cmds[] = + "fonttbl\x00" + "colortbl\x00" + "red\x00" + "green\x00" + "blue\x00" + "cf\x00" + "fs\x00" + "highlight\x00" + "pard\x00" + "par\x00" + "i\x00" + "b\x00" + "ul\x00" + "f\x00" + "fcharset\x00" + "fname\x00" + "ulnone\x00" + "ltrpar\x00" + "rtlpar\x00" + "line\x00" + "ansicpg\x00" + "\x00"; + +int yywrap() { return 1; } + +static char h2d(char c) +{ + if ((c >= '0') && (c <= '9')) + return c - '0'; + if ((c >= 'A') && (c <= 'F')) + return (c - 'A') + 10; + if ((c >= 'a') && (c <= 'f')) + return (c - 'a') + 10; + return 0; +} + +QString RTF2HTML::Parse(const char *rtf, const char *_encoding) +{ + encoding = _encoding; + YY_BUFFER_STATE yy_current_buffer = yy_scan_string(rtf); + yy_start = 1; /* == BEGIN(INITIAL) - go to initial state since yy_start + is static and can have an old invalid value */ + rtf_ptr = rtf; + int res; + while ((res = yylex())) { + switch (res){ + case UP:{ + cur_level.flush(); + levels.push(cur_level); + break; + } + case DOWN:{ + if (!levels.empty()){ + cur_level.flush(); + cur_level.reset(); + cur_level = levels.top(); + levels.pop(); + } + break; + } + case IMG:{ + cur_level.flush(); + const char ICQIMAGE[] = "icqimage"; + const char *p = yytext + 3; + if ((strlen(p) > strlen(ICQIMAGE)) && !memcmp(p, ICQIMAGE, strlen(ICQIMAGE))){ + unsigned n = 0; + for (p += strlen(ICQIMAGE); *p; p++){ + if ((*p >= '0') && (*p <= '9')){ + n = n << 4; + n += (*p - '0'); + continue; + } + if ((*p >= 'A') && (*p <= 'F')){ + n = n << 4; + n += (*p - 'A') + 10; + continue; + } + if ((*p >= 'a') && (*p <= 'f')){ + n = n << 4; + n += (*p - 'a') + 10; + continue; + } + break; + } + if (n < 26) + PrintUnquoted("", n); + }else{ + log(L_WARN, "Unknown image %s", yytext); + } + break; + } + case SKIP: + break; + case SLASH: + cur_level.setText(yytext+1); + break; + case TXT: + cur_level.setText(yytext); + break; + case UNICODE_CHAR:{ + cur_level.flush(); + sParagraph += QChar((unsigned short)(atol(yytext + 2))); + break; + } + case HEX:{ + char s[2]; + s[0] = (h2d(yytext[2]) << 4) + h2d(yytext[3]); + s[1] = 0; + cur_level.setText(s); + break; + } + case CMD: + { + cur_level.flush(); + const char *cmd = yytext + 1; + unsigned n_cmd = 0; + unsigned cmd_size = 0; + int cmd_value = -1; + const char *p; + for (p = cmd; *p; p++, cmd_size++) + if (((*p >= '0') && (*p <= '9')) || (*p == ' ')) break; + if (*p && (*p != ' ')) cmd_value = atol(p); + for (p = cmds; *p; p += strlen(p) + 1, n_cmd++){ + if (strlen(p) > cmd_size) continue; + if (!memcmp(p, cmd, cmd_size)) break; + } + cmd += strlen(p); + switch (n_cmd){ + case FONTTBL: // fonttbl + cur_level.setFontTbl(); + break; + case COLORTBL: + cur_level.setColors(); + break; + case RED: + cur_level.setRed(cmd_value); + break; + case GREEN: + cur_level.setGreen(cmd_value); + break; + case BLUE: + cur_level.setBlue(cmd_value); + break; + case CF: + cur_level.setFontColor(cmd_value); + break; + case FS: + cur_level.setFontSizeHalfPoints(cmd_value); + break; + case HIGHLIGHT: + cur_level.setFontBgColor(cmd_value); + break; + case PARD: + cur_level.clearParagraphFormatting(); + break; + case PAR: + cur_level.startParagraph(); + break; + case I: + cur_level.setItalic(cmd_value != 0); + break; + case B: + cur_level.setBold(cmd_value != 0); + break; + case UL: + cur_level.setUnderline(cmd_value != 0); + break; + case ULNONE: + cur_level.setUnderline(false); + break; + case F: + // RTF fonts are 0-based; our font index is 1-based. + cur_level.setFont(cmd_value+1); + break; + case FCHARSET: + cur_level.setEncoding(cmd_value); + break; + case FNAME: + cur_level.setFontName(); + break; + case LTRPAR: + cur_level.setParagraphDirLTR(); + break; + case RTLPAR: + cur_level.setParagraphDirRTL(); + break; + case LINE: + cur_level.addLineBreak(); + case ANSICPG: + cur_level.setAnsiCodePage(cmd_value); + } + break; + } + } + }; + yy_delete_buffer(yy_current_buffer); + yy_current_buffer = NULL; + FlushParagraph(); + return s; +} + +bool ICQClient::parseRTF(const QByteArray &rtf, Contact *contact, QString &res) +{ + const char _RTF[] = "{\\rtf"; + // codec to use when no other information is in the rtf stream + QTextCodec *codec = getContacts()->getCodec(contact); + if (!qstrncmp(rtf.data(), _RTF, strlen(_RTF))) + { + RTF2HTML p; + res = p.Parse(rtf.data(), codec->name().data()); + return true; + } + res = codec->toUnicode(rtf); + return false; +} + diff --git a/plugins/icq/rtfgen.cpp b/plugins/icq/rtfgen.cpp new file mode 100644 index 0000000..4c91814 --- /dev/null +++ b/plugins/icq/rtfgen.cpp @@ -0,0 +1,1112 @@ +/*************************************************************************** + rtfgen.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifdef WIN32 +#include +#endif + +#include +#include +#include +#include + +#include +#include + +#include "html.h" +#include "icons.h" +#include "unquot.h" +#include "log.h" + +#include "icqclient.h" +#include "polling.h" + + +#include "icqclient.h" + +using namespace std; +using namespace SIM; + +// Represents a character (as opposed to paragraph) style +struct CharStyle +{ + CharStyle() : + colorIdx(-1), + sizePt(-1), + faceIdx(-1), + bold(false), + italic(false), + underline(false), + bgColorIdx(-1) + {} + + // Returns the diff from 'old' CharStyle to this CharStyle as RTF commands. + QString getDiffRTF(const CharStyle& old) const; + + bool operator==(const CharStyle& that) + { + return (colorIdx == that.colorIdx && + sizePt == that.sizePt && + faceIdx == that.faceIdx && + bold == that.bold && + italic == that.italic && + underline == that.underline && + bgColorIdx == that.bgColorIdx); + } + + bool operator!=(const CharStyle& that) + { + return !(*this == that); + } + + signed colorIdx; + signed sizePt; // size in points + signed faceIdx; + bool bold; + bool italic; + bool underline; + signed bgColorIdx; +}; + +QString CharStyle::getDiffRTF(const CharStyle& old) const +{ + QString rtf; + + if (old.colorIdx != colorIdx) + { + rtf += QString("\\cf%1").arg(colorIdx); + } + if (old.sizePt != sizePt) + { + rtf += QString("\\fs%1").arg(sizePt * 2); + } + if (old.faceIdx != faceIdx) + { + rtf += QString("\\f%1").arg(faceIdx); + } + if (old.bold != bold) + { + rtf += QString("\\b%1").arg(bold ? 1 : 0); + } + if (old.italic != italic) + { + rtf += QString("\\i%1").arg(italic ? 1 : 0); + } + if (old.underline != underline) + { + rtf += QString("\\ul%1").arg(underline ? 1 : 0); + } + if (old.bgColorIdx != bgColorIdx) + { + rtf += QString("\\highlight%1").arg(bgColorIdx); + } + + return rtf; +} + +class Tag +{ +public: + Tag() +: pCharStyle(NULL) + { + } + + ~Tag() + { + if (pCharStyle != NULL) + delete pCharStyle; + } + + void setCharStyle(const CharStyle& charStyle) + { + if (pCharStyle == NULL) + pCharStyle = new CharStyle(); + *pCharStyle = charStyle; + } + + bool hasCharStyle() + { + return pCharStyle != NULL; + } + +public: + QString name; + CharStyle* pCharStyle; +}; + +class TagStack : private list +{ +public: + TagStack() + { + } + + Tag* getTopTagWithCharStyle() + { + iterator it = end(), it_begin = begin(); + while(it != it_begin) + { + it--; + if (it->hasCharStyle()) + return &(*it); + } + return NULL; + } + + Tag* pushNew() + { + push_back(Tag()); + return &(back()); + } + + Tag* peek() + { + if (!empty()) + return &(back()); + else + return NULL; + } + + void pop() + { + pop_back(); + } +}; + +int htmlFontSizeToPt(int fontSize, int baseSize = 12) +{ + // Based on Qt's code (so we'd be compatible with QTextEdit) + int pt; + + switch ( fontSize ) { + case 1: + pt = 7*baseSize/10; + break; + case 2: + pt = (8 * baseSize) / 10; + break; + case 4: + pt = (12 * baseSize) / 10; + break; + case 5: + pt = (15 * baseSize) / 10; + break; + case 6: + pt = 2 * baseSize; + break; + case 7: + pt = (24 * baseSize) / 10; + break; + default: + pt = baseSize; + } + + return pt; +} + +class RTFGenParser : public HTMLParser +{ +public: + RTFGenParser(ICQClient *client, const QColor& foreColor, Contact *contact, unsigned max_size); + QByteArray parse(const QString &text); + // Returns the color's index in the colors table, adding the color if necessary. + int getColorIdx(const QColor &color); + // Returns the font face's index in the fonts table, adding the font face if necessary. + int getFontFaceIdx(const QString &fontFace); + unsigned textPos; + stack tags; + stack options; + unsigned m_res_size; +protected: + virtual void text(const QString &text); + virtual void tag_start(const QString &tag, const list &attrs); + virtual void tag_end(const QString &tag); + QByteArray res; + ICQClient *m_client; + Contact *m_contact; + QTextCodec *m_codec; + bool m_bSpace; + unsigned m_max_size; + + TagStack m_tags; + + // Used to compose RTF tables of unique font names and colors. + list m_fontFaces; + list m_colors; + + QColor m_foreColor; + // The character position in 'res' string of the last paragraph start + // (right after \par). Useful for inserting paragraph formatting + // after you wrote past the paragraph mark. + unsigned m_lastParagraphPos; + enum { + DirUnknown, // Initial BiDi dir; if not explicitly specified, + // its determined from the first "strong character". + DirLTR, + DirRTL + } m_paragraphDir; +}; + +RTFGenParser::RTFGenParser(ICQClient *client, const QColor& foreColor, Contact *contact, unsigned max_size) +{ + m_client = client; + m_contact = contact; + m_foreColor = foreColor; + m_max_size = max_size; + m_lastParagraphPos = 0; + m_paragraphDir = DirUnknown; +} + +#ifdef WIN32 + +struct rtf_cp +{ + unsigned cp; + unsigned charset; +}; + +rtf_cp rtf_cps[] = + { + { 737, 161 }, + { 855, 204 }, + { 857, 162 }, + { 862, 177 }, + { 864, 180 }, + { 866, 204 }, + { 869, 161 }, + { 875, 161 }, + { 932, 128 }, + { 1026, 162 }, + { 1250, 238 }, + { 1251, 204 }, + { 1253, 161 }, + { 1254, 162 }, + { 1255, 177 }, + { 0, 0 } + }; + +#endif + +int RTFGenParser::getColorIdx(const QColor& color) +{ + int i = 0; + for (list::iterator it = m_colors.begin(); it != m_colors.end(); ++it, i++){ + if ((*it) == color) + return i + 1; + } + m_colors.push_back(color); + return m_colors.size(); // the colors table is 1-based +} + +int RTFGenParser::getFontFaceIdx(const QString& fontFace) +{ + int i = 0; + for (list::iterator it = m_fontFaces.begin(); it != m_fontFaces.end(); ++it, i++){ + if ((*it) == fontFace) + return i; + } + m_fontFaces.push_back(fontFace); + return m_fontFaces.size() - 1; +} + +QByteArray RTFGenParser::parse(const QString &text) +{ + res.clear(); + m_res_size = 0; + m_codec = getContacts()->getCodec(m_contact); + int charset = 0; + for (const ENCODING *c = getContacts()->getEncodings(); c->language; c++){ + if (!qstricmp(c->codec, m_codec->name())){ + charset = c->rtf_code; + break; + } + } +#ifdef WIN32 + if ((charset == 0) && !qstricmp(m_codec->name(), "system")){ + char buff[256]; + int res = GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE, (char*)&buff, sizeof(buff)); + if (res){ + unsigned codepage = atol(buff); + if (codepage){ + for (const rtf_cp *c = rtf_cps; c->cp; c++){ + if (c->cp == codepage) + charset = c->charset; + } + } + } + } +#endif + unsigned ansicpg = 0; + const char *send_encoding = 0; + m_codec = NULL; + if (charset){ + for (const ENCODING *c = getContacts()->getEncodings(); c->language; c++){ + if ((c->rtf_code == charset) && c->bMain){ + send_encoding = c->codec; + m_codec = getContacts()->getCodecByName(send_encoding); + ansicpg = c->cp_code; + break; + } + } + } + + // Add defaults to the tables + m_fontFaces.push_back("MS Sans Serif"); + m_colors.push_back(m_foreColor); + // Create a "fake" tag which'll serve as the default style + CharStyle style; + style.faceIdx = 0; + style.colorIdx = 1; // colors are 1-based (0 = default) + style.sizePt = 12; // default according to Microsoft + Tag& tag = *(m_tags.pushNew()); + tag.setCharStyle(style); + + // Assume we go immediately after a tag. + m_bSpace = true; + HTMLParser::parse(text); + + QByteArray s; + s = "{\\rtf1\\ansi"; + if (ansicpg){ + s += "\\ansicpg"; + s += QByteArray::number(ansicpg); + } + s += "\\deff0\r\n"; + s += "{\\fonttbl"; + unsigned n = 0; + for (list::iterator it_face = m_fontFaces.begin(); it_face != m_fontFaces.end(); it_face++, n++){ + s += "{\\f"; + s += QByteArray::number(n); + QString face = (*it_face); + if (face.indexOf("Times") >= 0){ + s += "\\froman"; + }else if (face.indexOf("Courier") >= 0){ + s += "\\fmodern"; + }else{ + s += "\\fswiss"; + } + if (charset){ + s += "\\fcharset"; + s += QByteArray::number(charset); + } + s += ' '; + int pos = face.indexOf(QRegExp(" +[")); + if (pos > 0) + face = face.left(pos); + s += face.toLatin1(); + s += ";}"; + } + s += "}\r\n"; + s += "{\\colortbl ;"; + for (list::iterator it_colors = m_colors.begin(); it_colors != m_colors.end(); ++it_colors){ + QColor c = *it_colors; + s += "\\red"; + s += QByteArray::number(c.red()); + s += "\\green"; + s += QByteArray::number(c.green()); + s += "\\blue"; + s += QByteArray::number(c.blue()); + s += ';'; + } + s += "}\r\n"; + s += "\\viewkind4\\pard"; + s += style.getDiffRTF(CharStyle()).toUtf8(); + s += res; + s += "\r\n}\r\n"; + + log(L_DEBUG, "Resulting RTF: %s", s.data()); + + return s; +} + +void RTFGenParser::text(const QString &text) +{ + if (m_res_size) + return; + unsigned size = res.length(); + if (size > m_max_size){ + textPos = start_pos; + m_res_size = size; + return; + } + for (int i = 0; i < (int)(text.length()); i++){ + QChar c = text[i]; + if (c.isSpace()){ + unsigned size = res.length(); + if (size > m_max_size){ + textPos = start_pos + i; + m_res_size = size; + return; + } + } + // In Qt, unless you force the paragraph direction with (Left/Right) + // Ctrl-Shift (also known as Key_Direction_L and Key_Direction_R), + // the P tag won't have a DIR attribute at all. In such cases, unlike + // HTML, Qt will render the paragraph LTR or RTL according to the + // first strong character (as Unicode TR#9 defines). Thus, if the + // direction isn't known yet, we check each character till we find + // a strong one. + if ((m_lastParagraphPos != 0) && (m_paragraphDir == DirUnknown)) + { + switch(c.direction()) + { + case QChar::DirL: + res.insert(m_lastParagraphPos, "\\ltrpar"); + m_paragraphDir = DirLTR; + break; + case QChar::DirR: + res.insert(m_lastParagraphPos, "\\rtlpar"); + m_paragraphDir = DirRTL; + break; + default: // to avoid warnings + break; + } + } + + unsigned short u = c.unicode(); + if (c == '\r' || c == '\n') + continue; + if ((c == '{') || (c == '}') || (c == '\\')){ + char b[5]; + snprintf(b, sizeof(b), "\\\'%02x", u & 0xFF); + res += b; + m_bSpace = false; + continue; + } + if (u < 0x80){ + if (m_bSpace) + res += ' '; + res += (char)u; + m_bSpace = false; + continue; + } + QString s; + s += c; + if (m_codec){ + QByteArray plain = m_codec->fromUnicode(s); + if ((plain.length() == 1) && (m_codec->toUnicode(plain) == s)){ + char b[5]; + snprintf(b, sizeof(b), "\\\'%02x", plain[0] & 0xFF); + res += b; + m_bSpace = false; + continue; + } + } + res += "\\u"; + res += QByteArray::number(s[0].unicode()); + res += '?'; + m_bSpace = false; + } +} + +static const char *def_smiles[] = + { + ":-)", + ":-0", + ":-|", + ":-/", + ":-(", + ":-{}", + ":*)", + ":'-(", + ";-)", + ":-@", + ":-\")", + ":-X", + ":-P", + "8-)", + "O:-)", + ":-D", + "*ANNOYED*", + "*DISGUSTED*", + "*DROOLING*", + "*GIGGLING*", + "*JOKINGLY*", + "*SHOCKED*", + "*WHINING*", + "*SURPRISED*", + "*SURPRISED*", + "*IN LOVE*" + }; + +void RTFGenParser::tag_start(const QString &tagName, const list &attrs) +{ + if (m_res_size) + return; + CharStyle parentStyle, style; + { + Tag* pParentTag = m_tags.getTopTagWithCharStyle(); + if (pParentTag != NULL) + { + parentStyle = *(pParentTag->pCharStyle); + } + } + style = parentStyle; + if ((tagName == "b") || (tagName == "i") || (tagName == "u") || + (tagName == "font") || (tagName == "p") || (tagName == "span")){ + QString tag = tagName; + QString option; + for (list::const_iterator it = attrs.begin(); it != attrs.end(); ++it){ + QString key = *it; + ++it; + QString value = *it; + option += ' '; + option += key; + if (!value.isEmpty()){ + option += "=\""; + option += value; + option += "\""; + } + } + tags.push(tag); + options.push(option); + } + + if (tagName == "b"){ + style.bold = true; + } + else if (tagName == "i"){ + style.italic = true; + } + else if (tagName == "u"){ + style.underline = true; + } + else if (tagName == "font"){ + for (list::const_iterator it = attrs.begin(); it != attrs.end(); it++){ + QString name = (*it); + ++it; + QString value = (*it); + if (name == "color") + { + style.colorIdx = getColorIdx(value); + } + else if (name == "face") + { + style.faceIdx = getFontFaceIdx(value); + } + else if (name == "size") + { + int logicalSize = value.toInt(); + if (value[0] == '+' || value[0] == '-') + logicalSize += 3; + if (logicalSize < 1) + logicalSize = 1; + else if (logicalSize > 7) + logicalSize = 7; + style.sizePt = htmlFontSizeToPt(logicalSize); + } + } + } + else if (tagName == "p"){ + m_paragraphDir = DirUnknown; + m_lastParagraphPos = res.length(); + m_bSpace = true; + for (list::const_iterator it = attrs.begin(); it != attrs.end(); ++it){ + QString name = it->toLower(); + ++it; + QString value = (*it); + if (name == "dir") + { + QString dir = value.toLower(); + if (dir == "ltr") + { + res += "\\ltrpar"; + m_paragraphDir = DirLTR; + } + if (dir == "rtl") + { + res += "\\rtlpar"; + m_paragraphDir = DirRTL; + } + } + } + + } + else if (tagName == "br"){ + res += "\\line"; + m_bSpace = true; + } + else if (tagName == "img"){ + QString src; + QString alt; + for (list::const_iterator it = attrs.begin(); it != attrs.end(); ++it){ + QString name = (*it); + ++it; + QString value = (*it); + if (name == "src"){ + src = value; + break; + } + if (name == "alt"){ + alt = value; + break; + } + } + if (src.startsWith("sim:icons/")){ + QStringList smiles = getIcons()->getSmile(src.mid(10)); + for (QStringList::iterator its = smiles.begin(); its != smiles.end(); ++its){ + QString s = *its; + for (unsigned nSmile = 0; nSmile < 26; nSmile++){ + if (s != def_smiles[nSmile]) + continue; + res += "<##icqimage00"; + char buf[4]; + sprintf(buf, "%02X", nSmile); + res += buf; + res += '>'; + return; + } + } + if (!smiles.empty()){ + text(smiles.front()); + return; + } + } + text(alt); + return; + } + + // Process attributes which all tags share. + + for (list::const_iterator it = attrs.begin(); it != attrs.end(); ++it){ + QString name = it->toLower(); + ++it; + QString value = (*it); + + // Any tag might have a STYLE. + if (name == "style"){ + // A really crude CSS parser goes here: + QRegExp cssReNum("[0-9]+"); + list cssProp = parseStyle(value); + for (list::iterator it = cssProp.begin(); it != cssProp.end(); ++it) + { + QString cssPropName = *it; + ++it; + if (it == cssProp.end()) + break; + QString cssPropValue = *it; + if (cssPropName == "font-family") + { + style.faceIdx = getFontFaceIdx(cssPropValue); + } + else if (cssPropName == "font-size") + { + cssPropValue = cssPropValue.toLower(); + int length; + if(cssReNum.indexIn(cssPropValue) != -1) + { + length = cssReNum.matchedLength(); + float number = cssPropValue.left(length).toFloat(); + QString type = cssPropValue.mid(length); + if (type == "pt") + { + style.sizePt = static_cast(number); + } + else if (type == "px") + { + // for now, handle like 'pt', though it's wrong + style.sizePt = static_cast(number); + } + else if (type == "%") + { + style.sizePt = static_cast(parentStyle.sizePt * (number/100)); + } + // We don't handle 'cm', 'em' etc. + } + else if (cssPropValue == "smaller") + { + // FONT SIZE=3 is 'normal', 2 is 'smaller' + style.sizePt = htmlFontSizeToPt(2, parentStyle.sizePt); + } + else if (cssPropValue == "larger") + { + // FONT SIZE=3 is 'normal', 4 is 'larger' + style.sizePt = htmlFontSizeToPt(4, parentStyle.sizePt); + } + + // We don't handle 'small', 'medium' etc. It goes too far + // beyond our basic implementation. + // Also, empty 'type' would be invalid CSS, thus ignored. + } + else if (cssPropName == "font-style") + { + style.italic = (cssPropValue.toLower() == "italic"); + } + else if (cssPropName == "font-weight") + { + style.bold = (cssPropValue.toInt() >= 600); + } + else if (cssPropName == "text-decoration") + { + style.underline = (cssPropValue.toLower() == "underline"); + } + else if (cssPropName == "color") + { + style.colorIdx = getColorIdx(cssPropValue); + } + else if (cssPropName == "background-color") + { + style.bgColorIdx = getColorIdx(cssPropValue); + } + } + } + } + + Tag& tag = *(m_tags.pushNew()); + tag.name = tagName; + // Check if anything changed in the style. + // Only then the tag deserves getting a charStyle. + if (parentStyle != style) + { + QString rtf = style.getDiffRTF(parentStyle); + if (!rtf.isEmpty()) + { + res += rtf.toUtf8(); + m_bSpace = true; + } + tag.setCharStyle(style); + } +} + +void RTFGenParser::tag_end(const QString &tagName) +{ + if (m_res_size) + return; + if ((tagName == "b") || (tagName == "i") || (tagName == "u") || + (tagName == "font") || (tagName == "p") || (tagName == "span")){ + while (!tags.empty()){ + QString tag = tags.top(); + tags.pop(); + options.pop(); + if (tag == tagName) + break; + } + } + + // Roll back until we find our tag. + bool found = false; + for(Tag* pTag = m_tags.peek(); pTag != NULL && !found; pTag = m_tags.peek()) + { + if (pTag->name == tagName) + { + found = true; + } + + if (pTag->hasCharStyle()) + { + CharStyle style = *(pTag->pCharStyle); + + // We must pop here, so that getTopTagWithCharStyle will find a parent tag. + m_tags.pop(); + pTag = NULL; // to avoid confusion + + Tag* pParentTag = m_tags.getTopTagWithCharStyle(); + if (pParentTag != NULL) + { + if (pParentTag->hasCharStyle()) + { + CharStyle* pParentStyle = pParentTag->pCharStyle; + + // Roll back the character style. This is regardless of whether + // we found the closed tag; we just collapse all styles on our way. + QString rtf = pParentStyle->getDiffRTF(style); + if (!rtf.isEmpty()) + { + res += rtf.toUtf8(); + m_bSpace = true; + } + } + } + } + else // if this tag has no char style attached + { + m_tags.pop(); // just pop the tag out + pTag = NULL; // to avoid confusion + } + + if (found) + { + if (tagName.toLower() == "p") + { + res += "\\par"; + m_bSpace = true; + } + } + } +} + +QByteArray ICQClient::createRTF(QString &text, QString &part, unsigned long foreColor, Contact *contact, unsigned max_size) +{ + RTFGenParser p(this, foreColor, contact, max_size); + QByteArray res = p.parse(text); + if (p.m_res_size == 0){ + part = text; + text.clear(); + return res; + } + QString endTags; + QString startTags; + while (!p.tags.empty()){ + QString tag = p.tags.top(); + QString option = p.options.top(); + p.tags.pop(); + p.options.pop(); + endTags += "'; + startTags = '<' + tag + option + '>' + startTags; + } + part = text.left(p.textPos) + endTags; + text = startTags + text.mid(p.textPos); + return res; +} + +class ImageParser : public HTMLParser +{ +public: + ImageParser(bool bIcq); + QString parse(const QString &text); +protected: + virtual void text(const QString &text); + virtual void tag_start(const QString &tag, const list &attrs); + virtual void tag_end(const QString &tag); + void startBody(); + void endBody(); + QByteArray res; + bool m_bBody; + bool m_bIcq; +}; + +ImageParser::ImageParser(bool bIcq) +{ + m_bIcq = bIcq; +} + +QString ImageParser::parse(const QString &text) +{ + res = 0; //QString::null; + startBody(); + HTMLParser::parse(text); + endBody(); + return res; +} + +void ImageParser::startBody() +{ + m_bBody = true; + res = 0;//QString::null; +} + +void ImageParser::endBody() +{ + if (m_bBody) + m_bBody = false; +} + +void ImageParser::text(const QString &text) +{ + if (!m_bBody) + return; + res += quoteString(text).toUtf8(); +} + +void ImageParser::tag_start(const QString &tag, const list &attrs) +{ + QString oTag = tag; + + if (tag == "html") + { + res = 0; //QString::null; + m_bBody = false; + return; + } + if (tag == "body"){ + startBody(); + // We still want BODY's styles + oTag = "span"; + } + if (!m_bBody) + return; + if (tag == "img"){ + QString src; + QString alt; + for (list::const_iterator it = attrs.begin(); it != attrs.end(); ++it){ + QString name = *it; + ++it; + QString value = *it; + if (name == "src"){ + src = value; + break; + } + if (name == "alt"){ + alt = value; + break; + } + } + if (src.left(10) != "sim:icons/"){ + text(alt); + return; + } + QStringList smiles = getIcons()->getSmile(src.mid(5)); + if (smiles.empty()){ + text(alt); + return; + } + if (m_bIcq){ + QStringList::ConstIterator its; + for (its = smiles.constBegin(); its != smiles.constEnd(); ++its){ + for (unsigned nSmile = 0; nSmile < 26; nSmile++){ + if ((*its) != def_smiles[nSmile]) + continue; + res += ""; + return; + } + } + } + text(smiles.front()); + return; + } + res += '<'; + res += oTag.toUtf8(); + for (list::const_iterator it = attrs.begin(); it != attrs.end(); ++it){ + QString name = *it; + ++it; + QString value = *it; + res += ' '; + res += name.toUpper().toUtf8(); + if (!value.isEmpty()){ + res += "=\""; + res += quoteString(value).toUtf8(); + res += "\""; + } + } + res += '>'; +} + +void ImageParser::tag_end(const QString &tag) +{ + QString oTag = tag; + if (!m_bBody) + return; + if (tag == "body"){ + endBody(); + oTag = "span"; + } + res += "'; +} + +QString ICQClient::removeImages(const QString &text, bool bIcq) +{ + ImageParser p(bIcq); + return p.parse(text); +} + +class BgParser : public HTMLParser +{ +public: + BgParser(); + QString parse(const QString &text); + unsigned bgColor; +protected: + virtual void text(const QString &text); + virtual void tag_start(const QString &tag, const list &attrs); + virtual void tag_end(const QString &tag); + QString res; + bool m_bBody; +}; + +BgParser::BgParser() +{ + bgColor = 0xFFFFFF; + m_bBody = true; +} + +QString BgParser::parse(const QString &text) +{ + res = QString::null; + HTMLParser::parse(text); + return res; +} + +void BgParser::text(const QString &text) +{ + if (!m_bBody) + return; + res += quoteString(text); +} + +void BgParser::tag_start(const QString &tag, const list &attrs) +{ + if (tag == "body"){ + m_bBody = true; + res = QString::null; + for (list::const_iterator it = attrs.begin(); it != attrs.end(); ++it){ + QString name = *it; + ++it; + QString value = *it; + if (name.toLower() == "bgcolor"){ + QColor c(value); + bgColor = c.rgb(); + } + } + return; + } + if (!m_bBody) + return; + res += '<'; + res += tag; + for (list::const_iterator it = attrs.begin(); it != attrs.end(); ++it){ + QString name = *it; + ++it; + QString value = *it; + res += ' '; + res += name; + if (!value.isEmpty()){ + res += "=\""; + res += quoteString(value); + res += "\""; + } + } + res += '>'; +} + +void BgParser::tag_end(const QString &tag) +{ + if (tag == "body"){ + m_bBody = false; + return; + } + if (!m_bBody) + return; + res += "'; +} + +unsigned ICQClient::clearTags(QString &text) +{ + BgParser p; + text = p.parse(text); + return p.bgColor; +} + + diff --git a/plugins/icq/securedlg.cpp b/plugins/icq/securedlg.cpp new file mode 100644 index 0000000..7af7367 --- /dev/null +++ b/plugins/icq/securedlg.cpp @@ -0,0 +1,109 @@ +/*************************************************************************** + securedlg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "icons.h" +#include "securedlg.h" +#include "icqclient.h" +#include "icqmessage.h" + +#include +#include +#include +#include +#include + +using namespace SIM; + +SecureDlg::SecureDlg(ICQClient *client, unsigned contact, ICQUserData *data) + : QDialog(NULL) +{ + setupUi(this); + setObjectName("securedlg"); + setModal(false); + setAttribute(Qt::WA_DeleteOnClose); + SET_WNDPROC("secure") + setWindowIcon(Icon("encrypted")); + setButtonsPict(this); + setWindowTitle(windowTitle()); + m_client = client; + m_contact = contact; + m_data = data; + m_msg = NULL; + connect(btnCancel, SIGNAL(clicked()), this, SLOT(close())); + QTimer::singleShot(0, this, SLOT(start())); +} + +SecureDlg::~SecureDlg() +{ + if (m_msg) + EventMessageCancel(m_msg).process(); +} + +void SecureDlg::start() +{ + m_msg = new Message(MessageOpenSecure); + m_msg->setContact(m_contact); + m_msg->setClient(m_client->dataName(m_data)); + m_msg->setFlags(MESSAGE_NOHISTORY); + if (!static_cast(m_client)->send(m_msg, m_data)){ + delete m_msg; + error(I18N_NOOP("Request secure channel fail")); + } +} + +bool SecureDlg::processEvent(Event *e) +{ + switch(e->type()) { + case eEventContact: { + EventContact *ec = static_cast(e); + switch(ec->action()) { + case EventContact::eDeleted: { + close(); + break; + } + default: + break; + } + break; + } + case eEventMessageSent: { + EventMessage *em = static_cast(e); + Message *msg = em->msg(); + if (msg != m_msg) + return false; + QString err = msg->getError(); + if (!err.isEmpty()){ + error(err); + }else{ + m_msg = NULL; + close(); + } + return true; + } + default: + break; + } + return false; +} + +void SecureDlg::error(const QString &err) +{ + QString errText = i18n(err); + m_msg = NULL; + lblError->setText(errText); + btnCancel->setText(i18n("&Close")); +} diff --git a/plugins/icq/securedlg.h b/plugins/icq/securedlg.h new file mode 100644 index 0000000..369e18d --- /dev/null +++ b/plugins/icq/securedlg.h @@ -0,0 +1,45 @@ +/*************************************************************************** + securedlg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _SECUREDLG_H +#define _SECUREDLG_H + +#include "ui_securedlgbase.h" +#include "event.h" + +class ICQClient; +struct ICQUserData; + +class SecureDlg : public QDialog, public Ui::SecureDlgBase, public SIM::EventReceiver +{ + Q_OBJECT +public: + SecureDlg(ICQClient *client, unsigned contact, ICQUserData *data); + ~SecureDlg(); + ICQClient *m_client; + unsigned m_contact; + ICQUserData *m_data; +protected slots: + void start(); +protected: + virtual bool processEvent(SIM::Event *e); + void error(const QString &err); + SIM::Message *m_msg; +}; + +#endif + diff --git a/plugins/icq/securedlgbase.ui b/plugins/icq/securedlgbase.ui new file mode 100644 index 0000000..12907a2 --- /dev/null +++ b/plugins/icq/securedlgbase.ui @@ -0,0 +1,110 @@ + + + + + SecureDlgBase + + + + 0 + 0 + 415 + 151 + + + + Secure chanel request + + + + 11 + + + 6 + + + + + Secure channel is established using SSL with Diffie-Hellman key exchange and the TLS version 1 protocol. + +This only works with other SIM and Licq clients + + + Qt::AlignCenter + + + true + + + + + + + + true + + + + + + + Qt::AlignCenter + + + false + + + + + + + 0 + + + 6 + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Horizontal + + + + + + + &Cancel + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Horizontal + + + + + + + + qPixmapFromMimeSource + diff --git a/plugins/icq/snac.cpp b/plugins/icq/snac.cpp new file mode 100644 index 0000000..99d6c98 --- /dev/null +++ b/plugins/icq/snac.cpp @@ -0,0 +1,22 @@ + +#include "snac.h" +#include "icqclient.h" + +SnacHandler::SnacHandler(ICQClient* client, unsigned short snac) : m_snac(snac) +{ + m_client = client; +} + +SnacHandler::~SnacHandler() +{ +} + +void SnacHandler::snac(const unsigned short subtype, bool bMsgID, bool bType) +{ + m_client->snac(m_snac, subtype, bMsgID, bType); +} + +ICQClient* SnacHandler::client() +{ + return m_client; +} diff --git a/plugins/icq/snac.h b/plugins/icq/snac.h new file mode 100644 index 0000000..7ec40f6 --- /dev/null +++ b/plugins/icq/snac.h @@ -0,0 +1,25 @@ + +#ifndef _SNAC_H +#define _SNAC_H + +class ICQClient; +class ICQBuffer; +class SnacHandler +{ +public: + SnacHandler(ICQClient* client, unsigned short snac); + virtual ~SnacHandler(); + + unsigned short getType() { return m_snac; }; + virtual bool process(unsigned short subtype, ICQBuffer* buf, unsigned short seq) = 0; + + void snac(const unsigned short subtype, bool bMsgID = true, bool bType = false); + + ICQClient* client(); +protected: + unsigned short m_snac; + ICQClient* m_client; + +}; + +#endif diff --git a/plugins/icq/verifydlg.cpp b/plugins/icq/verifydlg.cpp new file mode 100644 index 0000000..a7a072e --- /dev/null +++ b/plugins/icq/verifydlg.cpp @@ -0,0 +1,55 @@ +/*************************************************************************** + verifydlg.cpp - description + ------------------- + begin : Sun Nov 27 2005 + copyright : (C) 2005 by Andrey Rahmatullin + email : wrar@altlinux.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include +#include + +#include "log.h" + +#include "verifydlg.h" + +using namespace SIM; + +VerifyDlg::VerifyDlg(QWidget *parent, const QPixmap& picture) + : QDialog(parent) +{ + setupUi(this); + setModal(false); + QTimer::singleShot(0, this, SLOT(changed())); + connect(edtVerify, SIGNAL(textChanged(const QString&)), SLOT(changed(const QString&))); + lblPicture->setPixmap(picture); + lblPicture->adjustSize(); + log(L_DEBUG, "Image size: %dx%d", picture.width(), picture.height()); + edtVerify->setFocus(); +} + +VerifyDlg::~VerifyDlg() +{ + +} + +void VerifyDlg::changed() +{ + changed(QString()); +} + +void VerifyDlg::changed(const QString& text) +{ + buttonOk->setEnabled(!text.isEmpty()); +} diff --git a/plugins/icq/verifydlg.h b/plugins/icq/verifydlg.h new file mode 100644 index 0000000..312516a --- /dev/null +++ b/plugins/icq/verifydlg.h @@ -0,0 +1,41 @@ +/*************************************************************************** + verifydlg.h - description + ------------------- + begin : Sun Nov 27 2005 + copyright : (C) 2005 by Andrey Rahmatullin + email : wrar@altlinux.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _VERIFYDLG_H +#define _VERIFYDLG_H + +#include "event.h" +#include "ui_verifydlgbase.h" +#include +#include + +class QPixmap; + +class VerifyDlg : public QDialog, public Ui::VerifyDlgBase, public SIM::EventReceiver +{ + Q_OBJECT +public: + VerifyDlg(QWidget *parent, const QPixmap& picture); + ~VerifyDlg(); + const QString getVerifyString() const { return edtVerify->text(); }; +protected slots: + void changed(); + void changed(const QString& text); +}; + +#endif + diff --git a/plugins/icq/verifydlgbase.ui b/plugins/icq/verifydlgbase.ui new file mode 100644 index 0000000..79644d6 --- /dev/null +++ b/plugins/icq/verifydlgbase.ui @@ -0,0 +1,262 @@ + + + + + VerifyDlgBase + + + + 0 + 0 + 317 + 231 + + + + Verification Dialog + + + true + + + + + + + + + 40 + 20 + + + + QSizePolicy::Expanding + + + Qt::Horizontal + + + + + + + true + + + + 0 + 0 + 0 + 0 + + + + + 240 + 100 + + + + true + + + false + + + + + + + + 40 + 20 + + + + QSizePolicy::Expanding + + + Qt::Horizontal + + + + + + + + + + + + 40 + 20 + + + + QSizePolicy::Expanding + + + Qt::Horizontal + + + + + + + Please retype the letters from the picture above: + + + edtVerify + + + false + + + + + + + + 40 + 20 + + + + QSizePolicy::Expanding + + + Qt::Horizontal + + + + + + + + + + + + 40 + 20 + + + + QSizePolicy::Expanding + + + Qt::Horizontal + + + + + + + + + + + 40 + 20 + + + + QSizePolicy::Expanding + + + Qt::Horizontal + + + + + + + + + + 20 + 12 + + + + QSizePolicy::Expanding + + + Qt::Vertical + + + + + + + 0 + + + 6 + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Horizontal + + + + + + + &OK + + + + + + true + + + true + + + + + + + &Cancel + + + + + + true + + + + + + + + + qPixmapFromMimeSource + + + buttonOk + clicked() + VerifyDlg + accept() + + + buttonCancel + clicked() + VerifyDlg + reject() + + + diff --git a/plugins/icq/warndlg.cpp b/plugins/icq/warndlg.cpp new file mode 100644 index 0000000..1800afe --- /dev/null +++ b/plugins/icq/warndlg.cpp @@ -0,0 +1,99 @@ +/*************************************************************************** + warndlg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "icons.h" +#include "warndlg.h" +#include "simgui/ballonmsg.h" +#include "icqclient.h" +#include "icqmessage.h" +#include "contacts/contact.h" + +#include +#include +#include +#include +#include +#include + +using namespace SIM; + +WarnDlg::WarnDlg(QWidget *parent, ICQUserData *data, ICQClient *client) + : QDialog(parent) +{ + setupUi(this); + setModal(true); + setAttribute(Qt::WA_DeleteOnClose); + SET_WNDPROC("warn") + setWindowIcon(Icon("error")); + setButtonsPict(this); + setWindowTitle(windowTitle()); + m_client = client; + m_data = data; + m_msg = NULL; + m_contact = 0; + Contact *contact; + if (m_client->findContact(client->screen(data), NULL, false, contact)) + m_contact = contact->id(); + lblInfo->setText(lblInfo->text().replace(QRegExp("\\%1"), m_client->screen(data))); + chkAnon->setChecked(m_client->getWarnAnonimously()); +} + +WarnDlg::~WarnDlg() +{ + if (m_msg) + EventMessageCancel(m_msg).process(); +} + +void WarnDlg::accept() +{ + m_msg = new WarningMessage; + m_msg->setClient(m_client->dataName(m_data)); + m_msg->setContact(m_contact); + m_msg->setAnonymous(chkAnon->isChecked()); + m_client->setWarnAnonimously(chkAnon->isChecked()); + if (!((Client*)m_client)->send(m_msg, m_data)){ + delete m_msg; + m_msg = NULL; + showError(I18N_NOOP("Send failed")); + return; + } + buttonOk->setEnabled(false); +} + +void WarnDlg::showError(const char *error) +{ + buttonOk->setEnabled(true); + BalloonMsg::message(i18n(error), buttonOk); +} + +bool WarnDlg::processEvent(Event *e) +{ + if (e->type() == eEventMessageSent){ + EventMessage *em = static_cast(e); + Message *msg = em->msg(); + if (msg == m_msg){ + m_msg = false; + QString err = msg->getError(); + if (!err.isEmpty()){ + showError(qPrintable(err)); + }else{ + QTimer::singleShot(0, this, SLOT(close())); + } + } + } + return false; +} diff --git a/plugins/icq/warndlg.h b/plugins/icq/warndlg.h new file mode 100644 index 0000000..78cb5f7 --- /dev/null +++ b/plugins/icq/warndlg.h @@ -0,0 +1,43 @@ +/*************************************************************************** + warndlg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _WARNDLG_H +#define _WARNDLG_H + +#include "ui_warndlgbase.h" +#include "icqclient.h" + +class WarningMessage; + +class WarnDlg : public QDialog, public Ui::WarnDlgBase, public SIM::EventReceiver +{ + Q_OBJECT +public: + WarnDlg(QWidget *parent, ICQUserData *data, ICQClient *client); + ~WarnDlg(); +protected: + void accept(); + virtual bool processEvent(SIM::Event *e); + void showError(const char*); + ICQClient *m_client; + ICQUserData *m_data; + unsigned m_contact; + WarningMessage *m_msg; +}; + +#endif + diff --git a/plugins/icq/warndlgbase.ui b/plugins/icq/warndlgbase.ui new file mode 100644 index 0000000..6a8f817 --- /dev/null +++ b/plugins/icq/warndlgbase.ui @@ -0,0 +1,128 @@ + + + + + WarnDlgBase + + + + 0 + 0 + 374 + 193 + + + + Send warning + + + true + + + + 11 + + + 6 + + + + + Click OK to send warning to %1. This will raise %1's warning and limit his or her activity. Do this only if %1 has done something to merit a warning. + + + Qt::AlignVCenter|Qt::AlignLeft + + + true + + + + + + + Warn &anonymously + + + + + + + Check this if you don't want your screen name revealed. +Anonymous warnings are less severe. + + + Qt::AlignTop|Qt::AlignLeft + + + true + + + + + + + 0 + + + 6 + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Horizontal + + + + + + + &OK + + + true + + + true + + + + + + + &Cancel + + + true + + + + + + + + qPixmapFromMimeSource + + + buttonOk + clicked() + WarningDlg + accept() + + + buttonCancel + clicked() + WarningDlg + reject() + + + diff --git a/plugins/icq/workinfo.cpp b/plugins/icq/workinfo.cpp new file mode 100644 index 0000000..5c116ab --- /dev/null +++ b/plugins/icq/workinfo.cpp @@ -0,0 +1,159 @@ +/*************************************************************************** + workinfo.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "icons.h" +#include "workinfo.h" +#include "icqclient.h" +#include "contacts/contact.h" + +#include +#include +#include + +using namespace SIM; + +WorkInfo::WorkInfo(QWidget *parent, ICQUserData *data, unsigned contact, ICQClient *client) : QWidget(parent) +{ + setupUi(this); + m_data = data; + m_client = client; + m_contact = contact; + btnSite->setIcon(Icon("home")); + connect(btnSite, SIGNAL(clicked()), this, SLOT(goUrl())); + if (m_data){ + edtAddress->setReadOnly(true); + edtCity->setReadOnly(true); + edtState->setReadOnly(true); + edtZip->setReadOnly(true); + disableWidget(cmbCountry); + disableWidget(cmbOccupation); + edtName->setReadOnly(true); + edtDept->setReadOnly(true); + edtPosition->setReadOnly(true); + edtSite->setReadOnly(true); + }else{ + connect(edtSite, SIGNAL(textChanged(const QString&)), this, SLOT(urlChanged(const QString&))); + } + fill(); +} + +void WorkInfo::apply() +{ +} + +bool WorkInfo::processEvent(Event *e) +{ + if (e->type() == eEventContact){ + EventContact *ec = static_cast(e); + if(ec->action() != EventContact::eChanged) + return false; + Contact *contact = ec->contact(); + if (contact->clientData.have(m_data)) + fill(); + } else + if ((e->type() == eEventClientChanged) && (m_data == 0)){ + EventClientChanged *ecc = static_cast(e); + if (ecc->client() == m_client) + fill(); + } + return false; +} + +static const ext_info occupations[] = + { + { I18N_NOOP("Academic"), 1 }, + { I18N_NOOP("Administrative"), 2 }, + { I18N_NOOP("Art/Entertainment"), 3 }, + { I18N_NOOP("College Student"), 4 }, + { I18N_NOOP("Computers"), 5 }, + { I18N_NOOP("Community & Social"), 6 }, + { I18N_NOOP("Education"), 7 }, + { I18N_NOOP("Engineering"), 8 }, + { I18N_NOOP("Financial Services"), 9 }, + { I18N_NOOP("Government"), 10 }, + { I18N_NOOP("High School Student"), 11 }, + { I18N_NOOP("Home"), 12 }, + { I18N_NOOP("ICQ - Providing Help"), 13 }, + { I18N_NOOP("Law"), 14 }, + { I18N_NOOP("Managerial"), 15 }, + { I18N_NOOP("Manufacturing"), 16 }, + { I18N_NOOP("Medical/Health"), 17 }, + { I18N_NOOP("Military"), 18 }, + { I18N_NOOP("Non-Goverment Organisation"), 19 }, + { I18N_NOOP("Professional"), 20 }, + { I18N_NOOP("Retail"), 21 }, + { I18N_NOOP("Retired"), 22 }, + { I18N_NOOP("Science & Research"), 23 }, + { I18N_NOOP("Sports"), 24 }, + { I18N_NOOP("Technical"), 25 }, + { I18N_NOOP("University student"), 26 }, + { I18N_NOOP("Web building"), 27 }, + { I18N_NOOP("Other services"), 99 }, + { "", 0 } + }; + +const ext_info *p_occupations = occupations; + +void WorkInfo::fill() +{ + ICQUserData *data = m_data; + if (data == NULL) + data = &m_client->data.owner; + edtAddress->setPlainText(data->WorkAddress.str()); + edtCity->setText(data->WorkCity.str()); + edtState->setText(data->WorkState.str()); + edtZip->setText(data->WorkZip.str()); + initCombo(cmbCountry, data->WorkCountry.toULong(), getCountries()); + initCombo(cmbOccupation, data->Occupation.toULong(), occupations); + edtName->setText(data->WorkName.str()); + edtDept->setText(data->WorkDepartment.str()); + edtPosition->setText(data->WorkPosition.str()); + edtSite->setText(data->WorkHomepage.str()); + urlChanged(edtSite->text()); +} + +void WorkInfo::goUrl() +{ + QString url = edtSite->text(); + if (url.isEmpty()) + return; + EventGoURL e(url); + e.process(); +} + +void WorkInfo::urlChanged(const QString &text) +{ + btnSite->setEnabled(!text.isEmpty()); +} + +void WorkInfo::apply(Client *client, void *_data) +{ + if (client != m_client) + return; + ICQUserData *data = m_client->toICQUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + data->WorkAddress.str() = edtAddress->toPlainText(); + data->WorkCity.str() = edtCity->text(); + data->WorkState.str() = edtState->text(); + data->WorkZip.str() = edtZip->text(); + data->WorkCountry.asULong() = getComboValue(cmbCountry, getCountries()); + data->Occupation.asULong() = getComboValue(cmbOccupation, occupations); + data->WorkName.str() = edtName->text(); + data->WorkDepartment.str() = edtDept->text(); + data->WorkPosition.str() = edtPosition->text(); + data->WorkHomepage.str() = edtSite->text(); +} + diff --git a/plugins/icq/workinfo.h b/plugins/icq/workinfo.h new file mode 100644 index 0000000..9da93c8 --- /dev/null +++ b/plugins/icq/workinfo.h @@ -0,0 +1,46 @@ +/*************************************************************************** + workinfo.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _WORKINFO_H +#define _WORKINFO_H + +#include "ui_workinfobase.h" +#include "event.h" + +class ICQClient; +struct ICQUserData; + +class WorkInfo : public QWidget, public Ui::WorkInfo, public SIM::EventReceiver +{ + Q_OBJECT +public: + WorkInfo(QWidget *parent, ICQUserData *data, unsigned contact, ICQClient *client); +public slots: + void apply(); + void apply(SIM::Client*, void*); + void goUrl(); + void urlChanged(const QString&); +protected: + virtual bool processEvent(SIM::Event *e); + void fill(); + ICQUserData *m_data; + unsigned m_contact; + ICQClient *m_client; +}; + +#endif + diff --git a/plugins/icq/workinfobase.ui b/plugins/icq/workinfobase.ui new file mode 100644 index 0000000..b4b995a --- /dev/null +++ b/plugins/icq/workinfobase.ui @@ -0,0 +1,275 @@ + + + WorkInfo + + + + 0 + 0 + 387 + 338 + + + + Form2 + + + + 6 + + + 11 + + + + + + &Company + + + + 11 + + + 6 + + + + + Address: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + City: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + State: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Zip code: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + Country: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Name: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + 6 + + + 0 + + + + + + + + + 0 + 0 + + + + + 22 + 22 + + + + + + + + + + + + + Web site: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + + &Occupation + + + + 11 + + + 6 + + + + + Occupation: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + Div / dept: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + + + + Position: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + + + + edtCity + edtState + edtZip + cmbCountry + edtName + edtSite + btnSite + TabWidget2 + edtDept + edtPosition + cmbOccupation + + + + diff --git a/plugins/icq/xml.cpp b/plugins/icq/xml.cpp new file mode 100644 index 0000000..cbbf142 --- /dev/null +++ b/plugins/icq/xml.cpp @@ -0,0 +1,219 @@ +/* + * XML Parser/Generator + * + * Copyright (C) 2001 Barnaby Gray . + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "xml.h" + +using namespace std; + +// ---------- XmlNode --------------------------- + +XmlNode::XmlNode(const string& t) : tag(t) { } + +XmlNode::~XmlNode() { } + +bool XmlNode::isLeaf() { return !isBranch(); } + +string XmlNode::getTag() { return tag; } + +string XmlNode::replace_all(const string& s, const string& r1, const string& r2) { + string t(s.c_str()); + int curr = 0, next; + while ( (next = t.find( r1, curr )) != -1) { + t.replace( next, r1.size(), r2 ); + curr = next + r2.size(); + } + return t; +} + +string XmlNode::quote(const string& a) { + return + replace_all( + replace_all( + replace_all(a, + "&", "&"), + "<", "<"), + ">", ">"); +} + +string XmlNode::unquote(const string& a) { + return + replace_all( + replace_all( + replace_all(a, + "<", "<"), + ">", ">"), + "&", "&"); +} + +XmlNode *XmlNode::parse(string::iterator& curr, string::iterator end) { + + skipWS(curr,end); + if (curr == end || *curr != '<') return NULL; + + string tag = parseTag(curr,end); + if (tag.empty() || tag[0] == '/') return NULL; + + skipWS(curr,end); + if (curr == end) return NULL; + + if (*curr == '<') { + + XmlNode *p = NULL; + while (curr != end) { + string::iterator mark = curr; + string nexttag = parseTag(curr,end); + if (nexttag.empty()) { if (p != NULL) delete p; return NULL; } + if (nexttag[0] == '/') { + // should be the closing + if (nexttag.size() == tag.size()+1 && nexttag.find(tag,1) == 1) { + // is closing tag + if (p == NULL) p = new XmlLeaf(unquote(tag),""); + return p; + } else { + if (p != NULL) delete p; + return NULL; + } + } else { + if (p == NULL) p = new XmlBranch(unquote(tag)); + // an opening tag + curr = mark; + XmlNode *c = parse(curr,end); + if (c != NULL) ((XmlBranch*)p)->pushnode(c); + } + skipWS(curr,end); + if(curr == end || *curr != '<') { + if (p != NULL) delete p; + + } + } + return NULL; + + } + // XmlLeaf + string value; + while (curr != end && *curr != '<') { + value += *curr; + curr++; + } + if(curr == end) return NULL; + string nexttag = parseTag(curr,end); + if (nexttag.empty() || nexttag[0] != '/') return NULL; + if (nexttag.size() == tag.size()+1 && nexttag.find(tag,1) == 1) { + return new XmlLeaf(unquote(tag),unquote(value)); + } + // error + return NULL; +} + +string XmlNode::parseTag(string::iterator& curr, string::iterator end) { + string tag; + if(curr == end || *curr != '<') return string(); + curr++; + while(curr != end && *curr != '>') { + tag += *curr; + curr++; + } + if (curr == end) return string(); + curr++; + return tag; +} + +void XmlNode::skipWS(string::iterator& curr, string::iterator end) { + while(curr != end && isspace(*curr)) curr++; +} + +// ----------- XmlBranch ------------------------ + +XmlBranch::XmlBranch(const string& t) : XmlNode(t) { } + +XmlBranch::~XmlBranch() { + list::iterator curr = children.begin(); + while (curr != children.end()) { + delete (*curr); + curr++; + } + children.clear(); +} + +bool XmlBranch::isBranch() { return true; } + +bool XmlBranch::exists(const string& tag) { + list::iterator curr = children.begin(); + while (curr != children.end()) { + if ((*curr)->getTag() == tag) return true; + curr++; + } + return false; +} + +XmlNode *XmlBranch::getNode(const string& tag) { + list::iterator curr = children.begin(); + while (curr != children.end()) { + if ((*curr)->getTag() == tag) return (*curr); + curr++; + } + return NULL; +} + +XmlBranch *XmlBranch::getBranch(const string& tag) { + XmlNode *t = getNode(tag); + if (t == NULL || !t->isBranch()) return NULL; + return static_cast(t); +} + +XmlLeaf *XmlBranch::getLeaf(const string& tag) { + XmlNode *t = getNode(tag); + if (t == NULL || !t->isLeaf()) return NULL; + return static_cast(t); +} + +void XmlBranch::pushnode(XmlNode *c) { + children.push_back(c); +} + +string XmlBranch::toString(int n) { + string ret(n,'\t'); + ret += '<' + quote(tag) + ">\n"; + list::iterator curr = children.begin(); + while (curr != children.end()) { + ret += (*curr)->toString(n+1); + curr++; + } + ret += string(n,'\t') + "\n"; + + return ret; +} + +// ----------- XmlLeaf -------------------------- + +XmlLeaf::XmlLeaf(const string& t, const string& v) + : XmlNode(t), value(v) { } + +XmlLeaf::~XmlLeaf() { } + +bool XmlLeaf::isBranch() { return false; } + +string XmlLeaf::getValue() { return value; } + +string XmlLeaf::toString(int n) { + return string(n,'\t') + '<' + quote(tag) + '>' + quote(value) + "\n"; +} + diff --git a/plugins/icq/xml.h b/plugins/icq/xml.h new file mode 100644 index 0000000..1f49b0c --- /dev/null +++ b/plugins/icq/xml.h @@ -0,0 +1,94 @@ +/* + * XML Parser/Generator + * Simple XML parser/generator sufficient to + * send+receive the XML in ICQ SMS messages + * Copyright (C) 2001 Barnaby Gray . + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef XML_H +#define XML_H + +#include +#include +#include + +class XmlNode { +private: + static std::string parseTag(std::string::iterator& curr, std::string::iterator end); + static void skipWS(std::string::iterator& curr, std::string::iterator end); + +protected: + std::string tag; + + XmlNode(const std::string& t); + +public: + virtual ~XmlNode(); + + virtual bool isBranch() = 0; + bool isLeaf(); + + std::string getTag(); + + static XmlNode *parse(std::string::iterator& start, std::string::iterator end); + + static std::string quote(const std::string& s); + static std::string unquote(const std::string& s); + static std::string replace_all(const std::string& s, const std::string& r1, const std::string& r2); + + virtual std::string toString(int n) = 0; +}; + +class XmlLeaf; + +class XmlBranch : public XmlNode { +private: + std::list children; + +public: + XmlBranch(const std::string& t); + ~XmlBranch(); + + bool isBranch(); + bool exists(const std::string& tag); + XmlNode *getNode(const std::string& tag); + XmlBranch *getBranch(const std::string& tag); + XmlLeaf *getLeaf(const std::string& tag); + + void pushnode(XmlNode *c); + + std::string toString(int n); + +}; + +class XmlLeaf : public XmlNode { +private: + std::string value; +public: + XmlLeaf(const std::string& t, const std::string& v); + ~XmlLeaf(); + + bool isBranch(); + std::string getValue(); + + std::string toString(int n); + +}; + +#endif + diff --git a/plugins/jabber/CMakeLists.txt b/plugins/jabber/CMakeLists.txt new file mode 100644 index 0000000..34a1216 --- /dev/null +++ b/plugins/jabber/CMakeLists.txt @@ -0,0 +1,68 @@ +################## +# jabber library # +################## +SET(jabber_SRCS + discoinfo.cpp + httppoll.cpp + infoproxy.cpp + jabber.cpp + jabber_auth.cpp + jabber_rosters.cpp + jabber_ssl.cpp + jabberaboutinfo.cpp + jabberadd.cpp + jabberbrowser.cpp + jabberbuffer.cpp + jabberclient.cpp + jabberconfig.cpp + jabberfiletransfer.cpp + jabberhomeinfo.cpp + jabberinfo.cpp + jabbermessage.cpp + jabberpicture.cpp + jabbersearch.cpp + jabberstatus.cpp + jabberworkinfo.cpp + jidadvsearch.cpp + jidsearch.cpp +) + +SET(jabber_HDRS + discoinfo.h + infoproxy.h + jabber.h + jabber_events.h + jabber_ssl.h + jabberaboutinfo.h + jabberadd.h + jabberbrowser.h + jabberbuffer.h + jabberclient.h + jabberconfig.h + jabberhomeinfo.h + jabberinfo.h + jabbermessage.h + jabberpicture.h + jabbersearch.h + jabberstatus.h + jabberworkinfo.h + jidadvsearch.h + jidsearch.h +) + +SET(jabber_UICS + discoinfobase.ui + infoproxybase.ui + jabberaboutinfobase.ui + jabberaddbase.ui + jabberconfigbase.ui + jabberhomeinfobase.ui + jabberinfobase.ui + jabberpicturebase.ui + jabberworkinfobase.ui + jidadvsearchbase.ui + jidsearchbase.ui +) + +SIM_ADD_PLUGIN(jabber) + diff --git a/plugins/jabber/discoinfo.cpp b/plugins/jabber/discoinfo.cpp new file mode 100644 index 0000000..da1b0f1 --- /dev/null +++ b/plugins/jabber/discoinfo.cpp @@ -0,0 +1,310 @@ +/*************************************************************************** + discoinfo.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include +#include +#include + +#include "icons.h" +#include "simgui/listview.h" +#include "misc.h" + +#include "jabberclient.h" +#include "discoinfo.h" +#include "jabberbrowser.h" +#include "jabber.h" +#include "jabberaboutinfo.h" + +using namespace SIM; + +extern DataDef jabberUserData[]; + +DiscoInfo::DiscoInfo(JabberBrowser *browser, const QString &features, + const QString &name, const QString &type, const QString &category) : QDialog(browser) +{ + setupUi(this); + setAttribute(Qt::WA_DeleteOnClose,true); + m_browser = browser; + SET_WNDPROC("jbrowser") + setWindowIcon(Icon("Jabber_online")); + setTitle(); + setButtonsPict(this); + connect(buttonApply, SIGNAL(clicked()), this, SLOT(apply())); + m_bTime = true; + m_bLast = true; + m_bStat = true; + m_bVCard = true; + m_about = NULL; + m_features = features; + m_name = name; + m_type = type; + m_category = category; + load_data(jabberUserData, &m_data, NULL); + disableWidget(edtJName); + disableWidget(edtType); + disableWidget(edtCategory); + edtNameSpace->setReadOnly(true); + disableWidget(edtName); + disableWidget(edtVersion); + disableWidget(edtSystem); + disableWidget(edtTime); + disableWidget(edtLast); + lstStat->addColumn(i18n("Name")); + lstStat->addColumn(i18n("Units")); + lstStat->addColumn(i18n("Value")); + lstStat->setExpandingColumn(2); + btnUrl->setIcon(Icon("home")); + connect(btnUrl, SIGNAL(clicked()), this, SLOT(goUrl())); + connect(edtUrl, SIGNAL(textChanged(const QString&)), this, SLOT(urlChanged(const QString&))); +} + +DiscoInfo::~DiscoInfo() +{ + free_data(jabberUserData, &m_data); + m_browser->m_info = NULL; +} + +void DiscoInfo::setTitle() +{ + setWindowTitle(m_url); +} + +void DiscoInfo::reset() +{ + if (m_about){ + tabInfo->removeTab(tabInfo->indexOf(m_about)); + delete m_about; + m_about = NULL; + } + if (m_browser->m_list->currentItem()){ + m_url = m_browser->m_list->currentItem()->text(COL_JID); + m_node = m_browser->m_list->currentItem()->text(COL_NODE); + } + free_data(jabberUserData, &m_data); + load_data(jabberUserData, &m_data, NULL); + m_data.ID.str() = m_url; + m_data.Node.str() = m_node; + setTitle(); + edtJName->setText(m_name); + edtType->setText(m_type); + edtCategory->setText(m_category); + edtNameSpace->setPlainText(m_features); + bool bTime = false; + bool bLast = false; + bool bStat = false; + bool bVCard = false; + QString mf = m_features; + while (!mf.isEmpty()){ + QString f = getToken(mf, '\n'); + if (f == "jabber:iq:time") + bTime = true; + if (f == "jabber:iq:last") + bLast = true; + if (f == "http://jabber.org/protocol/stats") + bStat = true; + if (f == "vcard-temp") + bVCard = true; + } + int pos = 2; + edtName->setText(QString::null); + edtVersion->setText(QString::null); + edtSystem->setText(QString::null); + m_browser->m_client->versionInfo(m_url, m_node); + if ((bTime || bLast) != (m_bTime || m_bLast)){ + m_bTime = bTime; + m_bLast = bLast; + if (m_bTime || m_bLast){ + tabInfo->insertTab(pos++, tabTime, i18n("&Time")); + }else{ + tabInfo->removeTab(tabInfo->indexOf(tabTime)); + } + }else if (m_bTime || m_bLast){ + pos++; + } + edtTime->setText(QString::null); + edtLast->setText(QString::null); + if (m_bTime){ + edtTime->show(); + m_browser->m_client->timeInfo(m_url, m_node); + }else{ + edtTime->hide(); + } + if (m_bLast){ + edtLast->show(); + m_browser->m_client->lastInfo(m_url, m_node); + }else{ + edtLast->hide(); + } + lstStat->clear(); + if (bStat != m_bStat){ + m_bStat = bStat; + if (m_bStat){ + tabInfo->insertTab(pos++, tabStat, i18n("&Stat")); + }else{ + tabInfo->removeTab(tabInfo->indexOf(tabStat)); + } + }else if (m_bStat){ + pos++; + } + m_statId = m_bStat ? m_browser->m_client->statInfo(m_url, m_node) : QString::null; + if (bVCard != m_bVCard){ + m_bVCard = bVCard; + if (m_bVCard || m_bVCard){ + tabInfo->insertTab(pos++, tabVCard, i18n("&Info")); + }else{ + tabInfo->removeTab(tabInfo->indexOf(tabVCard)); + } + }else if (m_bVCard){ + pos++; + } + edtFirstName->setText(QString::null); + edtNick->setText(QString::null); + edtBirthday->setText(QString::null); + edtUrl->setText(QString::null); + edtEMail->setText(QString::null); + edtPhone->setText(QString::null); + if (bVCard){ + m_about = new JabberAboutInfo(tabInfo, &m_data, m_browser->m_client); + tabInfo->insertTab(pos++, m_about, i18n("About info")); + m_browser->m_client->info_request(&m_data, true); + } +} + +bool DiscoInfo::processEvent(Event *e) +{ + if (e->type() == eEventVCard){ + EventVCard *evc = static_cast(e); + JabberUserData *data = evc->data(); + if (m_data.ID.str() == data->ID.str() && m_data.Node.str() == data->Node.str()){ + edtFirstName->setText(data->FirstName.str()); + edtNick->setText(data->Nick.str()); + edtBirthday->setText(data->Bday.str()); + edtUrl->setText(data->Url.str()); + urlChanged(edtUrl->text()); + edtEMail->setText(data->EMail.str()); + edtPhone->setText(data->Phone.str()); + } + } else + if (e->type() == eEventDiscoItem){ + EventDiscoItem *edi = static_cast(e); + DiscoItem *item = edi->item(); + if (m_statId == item->id){ + if (item->jid.isEmpty()){ + m_statId = QString::null; + return true; + } + ListViewItem *i = new ListViewItem(lstStat); + i->setText(0, item->jid); + i->setText(1, item->name); + i->setText(2, item->node); + return true; + } + } else + if (e->type() == eEventClientVersion){ + EventClientVersion *ecv = static_cast(e); + ClientVersionInfo* info = ecv->info(); + if (m_data.ID.str() == info->jid && m_data.Node.str() == info->node){ + edtName->setText(info->name); + edtVersion->setText(info->version); + edtSystem->setText(info->os); + } + } else + if (e->type() == eEventClientLastInfo){ + EventClientLastInfo *ecli = static_cast(e); + ClientLastInfo* info = ecli->info(); + if (m_data.ID.str() == info->jid){ + unsigned ss = info->seconds; + unsigned mm = ss / 60; + ss -= mm * 60; + unsigned hh = mm / 60; + mm -= hh * 60; + unsigned dd = hh / 24; + hh -= dd * 24; + QString date; + if (dd){ + date = i18n("%n day", "%n days", dd); + date += ' '; + } + QString time; + time.sprintf("%02u:%02u:%02u", hh, mm, ss); + date += time; + edtLast->setText(date); + } + } else + if (e->type() == eEventClientTimeInfo){ + EventClientTimeInfo *ecti = static_cast(e); + ClientTimeInfo* info = ecti->info(); + if (m_data.ID.str() == info->jid){ + /* + if (!info->display.isEmpty()) + edtTime->setText(info->display); + else + */ + edtTime->setText(info->utc); + } + } + return false; +} + +void DiscoInfo::resizeEvent(QResizeEvent *e) +{ + QDialog::resizeEvent(e); + lstStat->adjustColumn(); +} + +void DiscoInfo::accept() +{ + apply(); + QDialog::accept(); +} + +void DiscoInfo::apply() +{ + if (m_bVCard && m_about){ + m_about->apply(m_browser->m_client, &m_data); + m_data.FirstName.str() = edtFirstName->text(); + m_data.Nick.str() = edtNick->text(); + m_data.Bday.str() = edtBirthday->text(); + m_data.Url.str() = edtUrl->text(); + m_data.EMail.str() = edtEMail->text(); + m_data.Phone.str() = edtPhone->text(); + m_browser->m_client->setClientInfo(&m_data); + } +} + +void DiscoInfo::goUrl() +{ + QString url = edtUrl->text(); + if (url.isEmpty()) + return; + EventGoURL e(url); + e.process(); +} + +void DiscoInfo::urlChanged(const QString &text) +{ + btnUrl->setEnabled(!text.isEmpty()); +} + +/* +#ifndef NO_MOC_INCLUDES +#include "discoinfo.moc" +#endif +*/ + diff --git a/plugins/jabber/discoinfo.h b/plugins/jabber/discoinfo.h new file mode 100644 index 0000000..9cc1a8d --- /dev/null +++ b/plugins/jabber/discoinfo.h @@ -0,0 +1,65 @@ +/*************************************************************************** + discoinfo.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _DISCOINFO_H +#define _DISCOINFO_H + +#include "jabberclient.h" +#include "ui_discoinfobase.h" + +#include + +class JabberBrowser; +class JabberHomeInfo; +class JabberWorkInfo; +class JabberAboutInfo; + +class DiscoInfo : public QDialog, public Ui::DiscoInfo, public SIM::EventReceiver +{ + Q_OBJECT +public: + DiscoInfo(JabberBrowser *browser, const QString &features, + const QString &name, const QString &type, const QString &category); + ~DiscoInfo(); + void reset(); +protected slots: + void apply(); + void goUrl(); + void urlChanged(const QString &text); +protected: + void accept(); + QString m_url; + QString m_node; + QString m_features; + QString m_name; + QString m_type; + QString m_category; + virtual bool processEvent(SIM::Event *e); + void resizeEvent(QResizeEvent*); + void setTitle(); + bool m_bTime; + bool m_bLast; + bool m_bStat; + bool m_bVCard; + JabberBrowser *m_browser; + QString m_statId; + JabberAboutInfo *m_about; + JabberUserData m_data; +}; + +#endif + diff --git a/plugins/jabber/discoinfobase.ui b/plugins/jabber/discoinfobase.ui new file mode 100644 index 0000000..8cc7096 --- /dev/null +++ b/plugins/jabber/discoinfobase.ui @@ -0,0 +1,522 @@ + + + DiscoInfo + + + + 0 + 0 + 451 + 308 + + + + DiscoInfo + + + true + + + + 6 + + + 11 + + + + + + &Info + + + + 11 + + + 6 + + + + + Namespaces: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + Category: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Type: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + + + + Name: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + + &Version + + + + 11 + + + 6 + + + + + Name: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Version: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + System: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + &Time + + + + 11 + + + 6 + + + + + UTC client time: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + + + + Last activity, idle response: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + &Statistic + + + + 6 + + + 11 + + + + + + + + + + + + + &Info + + + + 11 + + + 6 + + + + + Nick: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + Homepage: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Birth date: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + + + + First Name: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + 6 + + + 0 + + + + + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + EMail: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Phone: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + + + + + 6 + + + 0 + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + &Apply + + + true + + + + + + + &OK + + + true + + + true + + + + + + + &Close + + + true + + + + + + + + + + ListView + QWidget +
simgui/listview.h
+
+
+ + tabInfo + edtJName + edtType + edtCategory + edtName + edtVersion + edtSystem + edtTime + edtLast + buttonCancel + + + + + buttonCancel + clicked() + DiscoInfo + reject() + + + 20 + 20 + + + 20 + 20 + + + + + buttonOk + clicked() + DiscoInfo + accept() + + + 20 + 20 + + + 20 + 20 + + + + +
diff --git a/plugins/jabber/httppoll.cpp b/plugins/jabber/httppoll.cpp new file mode 100644 index 0000000..0925355 --- /dev/null +++ b/plugins/jabber/httppoll.cpp @@ -0,0 +1,184 @@ +/*************************************************************************** + httppool.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "simapi.h" + +#include "fetch.h" +#include "log.h" + +#include "jabberclient.h" +#include +#include + +using namespace SIM; + +class JabberHttpPool : public Socket, public FetchClient +{ +public: + JabberHttpPool(const QString &url); + ~JabberHttpPool(); + virtual void connect(const QString &host, unsigned short port); + virtual int read(char *buf, unsigned size); + virtual void write(const char *buf, unsigned size); + virtual void close(); + virtual Mode mode() const { return Web; } + virtual bool isEncrypted(){ return false; } + virtual bool startEncryption(){ return false; } +protected: + QString getKey(); + virtual bool done(unsigned code, Buffer &data, const QString &headers); + JabberBuffer readData; + JabberBuffer writeData; + QString m_url; + QByteArray m_key; + QByteArray m_seed; + QString m_cookie; + virtual unsigned long localHost(); + virtual void pause(unsigned); +}; + +// ______________________________________________________________________________________ + +JabberHttpPool::JabberHttpPool(const QString &url) + : m_url(url) +{ + m_cookie = "0"; +/* + Buffer k; + for (unsigned i = 0; i < 48; i++){ + char c = get_random() & 0xFF; + k.pack(&c, 1); + } + m_seed += k.toBase64(); +*/ + m_seed = "foo"; +} + +JabberHttpPool::~JabberHttpPool() +{ +} + +QString JabberHttpPool::getKey() +{ + if (m_key.isEmpty()){ + m_key = m_seed; + return m_key; + } + QByteArray digest = QCryptographicHash::hash(m_key, QCryptographicHash::Sha1); + Buffer b; + b.pack(digest, digest.size()); + m_key = b.toBase64(); + return m_key; +} + +int JabberHttpPool::read(char *buf, unsigned size) +{ + unsigned tail = readData.size() - readData.readPos(); + if (size > tail) size = tail; + if (size == 0) return 0; + readData.unpack(buf, size); + if (readData.readPos() == (unsigned)readData.size()) + readData.init(0); + return size; +} + +void JabberHttpPool::write(const char *buf, unsigned size) +{ + writeData.pack(buf, size); + if (!isDone()) + return; + Buffer *packet = new Buffer; + *packet << (const char*)m_cookie.toLocal8Bit().data(); + *packet << ";" << (const char*)getKey().toLocal8Bit().data(); + *packet << ","; + log(L_DEBUG, "%s;%s,", qPrintable(m_cookie), qPrintable(getKey())); + packet->pack(writeData.data(), writeData.writePos()); + char headers[] = "Content-Type: application/x-www-form-urlencoded"; + fetch(m_url, headers, packet); + writeData.init(0); +} + +void JabberHttpPool::close() +{ + writeData.init(0); + stop(); +} + +void JabberHttpPool::connect(const QString&, unsigned short) +{ + if (notify) + notify->connect_ready(); +} + +bool JabberHttpPool::done(unsigned code, Buffer &data, const QString &headers) +{ + if (code != 200){ + log(L_DEBUG, "HTTP result %u", code); + error("Bad result"); + return false; + } + QString cookie; + int idx = headers.indexOf("Set-Cookie:"); + if(idx != -1) { + int end = headers.indexOf("\n", idx); + if(end == -1) + m_cookie = headers.mid(idx); + else + m_cookie = headers.mid(end - idx + 1); + } + m_cookie = cookie; + int err_code = getToken(cookie, ':').toInt(); + if (cookie == "0"){ + const char *err = "Unknown poll error"; + switch (err_code){ + case -1: + err = "Server Error"; + break; + case -2: + err = "Bad Request"; + break; + case -3: + err = "Key Sequence Error"; + break; + } + error(err); + return false; + } + readData = data; + if (notify) + notify->read_ready(); + return false; +} + +unsigned long JabberHttpPool::localHost() +{ + return 0; +} + +void JabberHttpPool::pause(unsigned) +{ +} + +Socket *JabberClient::createSocket() +{ + m_bHTTP = getUseHTTP() && !getURL().isEmpty(); + if (m_bHTTP) + return new JabberHttpPool(getURL()); + return NULL; +} + + diff --git a/plugins/jabber/infoproxy.cpp b/plugins/jabber/infoproxy.cpp new file mode 100644 index 0000000..9e6cb1e --- /dev/null +++ b/plugins/jabber/infoproxy.cpp @@ -0,0 +1,49 @@ +/*************************************************************************** + infoproxy.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "infoproxy.h" + +#include + +using namespace SIM; + +InfoProxy::InfoProxy(QWidget *parent, QWidget *child, const QString &title) : QWidget(parent) + //: InfoProxyBase(parent) +{ + setupUi(this); + connect(this, SIGNAL(sig_apply()), child, SLOT(apply())); + connect(this, SIGNAL(sig_apply(SIM::Client*, void*)), child, SLOT(apply(SIM::Client*, void*))); + tabInfo->addTab(child, title); + tabInfo->removeTab(tabInfo->indexOf(tab)); +} + +void InfoProxy::apply() +{ + emit sig_apply(); +} + +void InfoProxy::apply(Client *client, void *data) +{ + emit sig_apply(client, data); +} + +/* +#ifndef NO_MOC_INCLUDES +#include "infoproxy.moc" +#endif +*/ + diff --git a/plugins/jabber/infoproxy.h b/plugins/jabber/infoproxy.h new file mode 100644 index 0000000..9616f80 --- /dev/null +++ b/plugins/jabber/infoproxy.h @@ -0,0 +1,38 @@ +/*************************************************************************** + infoproxy.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _INFOPROXY_H +#define _INFOPROXY_H + +#include "event.h" +#include "ui_infoproxybase.h" + +class InfoProxy : public QWidget, public Ui::InfoProxyBase, public SIM::EventReceiver +{ + Q_OBJECT +public: + InfoProxy(QWidget *parent, QWidget *child, const QString &title); +signals: + void sig_apply(); + void sig_apply(SIM::Client*, void*); +public slots: + void apply(); + void apply(SIM::Client*, void*); +}; + +#endif + diff --git a/plugins/jabber/infoproxybase.ui b/plugins/jabber/infoproxybase.ui new file mode 100644 index 0000000..a62dbe8 --- /dev/null +++ b/plugins/jabber/infoproxybase.ui @@ -0,0 +1,61 @@ + + + + + InfoProxyBase + + + + 0 + 0 + 429 + 279 + + + + Form1 + + + + 11 + + + 6 + + + + + + + + + + + + + + + QWidget + QWidget +
QWidget
+ + -1 + -1 + + 0 + + 5 + 5 + + image0 + + text + +
+
+ + + 789c6dd2c10ac2300c00d07bbf2234b7229d1be245fc04c5a3201e4615f430059d0711ff5ddb2e6bb236ec90eed134cb5a19d8ef36602af5ecdbfeeac05dda0798d3abebde87e3faa374d3807fa0d633a52d38d8de6f679fe33fc776e196f53cd010188256a3600a292882096246517815ca99884606e18044a3a40d91824820924265a7923a2e8bcd05f33db1173e002913175f2a6be6d3294871a2d95fa00e8a94ee017b69d339d90df1e77c57ea072ede6758 + + +
diff --git a/plugins/jabber/jabber.cpp b/plugins/jabber/jabber.cpp new file mode 100644 index 0000000..c224394 --- /dev/null +++ b/plugins/jabber/jabber.cpp @@ -0,0 +1,423 @@ +/*************************************************************************** + jabber.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "jabberclient.h" +#include "jabber.h" +#include "misc.h" +#include "core_consts.h" +#include "contacts/protocolmanager.h" +#include "clientmanager.h" +#include "icons.h" + +#include + +using namespace SIM; + +Plugin *createJabberPlugin(unsigned base, bool, Buffer *cfg) +{ + Plugin *plugin = new JabberPlugin(base, cfg); + return plugin; +} + +static PluginInfo info = + { + NULL, + NULL, + VERSION, + createJabberPlugin, + PLUGIN_PROTOCOL + }; + +EXPORT_PROC PluginInfo* GetPluginInfo() +{ + return &info; +} + +JabberProtocol::JabberProtocol(Plugin *plugin) + : Protocol(plugin) +{ + initStatuses(); +} + +JabberProtocol::~JabberProtocol() +{ +} + +void JabberProtocol::initStatuses() +{ + addStatus(JabberStatusPtr(new JabberStatus("online", "Online", true, "", Icon("Jabber_online"), QString::null, QString::null))); + addStatus(JabberStatusPtr(new JabberStatus("away", "Away", true, "", Icon("Jabber_away"), "away", QString::null))); + addStatus(JabberStatusPtr(new JabberStatus("n/a", "N/A", true, "", Icon("Jabber_na"), "xa", QString::null))); + addStatus(JabberStatusPtr(new JabberStatus("dnd", "Do not disturb", true, "", Icon("Jabber_dnd"), "dnd", QString::null))); + addStatus(JabberStatusPtr(new JabberStatus("occupied", "Occupied", true, "", Icon("Jabber_occupied"), "occupied", QString::null))); + addStatus(JabberStatusPtr(new JabberStatus("free_for_chat", "Free for chat", true, "", Icon("Jabber_ffc"), "chat", QString::null))); + addStatus(JabberStatusPtr(new JabberStatus("offline", "Offline", true, "", Icon("Jabber_offline"), QString::null, "unavailable"))); +} + +void JabberProtocol::addStatus(JabberStatusPtr status) +{ + m_statuses.append(status); +} + +QStringList JabberProtocol::statuses() +{ + QStringList list; + foreach(const JabberStatusPtr& status, m_statuses) { + list.append(status->id()); + } + return list; +} + +SIM::IMStatusPtr JabberProtocol::status(const QString& id) +{ + foreach(const JabberStatusPtr& status, m_statuses) { + if(status->id() == id) { + return status; + } + } + + return SIM::IMStatusPtr(); +} + +ClientPtr JabberProtocol::createClient(Buffer *cfg) +{ + ClientPtr jabber = ClientPtr(new JabberClient(this, cfg)); + getClientManager()->addClient(jabber); + return jabber; +} + +static CommandDef jabber_descr = + CommandDef ( + 0, + I18N_NOOP("Jabber"), + "Jabber_online", + "Jabber_invisible", + QString::null, + 0, + 0, + 0, + 0, + 0, + PROTOCOL_INFO | PROTOCOL_AR | PROTOCOL_INVISIBLE | PROTOCOL_SEARCH | PROTOCOL_AR_OFFLINE, + NULL, + QString::null + ); + +const CommandDef *JabberProtocol::description() +{ + return &jabber_descr; +} + +static CommandDef jabber_status_list[] = + { + CommandDef ( + STATUS_ONLINE, + I18N_NOOP("Online"), + "Jabber_online", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + STATUS_AWAY, + I18N_NOOP("Away"), + "Jabber_away", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + STATUS_NA, + I18N_NOOP("N/A"), + "Jabber_na", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + STATUS_DND, + I18N_NOOP("Do not Disturb"), + "Jabber_dnd", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + STATUS_OCCUPIED, + I18N_NOOP("Occupied"), + "Jabber_occupied", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + STATUS_FFC, + I18N_NOOP("Free for chat"), + "Jabber_ffc", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + STATUS_OFFLINE, + I18N_NOOP("Offline"), + "Jabber_offline", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef () + }; + +const CommandDef *JabberProtocol::statusList() +{ + return jabber_status_list; +} + +DataDef jabberData[] = + { + { "BrowserBar", DATA_LONG, 7, 0 }, + { "BrowserHistory", DATA_UTF, 1, 0 }, + { "AllLevels", DATA_BOOL, 1, 0 }, + { "BrowseType", DATA_ULONG, 1, DATA(BROWSE_DISCO | BROWSE_BROWSE | BROWSE_AGENTS) }, + { NULL, DATA_UNKNOWN, 0, 0 } + }; + +JabberPlugin *JabberPlugin::plugin = NULL; + +JabberPlugin::JabberPlugin(unsigned base, Buffer *cfg) + : Plugin(base) +{ + plugin = this; + load_data(jabberData, &data, cfg); + JabberPacket = registerType(); + getContacts()->addPacketType(JabberPacket, jabber_descr.text, true); + + EventMenu(MenuSearchResult, EventMenu::eAdd).process(); + EventMenu(MenuJabberGroups, EventMenu::eAdd).process(); + EventMenu(MenuBrowser, EventMenu::eAdd).process(); + + EventToolbar(BarBrowser, EventToolbar::eAdd).process(); + + Command cmd; + cmd->id = CmdJabberMessage; + cmd->text = I18N_NOOP("&Message"); + cmd->icon = "message"; + cmd->menu_id = MenuSearchResult; + cmd->menu_grp = 0x1000; + cmd->flags = COMMAND_DEFAULT; + EventCommandCreate(cmd).process(); + + cmd->id = CmdBrowseInfo; + cmd->text = I18N_NOOP("User &info"); + cmd->icon = "info"; + cmd->menu_grp = 0x1001; + EventCommandCreate(cmd).process(); + + cmd->id = CmdGroups; + cmd->text = I18N_NOOP("&Add to group"); + cmd->icon = QString::null; + cmd->menu_grp = 0x1002; + cmd->popup_id = MenuJabberGroups; + EventCommandCreate(cmd).process(); + + cmd->id = CmdGroups; + cmd->text = "_"; + cmd->menu_id = MenuJabberGroups; + cmd->popup_id = 0; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdBack; + cmd->text = I18N_NOOP("&Back"); + cmd->icon = "1leftarrow"; + cmd->bar_grp = 0x1000; + cmd->bar_id = BarBrowser; + cmd->menu_id = 0; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdForward; + cmd->text = I18N_NOOP("&Next"); + cmd->icon = "1rightarrow"; + cmd->bar_grp = 0x1001; + EventCommandCreate(cmd).process(); + + cmd->id = CmdUrl; + cmd->text = I18N_NOOP("JID"); + cmd->icon = "run"; + cmd->bar_grp = 0x2000; + cmd->flags = BTN_COMBO_CHECK; + EventCommandCreate(cmd).process(); + + cmd->id = CmdNode; + cmd->text = I18N_NOOP("Node"); + cmd->bar_grp = 0x2001; + cmd->flags = BTN_COMBO | BTN_NO_BUTTON; + EventCommandCreate(cmd).process(); + + cmd->id = CmdBrowseSearch; + cmd->text = I18N_NOOP("&Search"); + cmd->icon = "find"; + cmd->bar_grp = 0x3000; + cmd->menu_id = MenuSearchOptions; + cmd->menu_grp = 0x2000; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdRegister; + cmd->text = I18N_NOOP("&Register"); + cmd->icon = "reg"; + cmd->bar_grp = 0x3001; + cmd->menu_grp = 0x2001; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdBrowseInfo; + cmd->text = I18N_NOOP("Info"); + cmd->icon = "info"; + cmd->menu_id = 0; + cmd->menu_grp = 0; + cmd->bar_grp = 0x3010; + EventCommandCreate(cmd).process(); + + cmd->id = CmdBrowseConfigure; + cmd->text = I18N_NOOP("Configure"); + cmd->icon = "configure"; + cmd->bar_grp = 0x3020; + cmd->menu_id = MenuSearchOptions; + cmd->menu_grp = 0x2002; + EventCommandCreate(cmd).process(); + + cmd->id = CmdBrowseMode; + cmd->text = I18N_NOOP("Browser mode"); + cmd->icon = "configure"; + cmd->bar_grp = 0x5000; + cmd->menu_id = 0; + cmd->menu_grp = 0; + cmd->flags = COMMAND_DEFAULT; + cmd->popup_id = MenuBrowser; + EventCommandCreate(cmd).process(); + + cmd->id = CmdOneLevel; + cmd->text = I18N_NOOP("Load one level"); + cmd->icon = QString::null; + cmd->bar_id = 0; + cmd->bar_grp = 0; + cmd->menu_id = MenuBrowser; + cmd->menu_grp = 0x1000; + cmd->popup_id = 0; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = CmdAllLevels; + cmd->text = I18N_NOOP("Load all levels"); + cmd->menu_grp = 0x1001; + EventCommandCreate(cmd).process(); + + cmd->id = CmdModeDisco; + cmd->text = "Discovery"; + cmd->menu_grp = 0x2000; + EventCommandCreate(cmd).process(); + + cmd->id = CmdModeBrowse; + cmd->text = "Browse"; + cmd->menu_grp = 0x2001; + EventCommandCreate(cmd).process(); + + cmd->id = CmdModeAgents; + cmd->text = "Agents"; + cmd->menu_grp = 0x2002; + EventCommandCreate(cmd).process(); + + m_protocol = ProtocolPtr(new JabberProtocol(this)); + getProtocolManager()->addProtocol(m_protocol); + registerMessages(); +} + +JabberPlugin::~JabberPlugin() +{ + unregisterMessages(); + + EventMenu(MenuSearchResult, EventMenu::eRemove).process(); + EventMenu(MenuJabberGroups, EventMenu::eRemove).process(); + EventMenu(MenuBrowser, EventMenu::eRemove).process(); + + EventToolbar(BarBrowser, EventToolbar::eRemove).process(); + + getProtocolManager()->removeProtocol(m_protocol); + getContacts()->removePacketType(JabberPacket); + + free_data(jabberData, &data); +} + +QByteArray JabberPlugin::getConfig() +{ + return save_data(jabberData, &data); +} + +// vim: set expandtab: + diff --git a/plugins/jabber/jabber.h b/plugins/jabber/jabber.h new file mode 100644 index 0000000..01c2b7b --- /dev/null +++ b/plugins/jabber/jabber.h @@ -0,0 +1,107 @@ +/*************************************************************************** + jabber.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _JABBER_H +#define _JABBER_H + +#include "contacts.h" +#include "contacts/client.h" +#include "contacts/imstatus.h" +#include "jabberstatus.h" + +#include + +const unsigned JabberCmdBase = 0x00050000; + +#include "jabber_events.h" + +const unsigned long CmdJabberMessage = JabberCmdBase + 1; +const unsigned long CmdGroups = JabberCmdBase + 2; +const unsigned long CmdBack = JabberCmdBase + 3; +const unsigned long CmdForward = JabberCmdBase + 4; +const unsigned long CmdUrl = JabberCmdBase + 5; +const unsigned long CmdBrowseInfo = JabberCmdBase + 6; +const unsigned long CmdBrowseSearch = JabberCmdBase + 7; +const unsigned long CmdRegister = JabberCmdBase + 8; +const unsigned long CmdNode = JabberCmdBase + 9; +const unsigned long CmdBrowseMode = JabberCmdBase + 10; +const unsigned long CmdBrowseConfigure = JabberCmdBase + 11; +const unsigned long CmdOneLevel = JabberCmdBase + 12; +const unsigned long CmdAllLevels = JabberCmdBase + 13; +const unsigned long CmdModeDisco = JabberCmdBase + 14; +const unsigned long CmdModeBrowse = JabberCmdBase + 15; +const unsigned long CmdModeAgents = JabberCmdBase + 16; + +const unsigned long MenuSearchResult = JabberCmdBase + 1; +const unsigned long MenuJabberGroups = JabberCmdBase + 2; +const unsigned long MenuBrowser = JabberCmdBase + 3; + +const unsigned long BarBrowser = JabberCmdBase + 1; + +const unsigned BROWSE_DISCO = 1; +const unsigned BROWSE_BROWSE = 2; +const unsigned BROWSE_AGENTS = 4; + +class JabberProtocol : public SIM::Protocol +{ +public: + JabberProtocol(SIM::Plugin *plugin); + ~JabberProtocol(); + SIM::ClientPtr createClient(Buffer *cfg); + const SIM::CommandDef *description(); + const SIM::CommandDef *statusList(); + virtual const SIM::DataDef *userDataDef(); + + virtual QStringList statuses(); + virtual SIM::IMStatusPtr status(const QString& id); + +private: + void initStatuses(); + void addStatus(JabberStatusPtr status); + QList m_statuses; +}; + +struct JabberData +{ + SIM::Data browser_bar[7]; + SIM::Data BrowserHistory; + SIM::Data AllLevels; + SIM::Data BrowseType; +}; + +class JabberPlugin : public SIM::Plugin +{ +public: + JabberPlugin(unsigned base, Buffer *cfg); + virtual ~JabberPlugin(); + unsigned JabberPacket; + void registerMessages(); + void unregisterMessages(); + JabberData data; + PROP_UTF8(BrowserHistory); + PROP_BOOL(AllLevels); + PROP_ULONG(BrowseType); + static JabberPlugin *plugin; +protected: + virtual QByteArray getConfig(); + SIM::ProtocolPtr m_protocol; +}; + +#endif + +// vim: set expandtab: + diff --git a/plugins/jabber/jabber.rc b/plugins/jabber/jabber.rc new file mode 100644 index 0000000..bcc4f3d --- /dev/null +++ b/plugins/jabber/jabber.rc @@ -0,0 +1,97 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,9,6,0 + PRODUCTVERSION 0,9,6,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Vladimir Shutoff\0" + VALUE "FileDescription", "Jabber plugin\0" + VALUE "FileVersion", "0, 9, 6, 0\0" + VALUE "InternalName", "jabber\0" + VALUE "LegalCopyright", "Copyright © 2002-2003\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "jabber.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "SIM\0" + VALUE "ProductVersion", "0, 9, 6, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/jabber/jabber.vcproj b/plugins/jabber/jabber.vcproj new file mode 100644 index 0000000..c187f4d --- /dev/null +++ b/plugins/jabber/jabber.vcproj @@ -0,0 +1,1635 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/jabber/jabber_auth.cpp b/plugins/jabber/jabber_auth.cpp new file mode 100644 index 0000000..c27afe3 --- /dev/null +++ b/plugins/jabber/jabber_auth.cpp @@ -0,0 +1,112 @@ +/*************************************************************************** + jabber_auth.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "simapi.h" + +#include "jabberclient.h" + +#include +#include + +using namespace SIM; + +class AuthRequest : public JabberClient::ServerRequest +{ +public: + AuthRequest(JabberClient *client); +protected: + bool m_bFail; + virtual void element_start(const QString& el, const QXmlAttributes& attrs); + virtual void element_end(const QString& el); +}; + +AuthRequest::AuthRequest(JabberClient *client) + : JabberClient::ServerRequest(client, _SET, NULL, client->VHost()) +{ + m_bFail = true; +} + +void AuthRequest::element_end(const QString& el) +{ + if (el != "iq") + return; + if (m_bFail){ + QTimer::singleShot(0, m_client, SLOT(auth_failed())); + }else{ + QTimer::singleShot(0, m_client, SLOT(auth_ok())); + } +} + +void AuthRequest::element_start(const QString& el, const QXmlAttributes& attrs) +{ + if (el == "iq"){ + QString value = attrs.value("type").toLower(); + if (value == "result") + m_bFail = false; + } +} + +void JabberClient::auth_plain() +{ + AuthRequest *req = new AuthRequest(this); + req->start_element("query"); + req->add_attribute("xmlns", "jabber:iq:auth"); + QString username = data.owner.ID.str(); + username = getToken(username, '@'); + req->text_tag("username", username); + req->text_tag("password", getPassword()); + req->text_tag("resource", data.owner.Resource.str()); + req->send(); + m_requests.push_back(req); +} + +void JabberClient::auth_register() +{ + AuthRequest *req = new AuthRequest(this); + req->start_element("query"); + req->add_attribute("xmlns", "jabber:iq:register"); + QString username = data.owner.ID.str(); + username = getToken(username, '@'); + req->text_tag("username", username); + req->text_tag("password", getPassword()); + req->send(); + m_requests.push_back(req); +} + +void JabberClient::auth_digest() +{ + AuthRequest *req = new AuthRequest(this); + req->start_element("query"); + req->add_attribute("xmlns", "jabber:iq:auth"); + QString username = data.owner.ID.str(); + username = getToken(username, '@'); + req->text_tag("username", username); + + QString digest = m_id; + digest += getPassword(); + QByteArray md = QCryptographicHash::hash(digest.toUtf8(), QCryptographicHash::Sha1); + digest = QString::null; + for (int i = 0; i < md.size(); i++){ + char b[3]; + sprintf(b, "%02x", md[i] & 0xFF); + digest += b; + } + req->text_tag("digest", digest); + req->text_tag("resource", data.owner.Resource.str()); + req->send(); + m_requests.push_back(req); +} diff --git a/plugins/jabber/jabber_events.h b/plugins/jabber/jabber_events.h new file mode 100644 index 0000000..46adcd5 --- /dev/null +++ b/plugins/jabber/jabber_events.h @@ -0,0 +1,116 @@ +#ifndef _JABBER_EVENTS_H +#define _JABBER_EVENTS_H + +#include + +#include "event.h" + +struct ClientLastInfo; +struct ClientTimeInfo; +struct ClientVersionInfo; +struct DiscoItem; +struct JabberAgentInfo; +struct JabberSearchData; +struct agentRegisterInfo; +struct JabberUserData; + +class EventAgentInfo : public SIM::Event +{ +public: + EventAgentInfo(JabberAgentInfo *info) + : Event(SIM::eEventAgentInfo), m_info(info) {} + + JabberAgentInfo *agentInfo() const { return m_info; } +protected: + JabberAgentInfo *m_info; +}; + +class EventAgentRegister : public SIM::Event +{ +public: + EventAgentRegister(agentRegisterInfo *info) + : Event(SIM::eEventAgentRegister), m_info(info) {} + + agentRegisterInfo *registerInfo() const { return m_info; } +protected: + agentRegisterInfo *m_info; +}; + +class EventSearch : public SIM::Event +{ +public: + EventSearch(JabberSearchData *data) + : Event(SIM::eEventJabberSearch), m_data(data) {} + + JabberSearchData *searchData() const { return m_data; } +protected: + JabberSearchData *m_data; +}; + +class EventSearchDone : public SIM::Event +{ +public: + EventSearchDone(const QString &userID) + : Event(SIM::eEventJabberSearchDone), m_id(userID) {} + + const QString &userID() const { return m_id; } +protected: + QString m_id; +}; + +class EventDiscoItem : public SIM::Event +{ +public: + EventDiscoItem(DiscoItem *item) + : Event(SIM::eEventDiscoItem), m_item(item) {} + + DiscoItem *item() const { return m_item; } +protected: + DiscoItem *m_item; +}; + +class EventVCard : public SIM::Event +{ +public: + EventVCard(JabberUserData *data) + : Event(SIM::eEventVCard), m_data(data) {} + + JabberUserData *data() const { return m_data; } +protected: + JabberUserData *m_data; +}; + +class EventClientVersion : public SIM::Event +{ +public: + EventClientVersion(ClientVersionInfo *info) + : Event(SIM::eEventClientVersion), m_info(info) {} + + ClientVersionInfo *info() const { return m_info; } +protected: + ClientVersionInfo *m_info; +}; + +class EventClientLastInfo : public SIM::Event +{ +public: + EventClientLastInfo(ClientLastInfo *info) + : Event(SIM::eEventClientLastInfo), m_info(info) {} + + ClientLastInfo *info() const { return m_info; } +protected: + ClientLastInfo *m_info; +}; + +class EventClientTimeInfo : public SIM::Event +{ +public: + EventClientTimeInfo(ClientTimeInfo *info) + : Event(SIM::eEventClientTimeInfo), m_info(info) {} + + ClientTimeInfo *info() const { return m_info; } +protected: + ClientTimeInfo *m_info; +}; + +#endif // _JABBER_EVENTS_H diff --git a/plugins/jabber/jabber_pch.h b/plugins/jabber/jabber_pch.h new file mode 100644 index 0000000..19a4cc0 --- /dev/null +++ b/plugins/jabber/jabber_pch.h @@ -0,0 +1,55 @@ +#ifndef JABBER_PCH_H +#define JABBER_PCH_H +#pragma once + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef NO_QT_MOC_HEADER +#include +//#include +//#include +#endif + +#include "discoinfo.h" +#include "infoproxy.h" +#include "jabber.h" +#include "jabber_ssl.h" +#include "jabberaboutinfo.h" +#include "jabberadd.h" +#include "jabberbrowser.h" +#include "jabberclient.h" +#include "jabberconfig.h" +#include "jabberhomeinfo.h" +#include "jabberinfo.h" +#include "jabbermessage.h" +#include "jabberpicture.h" +#include "jabbersearch.h" +#include "jabberworkinfo.h" +#include "jidadvsearch.h" +#include "jidsearch.h" + +#endif // JABBER_PCH_H diff --git a/plugins/jabber/jabber_rosters.cpp b/plugins/jabber/jabber_rosters.cpp new file mode 100644 index 0000000..1250cee --- /dev/null +++ b/plugins/jabber/jabber_rosters.cpp @@ -0,0 +1,2893 @@ +/*************************************************************************** + jabber_rosters.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "simapi.h" + +#include +#include +#include +#include + +#include "html.h" +#include "log.h" +#include "unquot.h" +#include "misc.h" +#include "core_events.h" +#include "contacts/clientdataiterator.h" +#include "contacts/contact.h" +#include "contacts/group.h" + +#include "jabberclient.h" +#include "jabber.h" +#include "jabbermessage.h" + +using namespace std; +using namespace SIM; + +class RostersRequest : public JabberClient::ServerRequest +{ +public: + RostersRequest(JabberClient *client); + ~RostersRequest(); +protected: + virtual void element_start(const QString& el, const QXmlAttributes& attrs); + virtual void element_end(const QString& el); + virtual void char_data(const QString& str); + QString m_jid; + QString m_name; + QString m_grp; + QString m_subscription; + unsigned m_subscribe; + unsigned m_bSubscription; + QString *m_data; +}; + +RostersRequest::RostersRequest(JabberClient *client) + : JabberClient::ServerRequest(client, _GET, NULL, NULL) +{ + m_data = NULL; + ContactList::ContactIterator itc; + Contact *contact; + while ((contact = ++itc) != NULL){ + ClientDataIterator it(contact->clientData, client); + JabberUserData *data; + while ((data = m_client->toJabberUserData(++it)) != NULL) + data->bChecked.asBool() = false; + } + client->m_bJoin = false; +} + +RostersRequest::~RostersRequest() +{ + ContactList::ContactIterator itc; + Contact *contact; + list contactRemoved; + while ((contact = ++itc) != NULL){ + ClientDataIterator it(contact->clientData, m_client); + JabberUserData *data; + list dataRemoved; + while ((data = m_client->toJabberUserData(++it)) != NULL){ + if (!data->bChecked.toBool()){ + QString jid = data->ID.str(); + JabberListRequest *lr = m_client->findRequest(jid, false); + if (lr && lr->bDelete) + m_client->findRequest(jid, true); + dataRemoved.push_back(data); + } + } + if (dataRemoved.empty()) + continue; + for (list::iterator itr = dataRemoved.begin(); itr != dataRemoved.end(); ++itr) + contact->clientData.freeData(*itr); + if (contact->clientData.size() == 0) + contactRemoved.push_back(contact); + } + for (list::iterator itr = contactRemoved.begin(); itr != contactRemoved.end(); ++itr) + delete *itr; + m_client->processList(); + if (m_client->m_bJoin){ + EventJoinAlert(m_client).process(); + } +} + +void RostersRequest::element_start(const QString& el, const QXmlAttributes& attrs) +{ + if (el == "item"){ + m_subscribe = SUBSCRIBE_NONE; + m_grp = QString::null; + m_jid = attrs.value("jid"); + if (m_jid.length() == 0) + return; + m_name = attrs.value("name"); + m_subscription = QString::null; + m_bSubscription = false; + QString subscribe = attrs.value("subscription"); + if (subscribe == "none"){ + m_subscribe = SUBSCRIBE_NONE; + }else if (subscribe == "from"){ + m_subscribe = SUBSCRIBE_FROM; + }else if (subscribe == "to"){ + m_subscribe = SUBSCRIBE_TO; + }else if (subscribe == "both"){ + m_subscribe = SUBSCRIBE_BOTH; + }else{ + log(L_WARN, "Unknown attr subscribe=%s", qPrintable(subscribe)); + } + return; + } + if (el == "group"){ + m_grp = QString::null; + m_data = &m_grp; + return; + } + if (el == "subscription"){ + m_bSubscription = true; + m_subscription = QString::null; + m_data = &m_subscription; + return; + } +} + +void RostersRequest::element_end(const QString& el) +{ + if (el == "group"){ + m_data = NULL; + return; + } + if (el == "item"){ + if ( m_jid.indexOf('/') >= 0 ) + { + // If roster contains two contacts + // user@jabber.ru and user@jabber.ru/some_resource + // than it will be impossible, to move user@jabber.ru from one group to another because + // after reloading sim it will be merged with user@jabber.ru/some_resource + // because sim-im see no difference between them :-/ + // So the simplest way to fix this bus is to ignore roster records with explicit resource + // This is a nasty hack, but I see no way to fix it without rewriting all jabber stuff :-( + // N. Shaplov + log(L_DEBUG,"Ignoring contact with explicit resource: %s", qPrintable(m_jid)); + return; + } + bool bChanged = false; + JabberListRequest *lr = m_client->findRequest(m_jid, false); + Contact *contact; + QString resource; + JabberUserData *data = m_client->findContact(m_jid, m_name, false, contact, resource); + if (data == NULL){ + if (lr && lr->bDelete){ + m_client->findRequest(m_jid, true); + }else{ + bChanged = true; + data = m_client->findContact(m_jid, m_name, true, contact, resource); + if (m_bSubscription){ + contact->setFlags(CONTACT_TEMP); + EventContact eContact(contact, EventContact::eChanged); + eContact.process(); + m_client->auth_request(m_jid, MessageAuthRequest, m_subscription, true); + data = m_client->findContact(m_jid, m_name, false, contact, resource); + } + } + } + if (data == NULL) + return; + if (data->Subscribe.toULong() != m_subscribe){ + bChanged = true; + data->Subscribe.asULong() = m_subscribe; + } + data->Group.str() = m_grp; + data->bChecked.asBool() = true; + if (lr == NULL){ + unsigned grp = 0; + if (!m_grp.isEmpty()){ + Group *group = NULL; + ContactList::GroupIterator it; + while ((group = ++it) != NULL){ + if (m_grp == group->getName()){ + grp = group->id(); + break; + } + } + if (group == NULL){ + group = getContacts()->group(0, true); + group->setName(m_grp); + grp = group->id(); + EventGroup e(group, EventGroup::eChanged); + e.process(); + } + } + if (contact->getGroup() != (int)grp){ + if (grp == 0){ + void *d = NULL; + ClientDataIterator it_d(contact->clientData); + while ((d = ++it_d) != NULL){ + if (d != data) + break; + } + if (d){ + grp = contact->getGroup(); + Group *group = getContacts()->group(grp); + if (group) + m_client->listRequest(data, contact->getName(), group->getName(), false); + } + } + contact->setGroup(grp); + bChanged = true; + } + } + if (bChanged){ + EventContact e(contact, EventContact::eChanged); + e.process(); + } + } +} + +void RostersRequest::char_data(const QString& str) +{ + if (m_data != NULL) + *m_data += str; +} + +void JabberClient::rosters_request() +{ + RostersRequest *req = new RostersRequest(this); + req->start_element("query"); + req->add_attribute("xmlns", "jabber:iq:roster"); + req->send(); + m_requests.push_back(req); +} + +class InfoRequest : public JabberClient::ServerRequest +{ +public: + InfoRequest(JabberClient *client, JabberUserData *data, bool bVCard); + ~InfoRequest(); +protected: + virtual void element_start(const QString& el, const QXmlAttributes& attrs); + virtual void element_end(const QString& el); + virtual void char_data(const QString& str); + QString m_jid; + QString m_node; + QString m_host; + bool m_bStarted; + QString m_firstName; + QString m_nick; + QString m_desc; + QString m_email; + QString m_bday; + QString m_url; + QString m_orgName; + QString m_orgUnit; + QString m_title; + QString m_role; + QString m_phone; + QString m_street; + QString m_ext; + QString m_city; + QString m_region; + QString m_pcode; + QString m_country; + QString m_photo; // a bas64 encoded string + QString m_logo; // a bas64 encoded string + bool m_bPhoto; + bool m_bLogo; + bool m_bVCard; + + QString *m_data; +}; + +extern DataDef jabberUserData[]; + +InfoRequest::InfoRequest(JabberClient *client, JabberUserData *data, bool bVCard) + : JabberClient::ServerRequest(client, _GET, NULL, client->buildId(data)) +{ + m_jid = data->ID.str(); + m_node = data->Node.str(); + m_bStarted = false; + m_data = NULL; + m_bPhoto = false; + m_bLogo = false; + m_bVCard = bVCard; +} + +InfoRequest::~InfoRequest() +{ + if (m_bStarted){ + Contact *contact = NULL; + JabberUserData *data; + JabberUserData u_data; + if (m_bVCard){ + load_data(jabberUserData, &u_data, NULL); + data = &u_data; + data->ID.str() = m_jid; + data->Node.str() = m_node; + }else{ + if (m_jid == m_client->data.owner.ID.str()){ + data = &m_client->data.owner; + }else{ + QString jid = m_jid; + if (jid.indexOf('@') == -1){ + jid += '@'; + jid += m_host; + } + QString resource; + data = m_client->findContact(jid, QString::null, false, contact, resource); + if (data == NULL) + return; + } + } + bool bChanged = false; + bChanged |= data->FirstName.setStr(m_firstName); + bChanged |= data->Nick.setStr(m_nick); + bChanged |= data->Desc.setStr(m_desc); + bChanged |= data->Bday.setStr(m_bday); + bChanged |= data->Url.setStr(m_url); + bChanged |= data->OrgName.setStr(m_orgName); + bChanged |= data->OrgUnit.setStr(m_orgUnit); + bChanged |= data->Title.setStr(m_title); + bChanged |= data->Role.setStr(m_role); + bChanged |= data->Street.setStr(m_street); + bChanged |= data->ExtAddr.setStr(m_ext); + bChanged |= data->City.setStr(m_city); + bChanged |= data->Region.setStr(m_region); + bChanged |= data->PCode.setStr(m_pcode); + bChanged |= data->Country.setStr(m_country); + bChanged |= data->EMail.setStr(m_email); + bChanged |= data->Phone.setStr(m_phone); + + if (m_bVCard){ + EventVCard(data).process(); + free_data(jabberUserData, &u_data); + return; + } + QImage photo; + if (m_photo.length()){ + QString fName = m_client->photoFile(data); + QFile f(fName); + if (f.open(QIODevice::WriteOnly | QIODevice::Truncate)){ + QByteArray cstr = m_photo.toAscii(); // ok, base64 encoded + f.write(QByteArray::fromBase64(cstr)); + f.close(); + photo.load(fName); + }else{ + log(L_ERROR, "Can't create %s", qPrintable(fName)); + } + } + if (photo.width() && photo.height()){ + if ((photo.width() != (int)(data->PhotoWidth.toLong())) || + (photo.height() != (int)(data->PhotoHeight.toLong()))) + bChanged = true; + data->PhotoWidth.asLong() = photo.width(); + data->PhotoHeight.asLong() = photo.height(); + if (m_jid == m_client->data.owner.ID.str()) + m_client->setPhoto(m_client->photoFile(data)); + }else{ + if (data->PhotoWidth.toLong() || data->PhotoHeight.toLong()) + bChanged = true; + data->PhotoWidth.asLong() = 0; + data->PhotoHeight.asLong() = 0; + } + + QImage logo; + if (m_logo.length()){ + QString fName = m_client->logoFile(data); + QFile f(fName); + if (f.open(QIODevice::WriteOnly | QIODevice::Truncate)){ + QByteArray cstr = m_logo.toAscii(); // ok, base64 encoded + f.write(QByteArray::fromBase64(cstr)); + f.close(); + logo.load(fName); + }else{ + log(L_ERROR, "Can't create %s", qPrintable(fName)); + } + } + if (logo.width() && logo.height()){ + if ((logo.width() != (int)(data->LogoWidth.toLong())) || + (logo.height() != (int)(data->LogoHeight.toLong()))) + bChanged = true; + data->LogoWidth.asLong() = logo.width(); + data->LogoHeight.asLong() = logo.height(); + if (m_jid == m_client->data.owner.ID.str()) + m_client->setLogo(m_client->logoFile(data)); + }else{ + if (data->LogoWidth.toLong() || data->LogoHeight.toLong()) + bChanged = true; + data->LogoWidth.asLong() = 0; + data->LogoHeight.asLong() = 0; + } + + if (bChanged){ + if (contact){ + m_client->setupContact(contact, data); + EventContact(contact, EventContact::eChanged).process(); + }else{ + EventClientChanged(m_client).process(); + } + } + } +} + +void InfoRequest::element_start(const QString& el, const QXmlAttributes&) +{ + m_data = NULL; + if (el == "vcard"){ + m_bStarted = true; + return; + } + if (el == "nickname"){ + m_data = &m_nick; + return; + } + if (el == "fn"){ + m_data = &m_firstName; + return; + } + if (el == "desc"){ + m_data = &m_desc; + return; + } + if (el == "email"){ + m_data = &m_email; + return; + } + if (el == "bday"){ + m_data = &m_bday; + return; + } + if (el == "url"){ + m_data = &m_url; + return; + } + if (el == "orgname"){ + m_data = &m_orgName; + return; + } + if (el == "orgunit"){ + m_data = &m_orgUnit; + return; + } + if (el == "title"){ + m_data = &m_title; + return; + } + if (el == "role"){ + m_data = &m_role; + return; + } + if (el == "voice"){ + m_data = &m_phone; + return; + } + if (el == "street"){ + m_data = &m_street; + return; + } + if (el == "extadd"){ + m_data = &m_ext; + return; + } + if (el == "locality"){ + m_data = &m_city; + return; + } + if (el == "region"){ + m_data = &m_region; + return; + } + if (el == "pcode"){ + m_data = &m_pcode; + return; + } + if (el == "country"){ + m_data = &m_country; + return; + } + if (el == "photo"){ + m_bPhoto = true; + return; + } + if (el == "logo"){ + m_bLogo = true; + return; + } + if (el == "binval"){ + if (m_bPhoto) + m_data = &m_photo; + if (m_bLogo) + m_data = &m_logo; + } +} + +void InfoRequest::element_end(const QString& el) +{ + m_data = NULL; + if (el == "photo"){ + m_bPhoto = false; + return; + } + if (el == "logo"){ + m_bLogo = false; + return; + } + if(el == "vcard") + { + EventClientChanged(m_client).process(); + } +} + +void InfoRequest::char_data(const QString& str) +{ + if (m_data) + *m_data += str; +} + +void JabberClient::info_request(JabberUserData *user_data, bool bVCard) +{ + if (getState() != Connected) + return; + if (user_data == NULL) + user_data = &data.owner; + InfoRequest *req = new InfoRequest(this, user_data, bVCard); + req->start_element("vCard"); + req->add_attribute("prodid", "-//HandGen//NONSGML vGen v1.0//EN"); + req->add_attribute("xmlns", "vcard-temp"); + req->add_attribute("version", "2.0"); + if (!user_data->Node.str().isEmpty()) + req->add_attribute("node", user_data->Node.str()); + req->send(); + m_requests.push_back(req); +} + +class SetInfoRequest : public JabberClient::ServerRequest +{ +public: + SetInfoRequest(JabberClient *client, JabberUserData *data); +protected: + virtual void element_start(const QString& el, const QXmlAttributes& attrs); +}; + +SetInfoRequest::SetInfoRequest(JabberClient *client, JabberUserData *data) + : JabberClient::ServerRequest(client, _SET, NULL, client->buildId(data)) +{ +} + +void SetInfoRequest::element_start(const QString& el, const QXmlAttributes& attrs) +{ + if (el == "iq"){ + QString type = attrs.value("type"); + if (type == "result") + m_client->setInfoUpdated(false); + } +} + +void JabberClient::setClientInfo(void *_data) +{ + JabberUserData *data = toJabberUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + if (data != &this->data.owner){ + this->data.owner.FirstName.str() = data->FirstName.str(); + this->data.owner.Nick.str() = data->Nick.str(); + this->data.owner.Desc.str() = data->Desc.str(); + this->data.owner.Bday.str() = data->Bday.str(); + this->data.owner.Url.str() = data->Url.str(); + this->data.owner.OrgName.str() = data->OrgName.str(); + this->data.owner.OrgUnit.str() = data->OrgUnit.str(); + this->data.owner.Title.str() = data->Title.str(); + this->data.owner.Role.str() = data->Role.str(); + this->data.owner.Street.str() = data->Street.str(); + this->data.owner.ExtAddr.str() = data->ExtAddr.str(); + this->data.owner.City.str() = data->City.str(); + this->data.owner.Region.str() = data->Region.str(); + this->data.owner.PCode.str() = data->PCode.str(); + this->data.owner.Country.str() = data->Country.str(); + } + setInfoUpdated(true); + if (getState() != Connected) + return; + SetInfoRequest *req = new SetInfoRequest(this, &this->data.owner); + req->start_element("vCard"); + req->add_attribute("prodid", "-//HandGen//NONSGML vGen v1.0//EN"); + req->add_attribute("xmlns", "vcard-temp"); + req->add_attribute("version", "2.0"); + req->add_attribute("node", data->Node.str()); + req->text_tag("FN", data->FirstName.str()); + req->text_tag("NICKNAME", data->Nick.str()); + req->text_tag("DESC", data->Desc.str()); + QString mails = getContacts()->owner()->getEMails(); + while (mails.length()){ + QString mailItem = getToken(mails, ';', false); + QString mail = getToken(mailItem, '/'); + if (mailItem.length()) + continue; + req->text_tag("EMAIL", mail); + break; + } + req->text_tag("BDAY", data->Bday.str()); + req->text_tag("URL", data->Url.str()); + req->start_element("ORG"); + req->text_tag("ORGNAME", data->OrgName.str()); + req->text_tag("ORGUNIT", data->OrgUnit.str()); + req->end_element(); + req->text_tag("TITLE", data->Title.str()); + req->text_tag("ROLE", data->Role.str()); + QString phone; + QString phones = getContacts()->owner()->getPhones(); + while (phones.length()){ + QString phoneItem = getToken(phones, ';', false); + QString phoneValue = getToken(phoneItem, '/', false); + if (phoneItem.length()) + continue; + QString number = getToken(phoneValue, ','); + QString type = getToken(phoneValue, ','); + if (type == "Hone Phone"){ + phone = number; + break; + } + } + if (phone.length()){ + req->start_element("TEL"); + req->start_element("HOME"); + req->end_element(); + req->text_tag("VOICE", phone); + req->end_element(); + } + req->start_element("ADDR"); + req->start_element("HOME"); + req->end_element(); + req->text_tag("STREET", data->Street.str()); + req->text_tag("EXTADD", data->ExtAddr.str()); + req->text_tag("LOCALITY", data->City.str()); + req->text_tag("REGION", data->Region.str()); + req->text_tag("PCODE", data->PCode.str()); + req->text_tag("COUNTRY", data->Country.str()); + req->end_element(); + if (!getPhoto().isEmpty()){ + QFile img(getPhoto()); + if (img.open(QIODevice::ReadOnly)){ + Buffer b; + b.init(img.size()); + img.read(b.data(), b.size()); + QByteArray packed = b.toBase64(); + req->start_element("PHOTO"); + req->text_tag("BINVAL", packed); + req->end_element(); + } + } + if (!getLogo().isEmpty()){ + QFile img(getLogo()); + if (img.open(QIODevice::ReadOnly)){ + Buffer b; + b.init(img.size()); + img.read(b.data(), b.size()); + QByteArray packed = b.toBase64(); + req->start_element("LOGO"); + req->text_tag("BINVAL", packed.data()); + req->end_element(); + } + } + req->send(); + m_requests.push_back(req); +} + +class AddRequest : public JabberClient::ServerRequest +{ +public: + AddRequest(JabberClient *client, const QString &jid, unsigned grp); +protected: + virtual void element_start(const QString& el, const QXmlAttributes& attrs); + QString m_jid; + unsigned m_grp; +}; + +AddRequest::AddRequest(JabberClient *client, const QString &jid, unsigned grp) + : JabberClient::ServerRequest(client, _SET, NULL, NULL) +{ + m_jid = jid; + m_grp = grp; +} + +void AddRequest::element_start(const QString& el, const QXmlAttributes& attrs) +{ + if (el == "iq"){ + QString type = attrs.value("type"); + if (type == "result"){ + Contact *contact; + QString resource; + JabberUserData *data = m_client->findContact(m_jid, QString::null, true, contact, resource); + if (data && (contact->getGroup() != (int)m_grp)){ + contact->setGroup(m_grp); + EventContact e(contact, EventContact::eChanged); + e.process(); + } + } + } +} + +bool JabberClient::add_contact(const char *_jid, unsigned grp) +{ + Contact *contact; + QString resource; + QString jid = QString::fromUtf8(_jid); + if (findContact(jid, QString::null, false, contact, resource)){ + EventContact e(contact, EventContact::eChanged); + e.process(); + return false; + } + AddRequest *req = new AddRequest(this, jid, grp); + req->start_element("query"); + req->add_attribute("xmlns", "jabber:iq:roster"); + req->start_element("item"); + req->add_attribute("jid", jid); + Group *g = NULL; + if (grp) + g = getContacts()->group(grp); + if (g) + req->text_tag("group", g->getName()); + req->send(); + m_requests.push_back(req); + return true; +} + +JabberClient::PresenceRequest::PresenceRequest(JabberClient *client) + : ServerRequest(client, NULL, NULL, NULL) +{ +} + +//static unsigned get_number(QString &s, unsigned digits) +//{ +// if ((unsigned)s.length() < digits){ +// s = QString::null; +// return 0; +// } +// QString p = s.left(digits); +// s = s.mid(digits); +// return p.toUInt(); +//} + +static QDateTime fromDelay(const QString &t) +{ + QDateTime dt(QDateTime::currentDateTime()); + QRegExp reg("^(\\d{4})-?(\\d{2})-?(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})(.(\\d{3}))?((Z)|([-+]\\d{2}:\\d{2}))?$"); + do { + if( reg.indexIn(t) == -1 ) + break; + int numcap = reg.numCaptures(); + if( numcap < 6 ) + break; + QDate date; + date.setYMD( + reg.cap(1).toUInt(), + reg.cap(2).toUInt(), + reg.cap(3).toUInt() + ); + QTime time; + time.setHMS( + reg.cap(4).toUInt(), + reg.cap(5).toUInt(), + reg.cap(6).toUInt() + ); + dt.setDate( date ); + dt.setTime( time ); + if( numcap < 9 ) + break; + QString sTZD = reg.cap(9); + if( sTZD == "Z" ) { + dt.setTimeSpec( Qt::UTC ); + } + else { + dt.setTimeSpec( Qt::OffsetFromUTC ); + int secs = QTime::fromString(sTZD.right(5),"hh:mm").secsTo(QTime(0,0,0,0)); + if( sTZD[0] == '+' ) + secs = -secs; + dt.setUtcOffset( secs ); + dt.toLocalTime(); + } + } while( false ); + + return dt; +} + +JabberClient::PresenceRequest::~PresenceRequest() +{ + unsigned status = STATUS_UNKNOWN; + bool bInvisible = false; + // RFC 3921 "XMPP IM": 2.2.1. Types of Presence + if (m_type == "unavailable"){ + status = STATUS_OFFLINE; + }else if (m_type == "subscribe"){ + m_client->auth_request(m_from, MessageAuthRequest, m_status, true); + }else if (m_type == "subscribed"){ + m_client->auth_request(m_from, MessageAuthGranted, m_status, true); + }else if (m_type == "unsubscribe"){ + m_client->auth_request(m_from, MessageRemoved, m_status, true); + }else if (m_type == "unsubscribed"){ + m_client->auth_request(m_from, MessageAuthRefused, m_status, true); + }else if (m_type == "probe"){ + // server want to to know if we're living + m_client->ping(); + }else if (m_type == "error"){ + log(L_DEBUG, "An error has occurred regarding processing or delivery of a previously-sent presence stanza"); + }else if (m_type.length() == 0){ + // RFC 3921 "XMPP IM": 2.2.2.1. Show + status = STATUS_ONLINE; + if (m_show == "away"){ + status = STATUS_AWAY; + }else if (m_show == "chat"){ + status = STATUS_FFC; + }else if (m_show == "xa"){ + status = STATUS_NA; + }else if (m_show == "dnd"){ + status = STATUS_DND; + }else if (m_show == "occupied"){ + status = STATUS_OCCUPIED; + }else if (m_show == "online"){ + status = STATUS_ONLINE; + }else if (m_show.isEmpty()){ + // RFC 3921 "XMPP IM": 2.2.2.2. Status + status = STATUS_ONLINE; + if (m_status == "Online"){ + status = STATUS_ONLINE; + }else if (m_status == "Disconnected"){ + status = STATUS_OFFLINE; + }else if (m_status == "Connected"){ + status = STATUS_ONLINE; + }else if (m_status == "Invisible"){ + status = STATUS_ONLINE; + bInvisible = true; + }else if (!m_status.isEmpty()){ + status = STATUS_ONLINE; + } + }else{ + log(L_DEBUG, "Unsupported available status %s", qPrintable(m_show)); + } + }else{ + log(L_DEBUG, "Unsupported presence type %s", qPrintable(m_type)); + } + QDateTime time1(QDateTime::currentDateTime()); + QDateTime time2; + if (!m_stamp1.isEmpty()) + time1 = fromDelay(m_stamp1); + if (!m_stamp2.isEmpty()){ + time2 = fromDelay(m_stamp2); + if (time2 > time1){ + QDateTime t = time1; + time1 = time2; + time2 = t; + } + } + + if (status != STATUS_UNKNOWN){ + Contact *contact; + QString resource; + JabberUserData *data = m_client->findContact(m_from, QString::null, false, contact, resource); + if (data){ + unsigned i; + for (i = 1; i <= data->nResources.toULong(); i++){ + if (resource == get_str(data->Resources, i)) + break; + } + bool bChanged = false; + if (status == STATUS_OFFLINE){ + if (i <= data->nResources.toULong()){ + bChanged = true; + vector resources; + vector resourceReply; + vector resourceStatus; + vector resourceStatusTime; + vector resourceOnlineTime; + vector resourceClientName; + vector resourceClientVersion; + vector resourceClientOS; + for (unsigned n = 1; n <= data->nResources.toULong(); n++){ + if (i == n) + continue; + resources.push_back(get_str(data->Resources, n)); + resourceReply.push_back(get_str(data->ResourceReply, n)); + resourceStatus.push_back(get_str(data->ResourceStatus, n)); + resourceStatusTime.push_back(get_str(data->ResourceStatusTime, n)); + resourceOnlineTime.push_back(get_str(data->ResourceOnlineTime, n)); + resourceClientName.push_back(get_str(data->ResourceClientName, n)); + resourceClientVersion.push_back(get_str(data->ResourceClientVersion, n)); + resourceClientOS.push_back(get_str(data->ResourceClientOS, n)); + } + data->Resources.clear(); + data->ResourceReply.clear(); + data->ResourceStatus.clear(); + data->ResourceStatusTime.clear(); + data->ResourceOnlineTime.clear(); + data->ResourceClientName.clear(); + data->ResourceClientVersion.clear(); + data->ResourceClientOS.clear(); + for (i = 0; i < resources.size(); i++){ + set_str(&data->Resources, i + 1, resources[i]); + set_str(&data->ResourceReply, i + 1, resourceReply[i]); + set_str(&data->ResourceStatus, i + 1, resourceStatus[i]); + set_str(&data->ResourceStatusTime, i + 1, resourceStatusTime[i]); + set_str(&data->ResourceOnlineTime, i + 1, resourceOnlineTime[i]); + set_str(&data->ResourceClientName, i + 1, resourceClientName[i]); + set_str(&data->ResourceClientVersion, i + 1, resourceClientVersion[i]); + set_str(&data->ResourceClientOS, i + 1, resourceClientOS[i]); + } + data->nResources.asULong() = resources.size(); + } + if (data->nResources.toULong() == 0) + data->AutoReply.str() = m_status; + }else{ + if (i > data->nResources.toULong()){ + bChanged = true; + data->nResources.asULong() = i; + set_str(&data->Resources, i, resource); + set_str(&data->ResourceOnlineTime, i, QString::number(!time2.isNull() ? time2.toTime_t() : time1.toTime_t())); + if (m_client->getUseVersion()) + m_client->versionInfo(m_from); + } + if (QString::number(status) != get_str(data->ResourceStatus, i)){ + bChanged = true; + set_str(&data->ResourceStatus, i, QString::number(status)); + set_str(&data->ResourceStatusTime, i, QString::number(time1.toTime_t())); + } + if (m_status != get_str(data->ResourceReply, i)){ + bChanged = true; + set_str(&data->ResourceReply, i, m_status); + } + } + bool bOnLine = false; + status = STATUS_OFFLINE; + for (i = 1; i <= data->nResources.toULong(); i++){ + unsigned rStatus = get_str(data->ResourceStatus, i).toUInt(); + if (rStatus > status) + status = rStatus; + } + if (data->Status.toULong() != status){ + bChanged = true; + if ((status == STATUS_ONLINE) && + (((int)(time1.toTime_t() - m_client->data.owner.OnlineTime.toULong()) > 60) || + (data->Status.toULong() != STATUS_OFFLINE))) + bOnLine = true; + if (data->Status.toULong() == STATUS_OFFLINE){ + data->OnlineTime.asULong() = time1.toTime_t(); + data->richText.asBool() = true; + } + if (status == STATUS_OFFLINE && data->IsTyping.toBool()){ + data->IsTyping.asBool() = false; + EventContact e(contact, EventContact::eStatus);; + e.process(); + } + data->Status.asULong() = status; + data->StatusTime.asULong() = time1.toTime_t(); + } + if (data->invisible.toBool() != bInvisible){ + data->invisible.asBool() = bInvisible; + bChanged = true; + } + if (bChanged){ + StatusMessage *m = new StatusMessage(); + m->setContact(contact->id()); + m->setClient(m_client->dataName(data)); + m->setFlags(MESSAGE_RECEIVED); + m->setStatus(status); + EventMessageReceived e(m); + if(!e.process()) + delete m; + } + if (bOnLine && !contact->getIgnore() && !m_client->isAgent(data->ID.str())){ + EventContact e(contact, EventContact::eOnline); + e.process(); + } + } + } +} + +void JabberClient::PresenceRequest::element_start(const QString& el, const QXmlAttributes& attrs) +{ + if (el == "presence"){ + m_from = attrs.value("from"); + m_type = attrs.value("type"); + } + // XEP-0203: Delayed Delivery + if (el == "delay"){ + if (attrs.value("xmlns") == "http://www.xmpp.org/extensions/xep-0203.html#ns"){ + QString stamp = attrs.value("stamp"); + if (!stamp.isEmpty()){ + if (m_stamp1.isEmpty()){ + m_stamp1 = stamp; + }else if (m_stamp2.isEmpty()){ + m_stamp2 = stamp; + } + } + } + } else + if (el == "x"){ + // XEP-0091: Delayed Delivery + if (attrs.value("xmlns") == "jabber:x:delay"){ + QString stamp = attrs.value("stamp"); + if (!stamp.isEmpty()){ + if (m_stamp1.isEmpty()){ + m_stamp1 = stamp; + }else if (m_stamp2.isEmpty()){ + m_stamp2 = stamp; + } + } + } + } + m_data = QString::null; +} + +void JabberClient::PresenceRequest::element_end(const QString& el) +{ + if (el == "show"){ + m_show = m_data; + }else if (el == "status"){ + m_status = m_data; + } +} + +void JabberClient::PresenceRequest::char_data(const QString& str) +{ + m_data += str; +} + +JabberClient::IqRequest::IqRequest(JabberClient *client) + : ServerRequest(client, NULL, NULL, NULL) +{ + m_data = NULL; + m_file_size = 0; +} + +JabberClient::IqRequest::~IqRequest() +{ + JabberFileMessage *msg = NULL; + if (m_query == "jabber:iq:oob"){ + QString proto = m_url.left(7); + if (proto != "http://"){ + log(L_WARN, "Unknown protocol"); + return; + } + m_url = m_url.mid(7); + int n = m_url.indexOf(':'); + if (n < 0){ + log(L_WARN, "Port not found"); + return; + } + QString host = m_url.left(n); + unsigned short port = (unsigned short)m_url.mid(n + 1).toLong(); + n = m_url.indexOf('/'); + if (n < 0){ + log(L_WARN, "File not found"); + return; + } + QString file = m_url.mid(n + 1); + msg = new JabberFileMessage; + msg->setDescription(file); + msg->setText(m_descr); + msg->setHost(host); + msg->setPort(port); + }else if (!m_file_name.isEmpty()){ + msg = new JabberFileMessage; + msg->setDescription(m_file_name); + msg->setSize(m_file_size); + } + if (msg){ + Contact *contact; + QString resource; + JabberUserData *data = m_client->findContact(m_from, QString::null, false, contact, resource); + if (data == NULL){ + data = m_client->findContact(m_from, QString::null, true, contact, resource); + if (data == NULL) + return; + contact->setFlags(CONTACT_TEMP); + } + msg->setFrom(m_from); + msg->setID(m_id); + msg->setFlags(MESSAGE_RECEIVED | MESSAGE_TEMP); + msg->setClient(m_client->dataName(data)); + msg->setContact(contact->id()); + m_client->m_ackMsg.push_back(msg); + EventMessageReceived e(msg); + if (e.process()){ + for (list::iterator it = m_client->m_ackMsg.begin(); it != m_client->m_ackMsg.end(); ++it){ + if ((*it) == msg){ + m_client->m_ackMsg.erase(it); + break; + } + } + } + } +} + +void JabberClient::IqRequest::element_start(const QString& el, const QXmlAttributes& attrs) +{ + if (el == "iq"){ + m_from = attrs.value("from"); + m_id = attrs.value("id"); + m_type = attrs.value("type"); + return; + } + if (el == "query"){ + m_query = attrs.value("xmlns"); + } + if ( (el == "item") && (m_query == "jabber:iq:roster") ){ + QString jid = attrs.value("jid"); + QString subscription = attrs.value("subscription"); + QString name = attrs.value("name"); + if (!subscription.isEmpty()){ + unsigned subscribe = SUBSCRIBE_NONE; + if (subscription == "none"){ + subscribe = SUBSCRIBE_NONE; + }else if (subscription == "to"){ + subscribe = SUBSCRIBE_TO; + }else if (subscription == "from"){ + subscribe = SUBSCRIBE_FROM; + }else if (subscription == "both"){ + subscribe = SUBSCRIBE_BOTH; + }else if (subscription == "remove"){ + }else{ + log(L_DEBUG, "Unknown value subscription=%s", qPrintable(subscription)); + } + Contact *contact; + QString resource; + JabberUserData *data = m_client->findContact(jid, name, false, contact, resource); + if ((data == NULL) && (subscribe != SUBSCRIBE_NONE)){ + data = m_client->findContact(jid, name, true, contact, resource); + } + if (data && (data->Subscribe.toULong() != subscribe)){ + data->Subscribe.asULong() = subscribe; + EventContact e(contact, EventContact::eChanged); + e.process(); + if (m_client->getAutoSubscribe() && ((subscribe & SUBSCRIBE_FROM) == 0)){ + AuthMessage *msg = new AuthMessage(MessageAuthRequest); + msg->setContact(contact->id()); + msg->setFlags(MESSAGE_NOHISTORY); + m_client->send(msg, data); + } + } + } + } + // XEP-0092: Software Version + if ( (el == "query") && (m_query == "jabber:iq:version") ){ + if (m_type == "get" && m_client->getUseVersion()){ + // send our version + JabberClient::ServerRequest *req = new JabberClient::ServerRequest(m_client, JabberClient::ServerRequest::_RESULT, QString(), m_from, m_id); + req->start_element("query"); + req->add_attribute("xmlns", "jabber:iq:version"); + req->text_tag("name", PACKAGE); + req->text_tag("version", VERSION); + QString version = get_os_version(); + req->text_tag("os", version); + req->send(); + m_client->m_requests.push_back(req); + } + } + if (el == "url") + m_data = &m_url; + if (el == "desc") + m_data = &m_descr; + if (el == "file"){ + m_file_name = attrs.value("name"); + m_file_size = attrs.value("size").toUInt(); + } +} + +void JabberClient::IqRequest::element_end(const QString&) +{ + m_data = NULL; +} + +void JabberClient::IqRequest::char_data(const QString& str) +{ + if (m_data) + *m_data += str; +} + +JabberClient::StreamErrorRequest::StreamErrorRequest(JabberClient *client) + : ServerRequest(client, NULL, NULL, NULL) +{ +} + +JabberClient::StreamErrorRequest::~StreamErrorRequest() +{ + m_client->socket()->error_state(m_descr); +} + +void JabberClient::StreamErrorRequest::element_start(const QString& el, const QXmlAttributes&) +{ + if (el == "text"){ + m_data = &m_descr; + return; + } +} + +void JabberClient::StreamErrorRequest::element_end(const QString&) +{ + m_data = NULL; +} + +void JabberClient::StreamErrorRequest::char_data(const QString& str) +{ + if (m_data) + *m_data += str; +} + +class JabberBgParser : public HTMLParser +{ +public: + JabberBgParser(); + QString parse(const QString &text); + unsigned bgColor; +protected: + virtual void text(const QString &text); + virtual void tag_start(const QString &tag, const list &attrs); + virtual void tag_end(const QString &tag); + QString res; +}; + +JabberBgParser::JabberBgParser() +{ + bgColor = 0xFFFFFF; +} + +QString JabberBgParser::parse(const QString &text) +{ + res = QString::null; + HTMLParser::parse(text); + return res; +} + +void JabberBgParser::text(const QString &text) +{ + res += quoteString(text); +} + +void JabberBgParser::tag_start(const QString &tag, const list &attrs) +{ + if (tag == "body"){ + for (list::const_iterator it = attrs.begin(); it != attrs.end(); ++it){ + QString name = *it; + ++it; + QString value = *it; + if (name.toLower() == "bgcolor"){ + QColor c(value); + bgColor = c.rgb(); + } + } + return; + } + res += '<'; + res += tag; + for (list::const_iterator it = attrs.begin(); it != attrs.end(); ++it){ + QString name = *it; + ++it; + QString value = *it; + res += ' '; + res += name; + if (name == "style"){ + list styles = parseStyle(value); + for (list::iterator it = styles.begin(); it != styles.end(); ++it){ + QString name = *it; + ++it; + QString value = *it; + if (name == "background-color"){ + QColor c; + c.setNamedColor(value); + bgColor = c.rgb() & 0xFFFFFF; + } + } + } + if (!value.isEmpty()){ + res += "=\'"; + res += quoteString(value); + res += "\'"; + } + } + res += '>'; +} + +void JabberBgParser::tag_end(const QString &tag) +{ + if (tag == "body"){ + return; + } + res += "'; +} + +JabberClient::MessageRequest::MessageRequest(JabberClient *client) + : ServerRequest(client, NULL, NULL, NULL) +{ + m_data = NULL; + m_errorCode = 0; + m_bBody = false; + m_bCompose = false; + m_bEvent = false; + m_bRichText = false; + m_bEnc = false; + m_bRosters = false; + m_bError = false; +} + +JabberClient::MessageRequest::~MessageRequest() +{ + if (m_from.isEmpty()) + return; + Contact *contact; + QString resource; + JabberUserData *data = m_client->findContact(m_from, QString::null, false, contact, resource); + if (data == NULL){ + data = m_client->findContact(m_from, QString::null, true, contact, resource); + if (data == NULL) + return; + contact->setFlags(CONTACT_TEMP); + } + Message *msg = NULL; + + if (!m_bError){ + // JEP-0022 composing event handling + if (m_bBody){ + // Msg contains normal message. + // here means "send me composing events, please", so we should do it. + // But if that tag is absent, we must not send them. + data->SendTypingEvents.asBool() = m_bCompose; + data->TypingId.str() = (m_bCompose ? m_id : QString::null); + + // also, incoming message implicitly means that user has stopped typing + if (data->IsTyping.toBool()){ + data->IsTyping.asBool() = false; + EventContact e(contact, EventContact::eStatus);; + e.process(); + } + } + else{ + // Msg has no body ==> it is event message. + // Presence of here means "I'm typing", absence - "I'm not typing anymore". + data->IsTyping.asBool() = m_bCompose; + EventContact e(contact, EventContact::eStatus);; + e.process(); + } + } + + if (m_errorCode || !m_error.isEmpty()){ + if (!m_bEvent){ + JabberMessageError *m = new JabberMessageError; + m->setError(m_error); + m->setCode(m_errorCode); + msg = m; + } + }else if (m_bBody){ + if (!m_contacts.isEmpty()){ + msg = new ContactsMessage; + static_cast(msg)->setContacts(m_contacts); + }else if (m_subj.isEmpty()){ + msg = new Message(MessageGeneric); + }else{ + JabberMessage *m = new JabberMessage; + m->setSubject(m_subj); + msg = m; + } + } + if (msg == NULL) + return; + if (m_bBody && m_contacts.isEmpty()){ + if (!m_enc.isEmpty()){ + data->richText.asBool() = false; + msg->setText(m_enc); + }else if (m_richText.isEmpty()){ + data->richText.asBool() = false; + msg->setText(m_body); + }else{ + JabberBgParser p; + msg->setText(p.parse(m_richText)); + msg->setFlags(MESSAGE_RICHTEXT); + msg->setBackground(p.bgColor); + } + if (m_targets.size()){ + if ((msg->getFlags() & MESSAGE_RICHTEXT) == 0){ + msg->setText(quoteString(msg->getText())); + msg->setFlags(MESSAGE_RICHTEXT); + } + QString text = msg->getText(); + for (unsigned i = 0; i < m_targets.size(); i++){ + text += "
"; + text += quoteString(m_descs[i]); + text += ""; + } + } + }else{ + msg->setText(m_body); + } + msg->setFlags(msg->getFlags() | MESSAGE_RECEIVED); + msg->setClient(m_client->dataName(data)); + msg->setContact(contact->id()); + EventMessageReceived e(msg); + if (!e.process()) + delete msg; +} + +void JabberClient::MessageRequest::element_start(const QString& el, const QXmlAttributes& attrs) +{ + if (m_bRichText){ + *m_data += '<'; + *m_data += el; + for (int i = 0; i < attrs.count(); i++){ + *m_data += ' '; + *m_data += attrs.qName(i); + QChar ch('\''); + if(attrs.value(i).contains(QChar('\''))) + ch = QChar('"'); + *m_data += "="; + *m_data += ch; + *m_data += attrs.value(i); + *m_data += ch; + } + *m_data += '>'; + return; + } + m_data = NULL; + if (el == "message"){ + m_from = attrs.value("from"); + m_id = attrs.value("id"); + if (attrs.value("type") == "error") + m_bError = true; + return; + } + if (el == "body"){ + m_data = &m_body; + m_bBody = true; + return; + } + if (el == "subject"){ + m_data = &m_subj; + return; + } + if (el == "error"){ + m_errorCode = attrs.value("code").toUInt(); + m_data = &m_error; + return; + } + if (m_bEvent){ + // Parsing tag, which contains JEP-0022 event info + if (el == "composing"){ + m_bCompose = true; + return; + } + } + if (el == "url-data"){ + m_target = attrs.value("target"); + m_desc = QString::null; + return; + } + if (el == "desc"){ + m_data = &m_desc; + return; + } + if (m_bRosters && el == "item"){ + QString jid = attrs.value("jid"); + QString name = attrs.value("name"); + if (!jid.isEmpty()){ + if (!m_contacts.isEmpty()) + m_contacts += ';'; + m_contacts += "jabber:"; + m_contacts += jid; + if (name.isEmpty()){ + int n = jid.indexOf('@'); + if (n >= 0){ + name = jid.left(n); + }else{ + name = jid; + } + } + m_contacts += '/'; + m_contacts += name; + m_contacts += ','; + m_contacts += name; + m_contacts += " ("; + m_contacts += jid; + m_contacts += ')'; + } + return; + } + if (el == "x"){ + if (attrs.value("xmlns") == "jabber:x:event") + m_bEvent = true; + else if (attrs.value("xmlns") == "jabber:x:roster") + m_bRosters = true; + else if (attrs.value("xmlns") == "jabber:x:encrypted"){ + m_data = &m_enc; + *m_data += "-----BEGIN PGP MESSAGE-----\n\n"; + m_bEnc = true; + } + return; + } + if (el == "html"){ + if (attrs.value("xmlns") == "http://jabber.org/protocol/xhtml-im"){ + m_bRichText = true; + m_data = &m_richText; + } + return; + } +} + +void JabberClient::MessageRequest::element_end(const QString& el) +{ + if (m_bRichText){ + if (el == "html"){ + m_bRichText = false; + m_data = NULL; + return; + } + *m_data += "'; + return; + } else + if (el == "x") { + if (m_bEnc){ + m_bEnc = false; + *m_data += "\n-----END PGP MESSAGE-----\n"; + }else + m_bRosters = false; + } else + if (el == "url-data"){ + if (!m_target.isEmpty()){ + if (m_desc.isEmpty()) + m_desc = m_target; + m_targets.push_back(m_target); + m_descs.push_back(m_desc); + } + m_target = QString::null; + m_desc = QString::null; + } + m_data = NULL; +} + +void JabberClient::MessageRequest::char_data(const QString& str) +{ + if (m_data) + *m_data += str; +} + +class AgentRequest : public JabberClient::ServerRequest +{ +public: + AgentRequest(JabberClient *client, const QString &jid); + ~AgentRequest(); +protected: + JabberAgentsInfo data; + QString m_data; + QString m_jid; + bool m_bError; + virtual void element_start(const QString& el, const QXmlAttributes& attrs); + virtual void element_end(const QString& el); + virtual void char_data(const QString& str); +}; + +class AgentsDiscoRequest : public JabberClient::ServerRequest +{ +public: + AgentsDiscoRequest(JabberClient *client); +protected: + virtual void element_start(const QString& el, const QXmlAttributes& attrs); +}; + +class AgentDiscoRequest : public JabberClient::ServerRequest +{ +public: + AgentDiscoRequest(JabberClient *client, const QString &jid); + ~AgentDiscoRequest(); +protected: + JabberAgentsInfo data; + virtual void element_start(const QString& el, const QXmlAttributes& attrs); + bool m_bError; +}; + +static DataDef jabberAgentsInfo[] = + { + { "", DATA_STRING, 1, 0 }, + { "", DATA_STRING, 1, 0 }, + { "", DATA_STRING, 1, 0 }, + { "", DATA_BOOL, 1, 0 }, + { "", DATA_BOOL, 1, 0 }, + { "", DATA_ULONG, 1, 0 }, + { NULL, DATA_UNKNOWN, 0, 0 } + }; + +AgentDiscoRequest::AgentDiscoRequest(JabberClient *client, const QString &jid) + : ServerRequest(client, _GET, NULL, jid) +{ + load_data(jabberAgentsInfo, &data, NULL); + data.ID.str() = jid; + m_bError = false; +} + +AgentDiscoRequest::~AgentDiscoRequest() +{ + if (data.Name.str().isEmpty()){ + QString jid = data.ID.str(); + int n = jid.indexOf('.'); + if (n > 0){ + jid = jid.left(n); + data.Name.str() = jid; + } + } + if (m_bError){ + data.Register.asBool() = true; + data.Search.asBool() = true; + } + if (!data.Name.str().isEmpty()){ + data.VHost.str() = m_client->VHost(); + data.Client = m_client; +// unhandled ... +// Event e(EventAgentFound, &data); +// e.process(); + } + free_data(jabberAgentsInfo, &data); +} + +void AgentDiscoRequest::element_start(const QString& el, const QXmlAttributes& attrs) +{ + if (el == "error"){ + m_bError = true; + return; + } + if (el == "identity"){ + data.Name.str() = attrs.value("name"); + return; + } + if (el == "feature"){ + QString s = attrs.value("var"); + if (s == "jabber:iq:register") + data.Register.asBool() = true; + if (s == "jabber:iq:search") + data.Search.asBool() = true; + } +} + +AgentsDiscoRequest::AgentsDiscoRequest(JabberClient *client) + : ServerRequest(client, _GET, NULL, client->VHost()) +{ +} + +void AgentsDiscoRequest::element_start(const QString& el, const QXmlAttributes& attrs) +{ + if (el != "item") + return; + QString jid = attrs.value("jid"); + if (!jid.isEmpty()){ + AgentDiscoRequest *req = new AgentDiscoRequest(m_client, jid); + req->start_element("query"); + req->add_attribute("xmlns", "http://jabber.org/protocol/disco#info"); + req->send(); + m_client->m_requests.push_back(req); + } +} + +AgentRequest::AgentRequest(JabberClient *client, const QString &jid) + : ServerRequest(client, _GET, NULL, jid) +{ + load_data(jabberAgentsInfo, &data, NULL); + m_bError = false; + m_jid = jid; +} + +AgentRequest::~AgentRequest() +{ + free_data(jabberAgentsInfo, &data); + if (m_bError){ + AgentsDiscoRequest *req = new AgentsDiscoRequest(m_client); + req->start_element("query"); + req->add_attribute("xmlns", "http://jabber.org/protocol/disco#items"); + req->send(); + m_client->m_requests.push_back(req); + } +} + +void AgentRequest::element_start(const QString& el, const QXmlAttributes& attrs) +{ + if (el == "agent"){ + free_data(jabberAgentsInfo, &data); + load_data(jabberAgentsInfo, &data, NULL); + m_data = attrs.value("jid"); + data.ID.str() = m_data; + }else if (el == "search"){ + data.Search.asBool() = true; + }else if (el == "register"){ + data.Register.asBool() = true; + }else if (el == "error"){ + m_bError = true; + } + m_data = QString::null; +} + +void AgentRequest::element_end(const QString& el) +{ + if (el == "agent"){ + if (!data.ID.str().isEmpty()){ + data.VHost.str() = m_client->VHost(); + data.Client = m_client; +// unhandled ... +// Event e(EventAgentFound, &data); +// e.process(); + } + }else if (el == "name"){ + data.Name.str() = m_data; + } +} + +void AgentRequest::char_data(const QString& str) +{ + m_data += str; +} + +QString JabberClient::get_agents(const QString &jid) +{ + AgentRequest *req = new AgentRequest(this, jid); + req->start_element("query"); + req->add_attribute("xmlns", "jabber:iq:agents"); + addLang(req); + req->send(); + m_requests.push_back(req); + return req->m_id; +} + +class AgentInfoRequest : public JabberClient::ServerRequest +{ +public: + AgentInfoRequest(JabberClient *client, const QString &jid); + ~AgentInfoRequest(); +protected: + JabberAgentInfo data; + bool m_bOption; + QString m_data; + QString m_jid; + QString m_error; + bool m_bError; + unsigned m_error_code; + virtual void element_start(const QString& el, const QXmlAttributes& attrs); + virtual void element_end(const QString& el); + virtual void char_data(const QString& str); +}; + +static DataDef jabberAgentInfo[] = + { + { "", DATA_STRING, 1, 0 }, + { "", DATA_STRING, 1, 0 }, + { "", DATA_STRING, 1, 0 }, + { "", DATA_STRING, 1, 0 }, + { "", DATA_STRING, 1, 0 }, + { "", DATA_STRING, 1, 0 }, + { "", DATA_STRING, 1, 0 }, + { "", DATA_STRING, 1, 0 }, + { "", DATA_STRLIST, 1, 0 }, + { "", DATA_STRLIST, 1, 0 }, + { "", DATA_ULONG, 1, 0 }, + { "", DATA_BOOL, 1, 0 }, + { NULL, DATA_UNKNOWN, 0, 0 } + }; + + +AgentInfoRequest::AgentInfoRequest(JabberClient *client, const QString &jid) + : ServerRequest(client, _GET, NULL, jid) +{ + m_jid = jid; + m_bOption = false; + m_error_code = 0; + m_bError = false; + load_data(jabberAgentInfo, &data, NULL); +} + +AgentInfoRequest::~AgentInfoRequest() +{ + free_data(jabberAgentInfo, &data); + load_data(jabberAgentInfo, &data, NULL); + data.ID.str() = m_jid; + data.ReqID.str() = m_id; + data.nOptions.asULong() = m_error_code; + data.Label.str() = m_error; + EventAgentInfo(&data).process(); + free_data(jabberAgentInfo, &data); +} + +void AgentInfoRequest::element_start(const QString& el, const QXmlAttributes& attrs) +{ + if (el == "error"){ + m_bError = true; + m_error_code = attrs.value("code").toUInt(); + } + if (m_bError) + return; + if (el == "field"){ + free_data(jabberAgentInfo, &data); + load_data(jabberAgentInfo, &data, NULL); + data.ID.str() = m_jid; + m_data = attrs.value("var"); + data.Field.str() = m_data; + m_data = attrs.value("type"); + data.Type.str() = m_data; + m_data = attrs.value("label"); + data.Label.str() = m_data; + } + if (el == "option"){ + m_bOption = true; + m_data = attrs.value("label"); + set_str(&data.OptionLabels, data.nOptions.toULong(), m_data); + } + if (el == "x"){ + data.VHost.str() = m_client->VHost(); + data.Type.str() = "x"; + data.ReqID.str() = m_id; + data.ID.str() = m_jid; + EventAgentInfo(&data).process(); + free_data(jabberAgentInfo, &data); + load_data(jabberAgentInfo, &data, NULL); + } + m_data = QString::null; +} + +void AgentInfoRequest::element_end(const QString& el) +{ + if (el == "error"){ + m_error = m_data; + m_data = QString::null; + m_bError = false; + return; + } + if (m_bError) + return; + if (el == "desc"){ + data.Desc.str() = m_data; + return; + } + if (el == "field"){ + if (!data.Field.str().isEmpty()){ + data.VHost.str() = m_client->VHost(); + data.ReqID.str() = m_id; + data.ID.str() = m_jid; + EventAgentInfo(&data).process(); + free_data(jabberAgentInfo, &data); + load_data(jabberAgentInfo, &data, NULL); + } + }else if (el == "option"){ + m_bOption = false; + QString str = get_str(data.Options, data.nOptions.toULong()); + if (!str.isEmpty()) + data.nOptions.asULong()++; + }else if (el == "value"){ + if (m_bOption){ + set_str(&data.Options, data.nOptions.toULong(), m_data); + }else{ + data.Value.str() = m_data; + } + }else if (el == "required"){ + data.bRequired.asBool() = true; + }else if (el == "key" || el == "instructions"){ + data.Value.str() = m_data; + data.ID.str() = m_jid; + data.ReqID.str() = m_id; + data.Type.str() = el; + EventAgentInfo(&data).process(); + free_data(jabberAgentInfo, &data); + load_data(jabberAgentInfo, &data, NULL); + }else if (el != "error" && el != "iq" && el != "query" && el != "x"){ + data.Value.str() = m_data; + data.ID.str() = m_jid; + data.ReqID.str() = m_id; + data.Type.str() = el; + EventAgentInfo(&data).process(); + free_data(jabberAgentInfo, &data); + load_data(jabberAgentInfo, &data, NULL); + } +} + +void AgentInfoRequest::char_data(const QString& str) +{ + m_data += str; +} + +QString JabberClient::get_agent_info(const QString &jid, const QString &node, const QString &type) +{ + AgentInfoRequest *req = new AgentInfoRequest(this, jid); + req->start_element("query"); + QString xmlns = "jabber:iq:"; + xmlns += type; + req->add_attribute("xmlns", xmlns); + req->add_attribute("node", node); + addLang(req); + req->send(); + m_requests.push_back(req); + return req->m_id; +} + +typedef map VALUE_MAP; + +class SearchRequest : public JabberClient::ServerRequest +{ +public: + SearchRequest(JabberClient *client, const QString &jid); + ~SearchRequest(); +protected: + JabberSearchData data; + QString m_data; + QString m_attr; + list m_fields; + VALUE_MAP m_values; + bool m_bReported; + virtual void element_start(const QString& el, const QXmlAttributes& attrs); + virtual void element_end(const QString& el); + virtual void char_data(const QString& str); +}; + +static DataDef jabberSearchData[] = + { + { "", DATA_STRING, 1, 0 }, + { "", DATA_STRING, 1, 0 }, + { "", DATA_STRING, 1, 0 }, + { "", DATA_STRING, 1, 0 }, + { "", DATA_STRING, 1, 0 }, + { "", DATA_STRING, 1, 0 }, + { "", DATA_STRING, 1, 0 }, + { "", DATA_STRLIST, 1, 0 }, + { "", DATA_ULONG, 1, 0 }, + { NULL, DATA_UNKNOWN, 0, 0 } + }; + + +SearchRequest::SearchRequest(JabberClient *client, const QString &jid) + : ServerRequest(client, _SET, NULL, jid) +{ + load_data(jabberSearchData, &data, NULL); + m_bReported = false; +} + +SearchRequest::~SearchRequest() +{ + EventSearchDone(m_id).process(); + free_data(jabberSearchData, &data); +} + +void SearchRequest::element_start(const QString& el, const QXmlAttributes& attrs) +{ + if (el == "reported"){ + m_bReported = true; + }else if (el == "item"){ + free_data(jabberSearchData, &data); + load_data(jabberSearchData, &data, NULL); + m_data = attrs.value("jid"); + data.JID.str() = m_data; + }else if (el == "field"){ + QString var = attrs.value("var"); + if (m_bReported){ + if (!var.isEmpty() && (var != "jid")){ + QString label = attrs.value("label"); + if (label.isEmpty()) + label = var; + m_values.insert(VALUE_MAP::value_type(var, label)); + m_fields.push_back(var); + } + }else{ + m_attr = var; + } + } + m_data = QString::null; +} + +void SearchRequest::element_end(const QString& el) +{ + if (el == "reported"){ + m_bReported = false; + free_data(jabberSearchData, &data); + load_data(jabberSearchData, &data, NULL); + for (list::iterator it = m_fields.begin(); it != m_fields.end(); ++it){ + QString value; + VALUE_MAP::iterator itv = m_values.find((*it)); + if (itv != m_values.end()) + value = (*itv).second; + set_str(&data.Fields, data.nFields.toULong() * 2, value); + set_str(&data.Fields, data.nFields.toULong() * 2 + 1, value); + data.nFields.asULong()++; + } + data.ID.str() = m_id; + EventSearch(&data).process(); + m_values.clear(); + }else if (el == "item"){ + if (!data.JID.str().isEmpty()){ + for (list::iterator it = m_fields.begin(); it != m_fields.end(); ++it){ + VALUE_MAP::iterator itv = m_values.find((*it)); + if (itv != m_values.end()){ + QString val = (*itv).second; + set_str(&data.Fields, data.nFields.toULong(), val); + } + data.nFields.asULong()++; + } + data.ID.str() = m_id; + EventSearch(&data).process(); + m_values.clear(); + } + }else if (el == "value" || el == "field"){ + if (!m_attr.isEmpty() && !m_data.isEmpty()){ + if (m_attr == "jid"){ + data.JID.str() = m_data; + }else{ + m_values.insert(VALUE_MAP::value_type(m_attr, m_data)); + } + } + m_attr = QString::null; + }else if (el == "first"){ + data.First.str() = m_data; + }else if (el == "last"){ + data.Last.str() = m_data; + }else if (el == "nick"){ + data.Nick.str() = m_data; + }else if (el == "email"){ + data.EMail.str() = m_data; + }else if (el == "status"){ + data.Status.str() = m_data; + } +} + +void SearchRequest::char_data(const QString& str) +{ + m_data += str; +} + +QString JabberClient::search(const QString &jid, const QString &node, const QString &condition) +{ + SearchRequest *req = new SearchRequest(this, jid); + req->start_element("query"); + req->add_attribute("xmlns", "jabber:iq:search"); + req->add_attribute("node", node); + req->add_condition(condition, false); + req->send(); + m_requests.push_back(req); + return req->m_id; +} + +#if 0 +I18N_NOOP("Password does not match"); +I18N_NOOP("Low level network error"); +#endif + +class RegisterRequest : public JabberClient::ServerRequest +{ +public: + RegisterRequest(JabberClient *client, const QString &jid); + ~RegisterRequest(); +protected: + QString m_error; + QString *m_data; + unsigned m_error_code; + virtual void element_start(const QString& el, const QXmlAttributes& attrs); + virtual void element_end(const QString& el); + virtual void char_data(const QString& str); +}; + +RegisterRequest::RegisterRequest(JabberClient *client, const QString &jid) + : ServerRequest(client, _SET, NULL, jid) +{ + m_data = NULL; + m_error_code = (unsigned)(-1); +} + +RegisterRequest::~RegisterRequest() +{ + agentRegisterInfo ai; + ai.id = m_id; + ai.err_code = m_error_code; + ai.error = m_error; + EventAgentRegister(&ai).process(); +} + +void RegisterRequest::element_start(const QString& el, const QXmlAttributes& attrs) +{ + if (el == "error"){ + m_error_code = attrs.value("code").toUInt(); + if (m_error_code == 0) + m_error_code = (unsigned)(-1); + m_data = &m_error; + return; + } + if (el == "iq"){ + QString type = attrs.value("type"); + if (type == "result") + m_error_code = 0; + } +} + +void RegisterRequest::element_end(const QString&) +{ + m_data = NULL; +} + +void RegisterRequest::char_data(const QString& str) +{ + if (m_data != NULL) + *m_data += str; +} + +QString JabberClient::process(const QString &jid, const QString &node, const QString &condition, const QString &type) +{ + RegisterRequest *req = new RegisterRequest(this, jid); + req->start_element("query"); + QString xmlns = "jabber:iq:" + type; + req->add_attribute("xmlns", xmlns); + bool bData = (type == "data"); + if (bData) + req->add_attribute("type", "submit"); + req->add_attribute("node", node); + req->add_condition(condition, bData); + req->send(); + m_requests.push_back(req); + return req->m_id; +} + +void JabberClient::processList() +{ + if (getState() != Connected) + return; + for (list::iterator it = m_listRequests.begin(); it != m_listRequests.end(); ++it){ + JabberListRequest &r = (*it); + JabberClient::ServerRequest *req = new JabberClient::ServerRequest(this, JabberClient::ServerRequest::_SET, NULL, NULL); + req->start_element("query"); + req->add_attribute("xmlns", "jabber:iq:roster"); + req->start_element("item"); + req->add_attribute("jid", r.jid); + if (it->bDelete) + req->add_attribute("subscription", "remove"); + if (!it->name.isEmpty()) + req->add_attribute("name", r.name); + if (!it->bDelete) + req->text_tag("group", r.grp); + req->send(); + m_requests.push_back(req); + } + m_listRequests.clear(); +} + +class SendFileRequest : public JabberClient::ServerRequest +{ +public: + SendFileRequest(JabberClient *client, const QString &jid, FileMessage *msg); + ~SendFileRequest(); +protected: + virtual void element_start(const QString& el, const QXmlAttributes& attrs); + virtual void element_end(const QString& el); + virtual void char_data(const QString& str); + FileMessage *m_msg; +}; + +SendFileRequest::SendFileRequest(JabberClient *client, const QString &jid, FileMessage *msg) + : JabberClient::ServerRequest(client, _SET, NULL, jid) +{ + m_msg = msg; +} + +SendFileRequest::~SendFileRequest() +{ +} + +void SendFileRequest::element_start(const QString&, const QXmlAttributes&) +{ +} + +void SendFileRequest::element_end(const QString&) +{ +} + +void SendFileRequest::char_data(const QString&) +{ +} + +void JabberClient::sendFileRequest(FileMessage *msg, unsigned short, JabberUserData *data, const QString &fname, unsigned size) +{ + QString jid = data->ID.str(); + if (msg->getResource().isEmpty()){ + if (!data->Resource.str().isEmpty()){ + jid += '/'; + jid += data->Resource.str(); + } + }else{ + jid += '/'; + jid += msg->getResource(); + } + SendFileRequest *req = new SendFileRequest(this, jid, msg); + req->start_element("si"); + req->add_attribute("xmlns", "http://jabber.org/protocol/si"); + req->add_attribute("profile", "http://jabber.org/protocol/si/profile/file-transfer"); + req->add_attribute("id", get_unique_id()); + req->start_element("file"); + req->add_attribute("xmlns", "http://jabber.org/protocol/si/profile/file-transfer"); + req->add_attribute("size", QString::number(size)); + req->add_attribute("name", fname); + req->start_element("range"); + req->end_element(); + req->end_element(); + req->start_element("feature"); + req->add_attribute("xmlns", "http://jabber.org/protocol/feature-neg"); + req->start_element("x"); + req->add_attribute("xmlns", "jabber:x:data"); + req->add_attribute("type", "form"); + req->start_element("field"); + req->add_attribute("type", "list-single"); + req->add_attribute("var", "stream-method"); + req->start_element("option"); + req->text_tag("value", "http://jabber.org/protocol/bytestreams"); +#if 0 + req->start_element("query"); + req->add_attribute("xmlns", "jabber:iq:oob"); + QString url = "http://"; + struct in_addr addr; + addr.s_addr = socket()->localHost(); + url += inet_ntoa(addr); + url += ':'; + url += QString::number(port); + url += '/'; + url += fname; + QString desc; + desc = msg->getText(); + req->text_tag("url", url); + req->text_tag("desc", desc); +#endif + req->send(); + m_requests.push_back(req); +} + +void JabberClient::sendFileAccept(FileMessage *msg, JabberUserData *data) +{ + JabberFileMessage *m = static_cast(msg); + QString jid = data->ID.str(); + if (msg->getResource().isEmpty()){ + if (!data->Resource.str().isEmpty()){ + jid += '/'; + jid += data->Resource.str(); + } + }else{ + jid += '/'; + jid += msg->getResource(); + } + ServerRequest req(this, ServerRequest::_RESULT, NULL, jid, m->getID()); + req.start_element("si"); + req.add_attribute("xmlns", "http://jabber.org/protocol/si"); + req.start_element("feature"); + req.add_attribute("xmlns", "http://jabber.org/protocol/feature-neg"); + req.start_element("x"); + req.add_attribute("xmlns", "jabber:x:data"); + req.add_attribute("type", "submit"); + req.start_element("field"); + req.add_attribute("var", "stream-method"); + req.text_tag("value", "http://jabber.org/protocol/bytestreams"); + req.send(); +} + +class DiscoItemsRequest : public JabberClient::ServerRequest +{ +public: + DiscoItemsRequest(JabberClient *client, const QString &jid); + ~DiscoItemsRequest(); +protected: + virtual void element_start(const QString& el, const QXmlAttributes& attrs); + virtual void element_end(const QString& el); + virtual void char_data(const QString& str); + QString *m_data; + QString m_error; + unsigned m_code; +}; + +DiscoItemsRequest::DiscoItemsRequest(JabberClient *client, const QString &jid) + : JabberClient::ServerRequest(client, _GET, NULL, jid) +{ + m_data = NULL; + m_code = 0; +} + +DiscoItemsRequest::~DiscoItemsRequest() +{ + DiscoItem item; + item.id = m_id; + if (m_code){ + item.name = m_error; + item.node = QString::number(m_code); + } + EventDiscoItem(&item).process(); +} + +void DiscoItemsRequest::element_start(const QString& el, const QXmlAttributes& attrs) +{ + if (el == "item"){ + DiscoItem item; + item.id = m_id; + item.jid = attrs.value("jid"); + item.name = attrs.value("name"); + item.node = attrs.value("node"); + if (!item.jid.isEmpty()){ + EventDiscoItem(&item).process(); + } + } + if (el == "error"){ + m_code = attrs.value("code").toUInt(); + m_data = &m_error; + } +} + +void DiscoItemsRequest::element_end(const QString& el) +{ + if (el == "error") + m_data = NULL; +} + +void DiscoItemsRequest::char_data(const QString& str) +{ + if (m_data) + *m_data += str; +} + +QString JabberClient::discoItems(const QString &jid, const QString &node) +{ + if (getState() != Connected) + return QString::null; + DiscoItemsRequest *req = new DiscoItemsRequest(this, jid); + req->start_element("query"); + req->add_attribute("xmlns", "http://jabber.org/protocol/disco#items"); + req->add_attribute("node", node); + addLang(req); + req->send(); + m_requests.push_back(req); + return req->m_id; +} + +class DiscoInfoRequest : public JabberClient::ServerRequest +{ +public: + DiscoInfoRequest(JabberClient *client, const QString &jid); + ~DiscoInfoRequest(); +protected: + virtual void element_start(const QString& el, const QXmlAttributes& attrs); + virtual void element_end(const QString& el); + virtual void char_data(const QString& str); + QString *m_data; + QString m_error; + QString m_features; + QString m_name; + QString m_type; + QString m_category; + unsigned m_code; +}; + +DiscoInfoRequest::DiscoInfoRequest(JabberClient *client, const QString &jid) + : JabberClient::ServerRequest(client, _GET, NULL, jid) +{ + m_data = NULL; + m_code = 0; +} + +DiscoInfoRequest::~DiscoInfoRequest() +{ + if (m_code == 0){ + DiscoItem item; + item.id = m_id; + item.jid = "info"; + item.name = m_name; + item.category = m_category; + item.type = m_type; + item.features = m_features; + EventDiscoItem(&item).process(); + } + DiscoItem item; + item.id = m_id; + if (m_code){ + item.name = m_error; + item.node = QString::number(m_code); + } + EventDiscoItem(&item).process(); +} + +void DiscoInfoRequest::element_start(const QString& el, const QXmlAttributes& attrs) +{ + if (el == "identity"){ + m_category = attrs.value("category"); + m_name = attrs.value("name"); + m_type = attrs.value("type"); + } + if (el == "feature"){ + QString feature = attrs.value("var"); + if (!feature.isEmpty()){ + if (!m_features.isEmpty()) + m_features += '\n'; + m_features += feature; + } + } + if (el == "error"){ + m_code = attrs.value("code").toUInt(); + m_data = &m_error; + } +} + +void DiscoInfoRequest::element_end(const QString& el) +{ + if (el == "error") + m_data = NULL; +} + +void DiscoInfoRequest::char_data(const QString& str) +{ + if (m_data) + *m_data += str; +} + +QString JabberClient::discoInfo(const QString &jid, const QString &node) +{ + if (getState() != Connected) + return QString::null; + DiscoInfoRequest *req = new DiscoInfoRequest(this, jid); + req->start_element("query"); + req->add_attribute("xmlns", "http://jabber.org/protocol/disco#info"); + req->add_attribute("node", node); + req->send(); + m_requests.push_back(req); + return req->m_id; +} + +class BrowseRequest : public JabberClient::ServerRequest +{ +public: + BrowseRequest(JabberClient *client, const QString &jid); + ~BrowseRequest(); +protected: + virtual void element_start(const QString& el, const QXmlAttributes& attrs); + virtual void element_end(const QString& el); + virtual void char_data(const QString& str); + QString *m_data; + QString m_jid; + QString m_error; + QString m_name; + QString m_type; + QString m_category; + QString m_features; + QString m_ns; + unsigned m_code; +}; + +BrowseRequest::BrowseRequest(JabberClient *client, const QString &jid) + : JabberClient::ServerRequest(client, _GET, NULL, jid) +{ + m_data = NULL; + m_code = 0; + m_jid = jid; +} + +BrowseRequest::~BrowseRequest() +{ + if (!m_jid.isEmpty() && !m_name.isEmpty() && (m_code == 0)){ + DiscoItem item; + item.id = m_id; + item.jid = m_jid; + item.name = m_name; + item.type = m_type; + item.category = m_category; + item.features = m_features.toUtf8(); + EventDiscoItem(&item).process(); + } + DiscoItem item; + item.id = m_id; + if (m_code){ + item.name = m_error; + item.node = QString::number(m_code); + } + EventDiscoItem(&item).process(); +} + +void BrowseRequest::element_start(const QString& el, const QXmlAttributes& attrs) +{ + if (el == "error"){ + m_code = attrs.value("code").toUInt(); + m_data = &m_error; + } + if (el == "item" || el == "service" || el == "agent" || el == "headline"){ + if (!m_jid.isEmpty() && !m_name.isEmpty()){ + DiscoItem item; + item.id = m_id; + item.jid = m_jid; + item.name = m_name; + item.type = m_type; + item.category = m_category; + item.features = m_features; + EventDiscoItem(&item).process(); + } + m_jid = attrs.value("jid"); + m_name = attrs.value("name"); + m_type = attrs.value("type"); + m_category = attrs.value("category"); + if (el == "headline") + m_category = "headline"; + m_features = QString::null; + } + if (el == "query"){ + m_name = attrs.value("name"); + m_type = attrs.value("type"); + m_category = attrs.value("category"); + } + if (el == "ns") + m_data = &m_ns; +} + +void BrowseRequest::element_end(const QString& el) +{ + if (el == "error") + m_data = NULL; + if (el == "ns" && !m_ns.isEmpty()){ + if (!m_features.isEmpty()) + m_features += '\n'; + m_features += m_ns; + m_ns = QString::null; + m_data = NULL; + } + if ((el == "item" || el == "service" || + el == "agent" || el == "headline") + && !m_jid.isEmpty()){ + DiscoItem item; + item.id = m_id; + item.jid = m_jid; + item.name = m_name; + item.type = m_type; + item.category = m_category; + item.features = m_features; + EventDiscoItem(&item).process(); + m_jid = QString::null; + } +} + +void BrowseRequest::char_data(const QString& str) +{ + if (m_data) + *m_data += str; +} + +QString JabberClient::browse(const QString &jid) +{ + if (getState() != Connected) + return QString::null; + BrowseRequest *req = new BrowseRequest(this, jid); + req->start_element("query"); + req->add_attribute("xmlns", "jabber:iq:browse"); + req->send(); + m_requests.push_back(req); + return req->m_id; +} + +class VersionInfoRequest : public JabberClient::ServerRequest +{ +public: + VersionInfoRequest(JabberClient *client, const QString &jid, const QString &node); + ~VersionInfoRequest(); +protected: + virtual void element_start(const QString& el, const QXmlAttributes& attrs); + virtual void element_end(const QString& el); + virtual void char_data(const QString& str); + QString *m_data; + QString m_jid; + QString m_node; + QString m_name; + QString m_version; + QString m_os; +}; + +VersionInfoRequest::VersionInfoRequest(JabberClient *client, const QString &jid, const QString &node) + : JabberClient::ServerRequest(client, _GET, NULL, jid) +{ + m_data = NULL; + m_jid = jid; + m_node = node; +} + +VersionInfoRequest::~VersionInfoRequest() +{ + ClientVersionInfo info; + info.jid = m_jid; + info.node = m_node; + info.name = m_name; + info.version = m_version; + info.os = m_os; + EventClientVersion(&info).process(); +} + +void VersionInfoRequest::element_start(const QString& el, const QXmlAttributes&) +{ + if (el == "name") + m_data = &m_name; + if (el == "version") + m_data = &m_version; + if (el == "os") + m_data = &m_os; +} + +void VersionInfoRequest::element_end(const QString&) +{ + m_data = NULL; +} + +void VersionInfoRequest::char_data(const QString& str) +{ + if (m_data) + *m_data += str; +} + +QString JabberClient::versionInfo(const QString &jid, const QString &node) +{ + if (getState() != Connected) + return QString::null; + VersionInfoRequest *req = new VersionInfoRequest(this, jid, node); + req->start_element("query"); + req->add_attribute("xmlns", "jabber:iq:version"); + req->add_attribute("node", node); + req->send(); + m_requests.push_back(req); + return req->m_id; +} + +class TimeInfoRequest : public JabberClient::ServerRequest +{ +public: + TimeInfoRequest(JabberClient *client, const QString &jid); + ~TimeInfoRequest(); +protected: + virtual void element_start(const QString& el, const QXmlAttributes& attrs); + virtual void element_end(const QString& el); + virtual void char_data(const QString& str); + QString *m_data; + QString m_jid; + QString m_utc; + QString m_tz; + QString m_display; +}; + +TimeInfoRequest::TimeInfoRequest(JabberClient *client, const QString &jid) + : JabberClient::ServerRequest(client, _GET, NULL, jid) +{ + m_data = NULL; + m_jid = jid; +} + +TimeInfoRequest::~TimeInfoRequest() +{ + ClientTimeInfo info; + info.jid = m_jid; + info.utc = m_utc; + info.tz = m_tz; + info.display = m_display; + EventClientTimeInfo(&info).process(); +} + +void TimeInfoRequest::element_start(const QString& el, const QXmlAttributes&) +{ + if (el == "utc") + m_data = &m_utc; + if (el == "tz") + m_data = &m_tz; + if (el == "display") + m_data = &m_display; +} + +void TimeInfoRequest::element_end(const QString&) +{ + m_data = NULL; +} + +void TimeInfoRequest::char_data(const QString& str) +{ + if (m_data) + *m_data += str; +} + +QString JabberClient::timeInfo(const QString &jid, const QString &node) +{ + if (getState() != Connected) + return QString::null; + TimeInfoRequest *req = new TimeInfoRequest(this, jid); + req->start_element("query"); + req->add_attribute("xmlns", "jabber:iq:time"); + req->add_attribute("node", node); + req->send(); + m_requests.push_back(req); + return req->m_id; +} + +class LastInfoRequest : public JabberClient::ServerRequest +{ +public: + LastInfoRequest(JabberClient *client, const QString &jid); +protected: + virtual void element_start(const QString& el, const QXmlAttributes& attrs); + QString m_jid; +}; + +LastInfoRequest::LastInfoRequest(JabberClient *client, const QString &jid) + : JabberClient::ServerRequest(client, _GET, NULL, jid) +{ + m_jid = jid; +} + +void LastInfoRequest::element_start(const QString& el, const QXmlAttributes& attrs) +{ + if (el == "query"){ + ClientLastInfo info; + info.jid = m_jid; + info.seconds = attrs.value("seconds").toUInt(); + EventClientLastInfo(&info).process(); + } +} + +QString JabberClient::lastInfo(const QString &jid, const QString &node) +{ + if (getState() != Connected) + return QString::null; + LastInfoRequest *req = new LastInfoRequest(this, jid); + req->start_element("query"); + req->add_attribute("xmlns", "jabber:iq:last"); + req->add_attribute("node", node); + req->send(); + m_requests.push_back(req); + return req->m_id; +} + +class StatRequest : public JabberClient::ServerRequest +{ +public: + StatRequest(JabberClient *client, const QString &jid, const QString &id); + ~StatRequest(); +protected: + virtual void element_start(const QString& el, const QXmlAttributes& attrs); + QString m_id; +}; + +StatRequest::StatRequest(JabberClient *client, const QString &jid, const QString &id) + : JabberClient::ServerRequest(client, _GET, NULL, jid) +{ + m_id = id; +} + +StatRequest::~StatRequest() +{ + DiscoItem item; + item.id = m_id; + item.jid = QString::null; + EventDiscoItem(&item).process(); +} + +void StatRequest::element_start(const QString& el, const QXmlAttributes& attrs) +{ + if (el == "stat"){ + DiscoItem item; + item.id = m_id; + item.jid = attrs.value("name"); + item.name = attrs.value("units"); + item.node = attrs.value("value"); + EventDiscoItem(&item).process(); + } +} + +class StatItemsRequest : public JabberClient::ServerRequest +{ +public: + StatItemsRequest(JabberClient *client, const QString &jid, const QString &node); + ~StatItemsRequest(); +protected: + virtual void element_start(const QString& el, const QXmlAttributes& attrs); + list m_stats; + QString m_jid; + QString m_node; +}; + +StatItemsRequest::StatItemsRequest(JabberClient *client, const QString &jid, const QString &node) + : JabberClient::ServerRequest(client, _GET, NULL, jid) +{ + m_jid = jid; + m_node = node; +} + +StatItemsRequest::~StatItemsRequest() +{ + if (m_stats.empty()){ + DiscoItem item; + item.id = m_id; + item.jid = QString::null; + EventDiscoItem(&item).process(); + return; + } + StatRequest *req = new StatRequest(m_client, m_jid, m_id); + req->start_element("query"); + req->add_attribute("xmlns", "http://jabber.org/protocol/stats"); + req->add_attribute("node", m_node); + m_client->addLang(req); + for (list::iterator it = m_stats.begin(); it != m_stats.end(); ++it){ + req->start_element("stat"); + req->add_attribute("name", (*it)); + req->end_element(); + } + req->send(); + m_client->m_requests.push_back(req); +} + +void StatItemsRequest::element_start(const QString& el, const QXmlAttributes& attrs) +{ + if (el == "stat"){ + QString name = attrs.value("name"); + if (!name.isEmpty()) + m_stats.push_back(name); + } +} + +QString JabberClient::statInfo(const QString &jid, const QString &node) +{ + if (getState() != Connected) + return QString::null; + StatItemsRequest *req = new StatItemsRequest(this, jid, node); + req->start_element("query"); + req->add_attribute("xmlns", "http://jabber.org/protocol/stats"); + req->add_attribute("node", node); + addLang(req); + req->send(); + m_requests.push_back(req); + return req->m_id; +} + +static char XmlLang[] = I18N_NOOP("Please translate this to short language name like 'ru' or 'de'. Do not translate this sentence!)"); + +void JabberClient::addLang(ServerRequest *req) +{ + QString s = i18n(XmlLang); + if (s == XmlLang) + return; + req->add_attribute("xml:lang", s); +} + +class ChangePasswordRequest : public JabberClient::ServerRequest +{ +public: + ChangePasswordRequest(JabberClient *client, const QString &password); + ~ChangePasswordRequest(); +protected: + QString m_password; +}; + +ChangePasswordRequest::ChangePasswordRequest(JabberClient *client, const QString &password) + : JabberClient::ServerRequest(client, _SET, NULL, NULL) + , m_password(password) +{} + +ChangePasswordRequest::~ChangePasswordRequest() +{ + m_client->setPassword(m_password); +} + +void JabberClient::changePassword(const QString &password) +{ + if (getState() != Connected) + return; + QString id_name = data.owner.ID.str(); + int pos = id_name.indexOf('@'); + + if(pos != -1) + id_name = id_name.left(pos); + + ChangePasswordRequest *req = new ChangePasswordRequest(this, password); + req->start_element("query"); + req->add_attribute("xmlns", "jabber:iq:register"); + req->text_tag("username", id_name); + req->text_tag("password", password); + m_requests.push_back(req); + req->send(); +} + + diff --git a/plugins/jabber/jabber_ssl.cpp b/plugins/jabber/jabber_ssl.cpp new file mode 100644 index 0000000..1674f62 --- /dev/null +++ b/plugins/jabber/jabber_ssl.cpp @@ -0,0 +1,27 @@ +/*************************************************************************** + jabber_ssl.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "simapi.h" + +#include "jabber_ssl.h" + +using namespace SIM; + +JabberSSL::JabberSSL(Socket *s, bool forceSSL) + : SSLClient(s), m_forceSSL(forceSSL) +{ +} diff --git a/plugins/jabber/jabber_ssl.h b/plugins/jabber/jabber_ssl.h new file mode 100644 index 0000000..79dfe3a --- /dev/null +++ b/plugins/jabber/jabber_ssl.h @@ -0,0 +1,35 @@ +/*************************************************************************** + jabber_ssl.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _JABBER_SSL_H +#define _JABBER_SSL_H + +#include "simapi.h" +#include "socket/socket.h" +#include "socket/sslclient.h" + +class JabberSSL : public SIM::SSLClient +{ +public: + JabberSSL(SIM::Socket*, bool); +private: + bool m_forceSSL; + +}; + +#endif + diff --git a/plugins/jabber/jabberaboutinfo.cpp b/plugins/jabber/jabberaboutinfo.cpp new file mode 100644 index 0000000..24bafc8 --- /dev/null +++ b/plugins/jabber/jabberaboutinfo.cpp @@ -0,0 +1,83 @@ +/*************************************************************************** + jabberaboutinfo.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "jabberclient.h" +#include "jabberaboutinfo.h" +#include "jabber.h" +#include "contacts/contact.h" + +using namespace SIM; + +JabberAboutInfo::JabberAboutInfo(QWidget *parent, JabberUserData *data, JabberClient *client) : QWidget(parent) + //: JabberAboutInfoBase(parent) +{ + setupUi(this); + m_client = client; + m_data = data; + if (m_data) + edtAbout->setReadOnly(true); + fill(m_data); +} + +void JabberAboutInfo::apply() +{ +} + +bool JabberAboutInfo::processEvent(Event *e) +{ + if (e->type() == eEventContact){ + EventContact *ec = static_cast(e); + if(ec->action() != EventContact::eChanged) + return false; + Contact *contact = ec->contact(); + if (contact->clientData.have(m_data)) + fill(m_data); + } else + if ((e->type() == eEventClientChanged) && (m_data == 0)){ + EventClientChanged *ecc = static_cast(e); + if (ecc->client() == m_client) + fill(m_data); + } else + if (m_data && (e->type() == eEventVCard)){ + EventVCard *evc = static_cast(e); + JabberUserData *data = evc->data(); + if (m_data->ID.str() == data->ID.str() && m_data->Node.str() == data->Node.str()) + fill(data); + } + return false; +} + +void JabberAboutInfo::fill(JabberUserData *data) +{ + if (data == NULL) data = &m_client->data.owner; + edtAbout->setPlainText(data->Desc.str()); +} + +void JabberAboutInfo::apply(Client *client, void *_data) +{ + if (client != m_client) + return; + JabberUserData *data = m_client->toJabberUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + data->Desc.str() = edtAbout->toPlainText(); +} + +/* +#ifndef NO_MOC_INCLUDES +#include "jabberaboutinfo.moc" +#endif +*/ + diff --git a/plugins/jabber/jabberaboutinfo.h b/plugins/jabber/jabberaboutinfo.h new file mode 100644 index 0000000..d484a7c --- /dev/null +++ b/plugins/jabber/jabberaboutinfo.h @@ -0,0 +1,44 @@ +/*************************************************************************** + jabberaboutinfo.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _JABBERABOUTINFO_H +#define _JABBERABOUTINFO_H + +#include "ui_jabberaboutinfobase.h" +#include "event.h" + + +struct JabberUserData; +class JabberClient; + +class JabberAboutInfo : public QWidget, public Ui::JabberAboutInfo, public SIM::EventReceiver +{ + Q_OBJECT +public: + JabberAboutInfo(QWidget *parent, JabberUserData *data, JabberClient *client); +public slots: + void apply(); + void apply(SIM::Client*, void*); +protected: + virtual bool processEvent(SIM::Event *e); + void fill(JabberUserData *data); + JabberUserData *m_data; + JabberClient *m_client; +}; + +#endif + diff --git a/plugins/jabber/jabberaboutinfobase.ui b/plugins/jabber/jabberaboutinfobase.ui new file mode 100644 index 0000000..a7c67ff --- /dev/null +++ b/plugins/jabber/jabberaboutinfobase.ui @@ -0,0 +1,40 @@ + + + JabberAboutInfo + + + + 0 + 0 + 374 + 251 + + + + Form4 + + + + 6 + + + 11 + + + + + Additional information: + + + false + + + + + + + + + + + diff --git a/plugins/jabber/jabberadd.cpp b/plugins/jabber/jabberadd.cpp new file mode 100644 index 0000000..cd00e7c --- /dev/null +++ b/plugins/jabber/jabberadd.cpp @@ -0,0 +1,492 @@ +/*************************************************************************** + jabberadd.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include +#include + +#include "icons.h" +#include "simgui/intedit.h" +#include "simgui/listview.h" +#include "misc.h" +#include "log.h" +#include "contacts/contact.h" + +#include "jabberclient.h" +#include "jabberadd.h" +#include "jabber.h" +#include "jabbersearch.h" +#include "jabberbrowser.h" + +using namespace std; +using namespace SIM; + +const unsigned FILL_FIRST = 0x0001; +const unsigned FILL_LAST = 0x0002; +const unsigned FILL_NICK = 0x0004; +const unsigned FILL_MAIL = 0x0008; +const unsigned FILL_ALL = (FILL_FIRST + FILL_LAST + FILL_NICK + FILL_MAIL); + +JabberAdd::JabberAdd(JabberClient *client, QWidget *parent) : QWidget(parent) + //: JabberAddBase(parent) +{ + setupUi(this); + m_client = client; + m_browser = NULL; + m_bBrowser = false; + connect(this, SIGNAL(setAdd(bool)), topLevelWidget(), SLOT(setAdd(bool))); + connect(this, SIGNAL(addResult(QWidget*)), topLevelWidget(), SLOT(addResult(QWidget*))); + connect(this, SIGNAL(showResult(QWidget*)), topLevelWidget(), SLOT(showResult(QWidget*))); + connect(grpJID, SIGNAL(toggled(bool)), this, SLOT(radioToggled(bool))); + connect(grpMail, SIGNAL(toggled(bool)), this, SLOT(radioToggled(bool))); + connect(grpName, SIGNAL(toggled(bool)), this, SLOT(radioToggled(bool))); + connect(btnBrowser, SIGNAL(clicked()), this, SLOT(browserClick())); + QIcon is = Icon("1rightarrow"); + btnBrowser->setIcon(is); +} + +JabberAdd::~JabberAdd() +{ + if (m_browser) + delete m_browser; +} + +void JabberAdd::browserDestroyed() +{ + m_browser = NULL; +} + +void JabberAdd::radioToggled(bool) +{ + setBrowser(false); + log(L_DEBUG, "JabberAdd::radioToggled() FIXMEEEE!!!!"); + /* + if (isVisible()) + emit setAdd(grpJID->isChecked()); + */ +} + +void JabberAdd::showEvent(QShowEvent *e) +{ + log(L_DEBUG, "JabberAdd::showEvent() FIXMEEEE!!!!"); + QWidget::showEvent(e); + /* + emit setAdd(grpJID->isChecked()); + if (m_browser && m_bBrowser) + emit showResult(m_browser); + */ +} + +void JabberAdd::browserClick() +{ + setBrowser(!m_bBrowser); +} + +void JabberAdd::setBrowser(bool bBrowser) +{ + if (m_bBrowser == bBrowser) + return; + m_bBrowser = bBrowser; + if (m_bBrowser && (m_browser == NULL)){ + m_browser = new JabberBrowser; + emit addResult(m_browser); + m_browser->setClient(m_client); + connect(m_browser, SIGNAL(destroyed()), this, SLOT(browserDestroyed())); + } + emit showResult(m_bBrowser ? m_browser : NULL); + QIcon is = Icon(m_bBrowser ? "1leftarrow" : "1rightarrow"); + btnBrowser->setIcon(is); + if (m_bBrowser){ + edtJID->setEnabled(false); + edtMail->setEnabled(false); + edtFirst->setEnabled(false); + edtLast->setEnabled(false); + edtNick->setEnabled(false); + lblFirst->setEnabled(false); + lblLast->setEnabled(false); + lblNick->setEnabled(false); + emit setAdd(false); + }else{ + log(L_DEBUG, "JabberAdd::setBrowser() FIXMEEEE!!!!"); + //grpJID->slotToggled(); + //grpName->slotToggled(); + //grpMail->slotToggled(); + } +} + +void JabberAdd::createContact(unsigned tmpFlags, Contact *&contact) +{ + log(L_DEBUG, "JabberAdd::createContact() FIXMEEEE!!!!"); + /* + if (!grpJID->isChecked() || edtJID->text().isEmpty()) + return; + QString resource; + if (m_client->findContact(edtJID->text(), QString::null, false, contact, resource)) + return; + QString name = edtJID->text(); + int n = name.indexOf('@'); + if (n > 0) + name = name.left(n); + m_client->findContact(edtJID->text(), name, true, contact, resource, false); + contact->setFlags(contact->getFlags() | tmpFlags); + */ +} + +void JabberAdd::search() +{ + log(L_DEBUG, "JabberAdd::search() FIXMEEEE!!!!"); + /* + if (m_bBrowser) + return; + if (grpName->isChecked()) + searchName(edtFirst->text(), edtLast->text(), edtNick->text()); + if (grpMail->isChecked()) + searchMail(edtMail->text()); + */ +} + +void JabberAdd::searchMail(const QString &mail) +{ + m_mail = mail; + m_first = QString::null; + m_last = QString::null; + m_nick = QString::null; + startSearch(); +} + +void JabberAdd::searchName(const QString &first, const QString &last, const QString &nick) +{ + m_first = first; + m_last = last; + m_nick = nick; + m_mail = QString::null; + startSearch(); +} + +void JabberAdd::startSearch() +{ + m_disco_items.clear(); + m_fields.clear(); + m_labels.clear(); + m_agents.clear(); + m_nFields = 0; + m_id_disco = QString::null; + QString url; + if (m_client->getUseVHost()) + url = m_client->getVHost(); + if (url.isEmpty()) + url = m_client->getServer(); + m_id_browse = m_client->browse(url); +} + +void JabberAdd::addAttr(const QString &name, const QString &label) +{ + for (unsigned i = 0; i < m_fields.size(); i++){ + if (m_fields[i] == name) + return; + } + m_fields.push_back(name); + m_labels.push_back(label); +} + +void JabberAdd::searchStop() +{ + m_id_browse = QString::null; + m_id_disco = QString::null; + m_disco_items.clear(); + m_fields.clear(); + m_labels.clear(); + m_agents.clear(); + m_nFields = 0; +} + +void JabberAdd::addAttrs() +{ + if (m_fields.size() <= m_nFields) + return; + QStringList attrs; + for (; m_nFields < m_fields.size(); m_nFields++){ + attrs.append(m_fields[m_nFields]); + attrs.append(m_labels[m_nFields]); + } + emit setColumns(attrs, 0, this); +} + +bool JabberAdd::processEvent(Event *e) +{ + if (e->type() == eEventDiscoItem){ + EventDiscoItem *edi = static_cast(e); + DiscoItem *item = edi->item(); + if (m_id_browse == item->id){ + if (item->jid.isEmpty()){ + if (!item->node.isEmpty()){ + QString url; + if (m_client->getUseVHost()) + url = m_client->getVHost(); + if (url.isEmpty()) + url = m_client->getServer(); + m_id_disco = m_client->discoItems(url, QString::null); + } + m_id_browse = QString::null; + checkDone(); + return true; + } + addSearch(item->jid, QString::null, item->features, item->type); + return true; + } + if (m_id_disco == item->id){ + if (item->jid.isEmpty()){ + m_id_disco = QString::null; + checkDone(); + return true; + } + ItemInfo info; + info.jid = item->jid; + info.node = item->node; + info.id = m_client->discoInfo(info.jid, info.node); + m_disco_items.push_back(info); + return true; + } + list::iterator it; + for (it = m_disco_items.begin(); it != m_disco_items.end(); ++it){ + if (it->id == item->id){ + addSearch(it->jid, it->node, item->features, item->type); + m_disco_items.erase(it); + checkDone(); + break; + } + } + } else + if (e->type() == eEventAgentInfo){ + EventAgentInfo *eai = static_cast(e); + JabberAgentInfo *data = eai->agentInfo(); + list::iterator it; + for (it = m_agents.begin(); it != m_agents.end(); ++it) + if (it->id_info == data->ReqID.str()) + break; + if (it == m_agents.end()) + return false; + if (data->Type.str().isEmpty()){ + it->id_info = QString::null; + if (m_first.isEmpty()) + it->fill |= FILL_FIRST; + if (m_last.isEmpty()) + it->fill |= FILL_LAST; + if (m_nick.isEmpty()) + it->fill |= FILL_NICK; + if (m_mail.isEmpty()) + it->fill |= FILL_MAIL; + if (it->fill != FILL_ALL){ + m_agents.erase(it); + checkDone(); + return true; + } + it->id_search = m_client->search(it->jid, it->node, it->condition); + if (it->condition.left(6) != "x:data"){ + addAttr("", i18n("JID")); + addAttr("first", i18n("First Name")); + addAttr("last", i18n("Last Name")); + addAttr("nick", i18n("Nick")); + addAttr("email", i18n("E-Mail")); + addAttrs(); + } + return true; + } + if (data->Type.str() == "x"){ + it->condition = "x:data"; + it->fill = 0; + return true; + } + QString value; + QString field; + if (!data->Field.str().isEmpty() && + (data->Type.str() == "text-single" || + data->Type.str() == "text-private" || + data->Type.str() == "text-multi")){ + field = data->Field.str(); + if ((data->Field.str() == "first") && !m_first.isEmpty()){ + value = m_first; + it->fill |= FILL_FIRST; + } + if ((data->Field.str() == "last") && !m_last.isEmpty()){ + value = m_last; + it->fill |= FILL_LAST; + } + if (((data->Field.str() == "nickname") || (data->Field.str() == "nick")) && !m_nick.isEmpty()){ + value = m_nick; + it->fill |= FILL_NICK; + } + if ((data->Field.str() == "email") && !m_mail.isEmpty()){ + value = m_mail; + it->fill |= FILL_MAIL; + } + } + if ((data->Type.str() == "first") && !m_first.isEmpty()){ + field = data->Type.str(); + value = m_first; + it->fill |= FILL_FIRST; + } + if ((data->Type.str() == "last") && !m_last.isEmpty()){ + field = data->Type.str(); + value = m_last; + it->fill |= FILL_LAST; + } + if (((data->Type.str() == "nickname") || (data->Type.str() == "nick")) && !m_nick.isEmpty()){ + field = data->Type.str(); + value = m_nick; + it->fill |= FILL_NICK; + } + if ((data->Type.str() == "email") && !m_mail.isEmpty()){ + field = data->Type.str(); + value = m_mail; + it->fill |= FILL_MAIL; + } + if (!value.isEmpty()){ + if (!it->condition.isEmpty()) + it->condition += ';'; + it->condition += field; + it->condition += '='; + it->condition += quoteChars(value, ";"); + } + return true; + } + if (e->type() == eEventJabberSearch){ + EventSearch *es = static_cast(e); + JabberSearchData *data = es->searchData(); + list::iterator it; + for (it = m_agents.begin(); it != m_agents.end(); ++it) + if (it->id_search == data->ID.str()) + break; + if (it == m_agents.end()) + return false; + if (data->JID.str().isEmpty()){ + addAttr("", i18n("JID")); + for (unsigned i = 0; i < data->nFields.toULong(); i++){ + addAttr(get_str(data->Fields, i * 2), get_str(data->Fields, i * 2 + 1)); + it->fields.push_back(get_str(data->Fields, i * 2)); + } + addAttrs(); + return true; + } + QString icon = "Jabber"; + if (it->type == "icq"){ + icon = "ICQ"; + }else if (it->type == "aim"){ + icon = "AIM"; + }else if (it->type == "msn"){ + icon = "MSN"; + }else if (it->type == "yahoo"){ + icon = "Yahoo!"; + }else if (it->type == "sms"){ + icon = "sms"; + }else if ((it->type == "x-gadugadu") || (it->type == "gg")){ + icon = "GG"; + } + if (!data->Status.str().isEmpty()){ + if (data->Status.str() == "online"){ + icon += "_online"; + }else{ + icon += "_offline"; + } + } + QStringList l; + l.append(icon); + l.append(data->JID.str()); + for (unsigned i = 0; i < m_fields.size(); i++){ + QString v; + if (m_fields[i].isEmpty()){ + v = data->JID.str(); + }else if ((m_fields[i] == "first") && !data->First.str().isEmpty()){ + v = data->First.str(); + }else if ((m_fields[i] == "last") && !data->Last.str().isEmpty()){ + v = data->Last.str(); + }else if ((m_fields[i] == "nick") && !data->Nick.str().isEmpty()){ + v = data->Nick.str(); + }else if ((m_fields[i] == "email") && !data->EMail.str().isEmpty()){ + v = data->EMail.str(); + }else{ + for (unsigned n = 0; n < it->fields.size(); n++){ + if (it->fields[n] == m_fields[i]){ + v = get_str(data->Fields, n); + break; + } + } + } + l.append(v); + } + emit addItem(l, this); + } else + if (e->type() == eEventJabberSearchDone){ + EventSearchDone *esd = static_cast(e); + QString id = esd->userID(); + list::iterator it; + for (it = m_agents.begin(); it != m_agents.end(); ++it) + if (it->id_search == id) + break; + if (it == m_agents.end()) + return false; + m_agents.erase(it); + checkDone(); + return true; + } + return false; +} + +void JabberAdd::addSearch(const QString &jid, const QString &node, const QString &features, const QString &type) +{ + if (features.isEmpty()) + return; + QString f = features; + while (!f.isEmpty()){ + QString feature = getToken(f, '\n'); + if (feature == "jabber:iq:search"){ + AgentSearch as; + as.jid = jid; + as.node = node; + as.id_info = m_client->get_agent_info(jid, node, "search"); + as.fill = 0; + as.type = type; + m_agents.push_back(as); + return; + } + } +} + +void JabberAdd::checkDone() +{ + if (m_id_browse.isEmpty() && m_id_disco.isEmpty() && + m_disco_items.empty() && m_agents.empty()) + emit searchDone(this); +} + +void JabberAdd::createContact(const QString &name, unsigned tmpFlags, Contact *&contact) +{ + QString resource; + if (m_client->findContact(name, QString::null, false, contact, resource)) + return; + if (m_client->findContact(name, QString::null, true, contact, resource, false) == NULL) + return; + contact->setFlags(contact->getFlags() | tmpFlags); +} + +/* +#ifndef NO_MOC_INCLUDES +#include "jabberadd.moc" +#endif +*/ + diff --git a/plugins/jabber/jabberadd.h b/plugins/jabber/jabberadd.h new file mode 100644 index 0000000..15ac7b2 --- /dev/null +++ b/plugins/jabber/jabberadd.h @@ -0,0 +1,98 @@ +/*************************************************************************** + jabberadd.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _JABBERADD_H +#define _JABBERADD_H + +#include "jabberclient.h" +#include "ui_jabberaddbase.h" + +#include + +class JabberClient; +class JabberBrowser; +class GroupRadioButton; + +struct ItemInfo +{ + QString jid; + QString node; + QString id; +}; + +struct AgentSearch +{ + QString jid; + QString node; + QString id_info; + QString id_search; + QString condition; + unsigned fill; + std::vector fields; + QString type; +}; + +class JabberAdd : public QWidget, public Ui::JabberAdd, public SIM::EventReceiver +{ + Q_OBJECT +public: + JabberAdd(JabberClient *client, QWidget *parent); + ~JabberAdd(); +signals: + void setAdd(bool); + void addResult(QWidget*); + void showResult(QWidget*); + void setColumns(const QStringList&, int, QWidget*); + void addItem(const QStringList&, QWidget*); + void searchDone(QWidget*); +protected slots: + void radioToggled(bool); + void browserDestroyed(); + void browserClick(); + void search(); + void searchStop(); + void searchMail(const QString&); + void searchName(const QString&, const QString&, const QString&); + void createContact(const QString&, unsigned tmpFlags, SIM::Contact *&contact); + void createContact(unsigned tmpFlags, SIM::Contact *&contact); +protected: + virtual bool processEvent(SIM::Event *e); + void setBrowser(bool bBrowser); + void showEvent(QShowEvent*); + void startSearch(); + void checkDone(); + void addAttr(const QString &name, const QString &label); + void addAttrs(); + void addSearch(const QString &jid, const QString &node, const QString &features, const QString &type); + JabberClient *m_client; + JabberBrowser *m_browser; + bool m_bBrowser; + QString m_first; + QString m_last; + QString m_nick; + QString m_mail; + QString m_id_browse; + QString m_id_disco; + std::list m_disco_items; + std::list m_agents; + std::vector m_fields; + std::vector m_labels; + unsigned m_nFields; +}; + +#endif + diff --git a/plugins/jabber/jabberaddbase.ui b/plugins/jabber/jabberaddbase.ui new file mode 100644 index 0000000..78ca9a5 --- /dev/null +++ b/plugins/jabber/jabberaddbase.ui @@ -0,0 +1,145 @@ + + JabberAdd + + + + 0 + 0 + 196 + 381 + + + + + + + + 6 + + + 0 + + + + + &JID + + + + 6 + + + 11 + + + + + + + + + + + &E-Mail + + + + 6 + + + 11 + + + + + + + + + + + &Name + + + + 6 + + + 11 + + + + + First: + + + false + + + + + + + + + + Last: + + + false + + + + + + + + + + Nickname: + + + false + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + Jabber &browser + + + + + + + + RadioGroup +
simgui/intedit.h
+
+
+ + +
diff --git a/plugins/jabber/jabberbrowser.cpp b/plugins/jabber/jabberbrowser.cpp new file mode 100644 index 0000000..2bf18d1 --- /dev/null +++ b/plugins/jabber/jabberbrowser.cpp @@ -0,0 +1,1023 @@ +/*************************************************************************** + jabberbrowser.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "icons.h" +#include "jabberclient.h" +#include "jabberbrowser.h" +#include "jabbersearch.h" +#include "jabber.h" +#include "discoinfo.h" +#include "simgui/listview.h" +#include "simgui/toolbtn.h" +#include "jidsearch.h" +#include "simgui/ballonmsg.h" + +#include "core.h" + +#include "contacts/contact.h" + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace SIM; + +const unsigned BROWSE_INFO = 8; + +JabberWizard::JabberWizard(QWidget *parent, const QString &title, const QString &icon, JabberClient *client, const QString &jid, const QString &node, const QString &type) + : QWizard(parent, Qt::Window) +{ + setAttribute(Qt::WA_DeleteOnClose, true); + m_type = type; + m_search = new JabberSearch; + m_search->init(this, client, jid, node, title, m_type == "register"); + addPage(m_search); + /* + m_result = new QLabel(this); + addPage(m_result); + */ + m_result->setText(i18n("Process")); + //helpButton()->hide(); + SET_WNDPROC("jbrowser") + setWindowIcon(Icon(icon)); + setWindowTitle(title); + connect(this, SIGNAL(selected(const QString&)), this, SLOT(slotSelected(const QString&))); +} + +void JabberWizard::search() +{ + //showPage(m_result); +} + +void JabberWizard::textChanged(const QString&) +{ + setNext(); +} + +void JabberWizard::slotSelected(const QString&) +{ + //if (currentPage() != m_result) + return; + //setFinishEnabled(m_result, false); + QString condition = m_search->condition(NULL); //Fixme unreachable code + m_id = m_search->m_client->process(m_search->m_jid, m_search->m_node, condition, m_type); +} + +bool JabberWizard::processEvent(Event *e) +{ + if (e->type() == eEventAgentRegister){ + EventAgentRegister *ear = static_cast(e); + agentRegisterInfo *ai = ear->registerInfo(); + if (m_id == ai->id){ + if (ai->err_code){ + QString err = i18n(ai->error); + if (err.isEmpty()) + err = i18n("Error %1").arg(ai->err_code); + m_result->setText(err); + }else{ + m_result->setText(i18n("Done")); + //setFinishEnabled(m_result, true); + QTimer::singleShot(0, this, SLOT(close())); + } + return true; + } + } + return false; +} + +void JabberWizard::setNext() +{ + //nextButton()->setEnabled(m_search->canSearch()); +} + +void JabberWizard::initTitle() +{ + if (m_search->m_title.isEmpty()) + return; + setWindowTitle(m_search->m_title); +} + +JabberBrowser::JabberBrowser() +{ + m_client = NULL; + m_info = NULL; + + m_list = new ListView(this); + m_list->addColumn(i18n("Name")); + m_list->addColumn(i18n("JID")); + m_list->addColumn(i18n("Node")); + m_list->setExpandingColumn(0); + m_list->setMenu(0); + connect(m_list, SIGNAL(currentChanged(ListViewItem*)), this, SLOT(currentChanged(ListViewItem*))); + connect(m_list, SIGNAL(selectionChanged()), this, SLOT(selectionChanged())); + connect(m_list, SIGNAL(dragStart()), this, SLOT(dragStart())); + + EventToolbar e(BarBrowser, this); + e.process(); + m_bar = e.toolBar(); + m_bar->setParam(this); + restoreToolbar(m_bar, JabberPlugin::plugin->data.browser_bar); + m_bar->show(); + resize(qApp->desktop()->width(), qApp->desktop()->height()); + setCentralWidget(m_list); + m_historyPos = -1; + + Command cmd; + cmd->id = CmdUrl; + cmd->param = this; + EventCommandWidget eWidget(cmd); + eWidget.process(); + CToolCombo *cmbUrl = dynamic_cast(eWidget.widget()); + if (cmbUrl){ + QString h = JabberPlugin::plugin->getBrowserHistory(); + while (h.length()) + cmbUrl->insertItem(INT_MAX,getToken(h, ';')); + cmbUrl->setText(QString::null); + } + + m_reg = NULL; + m_config = NULL; + m_search = NULL; + m_bInProcess = false; + m_list->setMenu(MenuSearchItem); +} + +JabberBrowser::~JabberBrowser() +{ + if (m_info) + delete m_info; + save(); +} + +void JabberBrowser::setClient(JabberClient *client) +{ + if (m_client == client) + return; + m_client = client; + QString url; + if (m_client->getUseVHost()) + url = m_client->getVHost(); + if (url.isEmpty()) + url = m_client->getServer(); + goUrl(url, QString::null); +} + +void JabberBrowser::goUrl(const QString &url, const QString &node) +{ + int i = 0; + vector::iterator it; + for (it = m_history.begin(); it != m_history.end(); ++it, i++){ + if (i > m_historyPos) + break; + } + m_history.erase(it, m_history.end()); + m_history.push_back(url); + i = 0; + for (it = m_nodes.begin(); it != m_nodes.end(); ++it, i++){ + if (i > m_historyPos) + break; + } + m_nodes.erase(it, m_nodes.end()); + m_nodes.push_back(node); + m_historyPos++; + go(url, node); +} + +void JabberBrowser::go(const QString &url, const QString &node) +{ + setNavigation(); + Command cmd; + m_list->clear(); + cmd->id = CmdBrowseInfo; + cmd->flags = COMMAND_DISABLED; + cmd->param = this; + EventCommandDisabled(cmd).process(); + + cmd->id = CmdBrowseSearch; + cmd->flags = COMMAND_DISABLED; + cmd->param = this; + EventCommandDisabled(cmd).process(); + + cmd->id = CmdRegister; + cmd->flags = COMMAND_DISABLED; + cmd->param = this; + EventCommandDisabled(cmd).process(); + + cmd->id = CmdBrowseConfigure; + cmd->flags = COMMAND_DISABLED; + cmd->param = this; + EventCommandDisabled(cmd).process(); + + m_bInProcess = true; + ListViewItem *item = new ListViewItem(m_list); + item->setText(COL_JID, url); + item->setText(COL_NAME, url); + item->setText(COL_NODE, node); + m_bError = false; + unsigned mode = 0; + if (JabberPlugin::plugin->getBrowseType() & BROWSE_DISCO){ + item->setText(COL_ID_DISCO_ITEMS, m_client->discoItems(url, node)); + item->setText(COL_ID_DISCO_INFO, m_client->discoInfo(url, node)); + mode = BROWSE_DISCO | BROWSE_INFO; + } + if (JabberPlugin::plugin->getBrowseType() & BROWSE_BROWSE){ + if (node.isEmpty()){ + item->setText(COL_ID_BROWSE, m_client->browse(url)); + mode |= BROWSE_BROWSE; + } + } + item->setText(COL_MODE, QString::number(mode)); + item->setPixmap(COL_NAME, Pict("empty")); + cmd->id = CmdUrl; + cmd->param = this; + EventCommandWidget eWidget(cmd); + eWidget.process(); + CToolCombo *cmbUrl = dynamic_cast(eWidget.widget()); + if (cmbUrl) + cmbUrl->setText(url); + cmd->id = CmdNode; + EventCommandWidget eWidget2(cmd); + eWidget2.process(); + CToolCombo *cmbNode = dynamic_cast(eWidget2.widget()); + if (cmbNode) + cmbNode->setText(node); + startProcess(); + if (item->text(COL_ID_DISCO_INFO).isEmpty()) + stop(i18n("Client offline")); +} + +void JabberBrowser::startProcess() +{ + Command cmd; + cmd->id = CmdUrl; + cmd->text = I18N_NOOP("Stop"); + cmd->icon = "cancel"; + cmd->bar_grp = 0x2000; + cmd->flags = BTN_COMBO_CHECK; + cmd->param = this; + EventCommandChange(cmd).process(); +} + +void JabberBrowser::showEvent(QShowEvent *e) +{ + QMainWindow::showEvent(e); + selectionChanged(); +} + +void JabberBrowser::selectionChanged() +{ + emit enableOptions(m_list->selectedItems().count() > 0); +} + +void JabberBrowser::save() +{ + saveToolbar(m_bar, JabberPlugin::plugin->data.browser_bar); +} + +bool JabberBrowser::processEvent(Event *e) +{ + if (e->type() == eEventAgentInfo){ + EventAgentInfo *eai = static_cast(e); + JabberAgentInfo *data = eai->agentInfo(); + if (m_search_id == data->ReqID.str()){ + if (data->Type.str().isEmpty()){ + if (data->nOptions.toULong()){ + QString err = i18n(data->Label.str()); + if (err.isEmpty()) + err = i18n("Error %1") .arg(data->nOptions.toULong()); + m_search_id = QString::null; + Command cmd; + cmd->id = CmdBrowseSearch; + cmd->param = this; + EventCommandWidget eWidget(cmd); + eWidget.process(); + QWidget *parent = eWidget.widget(); + if (parent == NULL) + parent = this; + BalloonMsg::message(err, parent); + delete m_search; + }else{ + m_search->jidSearch->addWidget(data); + connect(this, SIGNAL(addSearch(QWidget*, SIM::Client*, const QString&)), topLevelWidget(), SLOT(addSearch(QWidget*, SIM::Client*, const QString&))); + emit addSearch(m_search, m_client, m_search->m_jid); + disconnect(this, SIGNAL(addSearch(QWidget*, SIM::Client*, const QString&)), topLevelWidget(), SLOT(addSearch(QWidget*, SIM::Client*, const QString&))); + } + m_search_id = QString::null; + m_search = NULL; + return true; + } + m_search->jidSearch->addWidget(data); + return true; + } + if (m_reg_id == data->ReqID.str()) { + if (data->Type.str().isEmpty()){ + if (data->nOptions.toULong()){ + QString err = i18n(data->Label.str()); + if (err.isEmpty()) + err = i18n("Error %1") .arg(data->nOptions.toULong()); + m_reg_id = QString::null; + delete m_reg; + m_reg = NULL; + Command cmd; + cmd->id = CmdRegister; + cmd->param = this; + EventCommandWidget eWidget(cmd); + eWidget.process(); + QWidget *parent = eWidget.widget(); + if (parent == NULL) + parent = this; + BalloonMsg::message(err, parent); + }else if (m_reg){ + m_reg->m_search->addWidget(data); + QTimer::singleShot(0, this, SLOT(showReg())); + } + m_reg_id = QString::null; + return true; + } + if (m_reg) + m_reg->m_search->addWidget(data); + return true; + } + if (m_config_id == data->ReqID.str()){ + if (data->Type.str().isEmpty()){ + if (data->nOptions.toULong()){ + QString err = i18n(data->Label.str()); + if (err.isEmpty()) + err = i18n("Error %1") .arg(data->nOptions.toULong()); + m_config_id = QString::null; + delete m_config; + m_config = NULL; + Command cmd; + cmd->id = CmdBrowseConfigure; + cmd->param = this; + EventCommandWidget eWidget(cmd); + eWidget.process(); + QWidget *parent = eWidget.widget(); + if (parent == NULL) + parent = this; + BalloonMsg::message(err, parent); + }else if (m_config){ + m_config->m_search->addWidget(data); + QTimer::singleShot(0, this, SLOT(showConfig())); + } + m_config_id = QString::null; + return true; + } + if (m_config) + m_config->m_search->addWidget(data); + return true; + } + } else + if (e->type() == eEventCheckCommandState){ + EventCheckCommandState *ecs = static_cast(e); + CommandDef *cmd = ecs->cmd(); + if ((cmd->menu_id == MenuSearchOptions) && isVisible()){ + cmd->flags &= ~COMMAND_CHECKED; + switch (cmd->id){ + case CmdBrowseSearch: + if (haveFeature("jabber:iq:search")) + return true; + break; + case CmdRegister: + if (haveFeature("jabber:iq:register")) + return true; + break; + case CmdBrowseConfigure: + if (haveFeature("jabber:iq:data")) + return true; + break; + } + return false; + } + if (cmd->param != this) + return false; + if (cmd->menu_id != MenuBrowser) + return false; + cmd->flags &= ~COMMAND_CHECKED; + switch (cmd->id){ + case CmdOneLevel: + if (!JabberPlugin::plugin->getAllLevels()) + cmd->flags |= COMMAND_CHECKED; + return true; + case CmdAllLevels: + if (JabberPlugin::plugin->getAllLevels()) + cmd->flags |= COMMAND_CHECKED; + return true; + case CmdModeDisco: + if (JabberPlugin::plugin->getBrowseType() & BROWSE_DISCO) + cmd->flags |= COMMAND_CHECKED; + return true; + case CmdModeBrowse: + if (JabberPlugin::plugin->getBrowseType() & BROWSE_BROWSE) + cmd->flags |= COMMAND_CHECKED; + return true; + case CmdModeAgents: + if (JabberPlugin::plugin->getBrowseType() & BROWSE_AGENTS) + cmd->flags |= COMMAND_CHECKED; + return true; + } + } else + if (e->type() == eEventCommandExec){ + EventCommandExec *ece = static_cast(e); + CommandDef *cmd = ece->cmd(); + if (((cmd->menu_id == MenuSearchItem) || (cmd->menu_id == MenuSearchOptions)) && isVisible()){ + Command c; + c->id = cmd->id; + if (cmd->id == CmdSearchInfo) + c->id = CmdBrowseInfo; + c->param = this; + EventCommandExec(c).process(); + } + if (cmd->param != this) + return false; + ListViewItem *item = m_list->currentItem(); + if (cmd->menu_id == MenuBrowser){ + cmd->flags &= ~COMMAND_CHECKED; + unsigned mode = JabberPlugin::plugin->getBrowseType(); + switch (cmd->id){ + case CmdOneLevel: + JabberPlugin::plugin->setAllLevels(false); + changeMode(); + return true; + case CmdAllLevels: + JabberPlugin::plugin->setAllLevels(true); + changeMode(); + return true; + case CmdModeDisco: + mode ^= BROWSE_DISCO; + JabberPlugin::plugin->setBrowseType(mode); + changeMode(); + return true; + case CmdModeBrowse: + mode ^= BROWSE_BROWSE; + JabberPlugin::plugin->setBrowseType(mode); + changeMode(); + return true; + case CmdModeAgents: + mode ^= BROWSE_AGENTS; + JabberPlugin::plugin->setBrowseType(mode); + changeMode(); + return true; + } + return false; + } + if (item){ + if (cmd->id == CmdBrowseSearch){ + if (m_search) + delete m_search; + m_search = new JIDSearch(this, m_client, item->text(COL_JID), item->text(COL_NODE), item->text(COL_TYPE)); + m_search->jidSearch->init(this, m_client, m_search->m_jid, m_search->m_node, QString::null, false); + m_search_id = m_client->get_agent_info(item->text(COL_JID), item->text(COL_NODE), "search"); + return true; + } + if (cmd->id == CmdRegister){ + if (m_reg) + delete m_reg; + m_reg = new JabberWizard(this, i18n("%1 Register") .arg(item->text(COL_NAME)), "reg", m_client, item->text(COL_JID), item->text(COL_NODE), "register"); + connect(m_reg, SIGNAL(destroyed()), this, SLOT(regFinished())); + m_reg_id = m_client->get_agent_info(item->text(COL_JID), item->text(COL_NODE), "register"); + return true; + } + if (cmd->id == CmdBrowseConfigure){ + if (m_config) + delete m_config; + m_config = new JabberWizard(this, i18n("%1 Configure") .arg(item->text(COL_NAME)), "configure", m_client, item->text(COL_JID), item->text(COL_NODE), "data"); + connect(m_config, SIGNAL(destroyed()), this, SLOT(configFinished())); + m_config_id = m_client->get_agent_info(item->text(COL_JID), item->text(COL_NODE), "data"); + return true; + } + if (cmd->id == CmdBrowseInfo){ + if (m_info == NULL) + m_info = new DiscoInfo(this, m_list->currentItem()->text(COL_FEATURES), item->text(COL_NAME), item->text(COL_TYPE), item->text(COL_CATEGORY)); + m_info->reset(); + raiseWindow(m_info); + return true; + } + } + if (cmd->id == CmdBack){ + if (m_historyPos){ + m_historyPos--; + QString url = m_history[m_historyPos]; + QString node = m_nodes[m_historyPos]; + go(url, node); + } + } + if (cmd->id == CmdForward){ + if (m_historyPos + 1 < (int)(m_history.size())){ + m_historyPos++; + QString url = m_history[m_historyPos]; + QString node = m_nodes[m_historyPos]; + go(url, node); + } + } + if (cmd->id == CmdUrl){ + if (m_bInProcess){ + stop(QString::null); + return true; + } + QString jid; + QString node; + Command cmd; + cmd->id = CmdUrl; + cmd->param = this; + EventCommandWidget eWidget(cmd); + eWidget.process(); + CToolCombo *cmbUrl = dynamic_cast(eWidget.widget()); + if (cmbUrl) + jid = cmbUrl->lineEdit()->text(); + cmd->id = CmdNode; + EventCommandWidget eWidget2(cmd); + eWidget2.process(); + CToolCombo *cmbNode = dynamic_cast(eWidget2.widget()); + if (cmbNode) + node = cmbNode->lineEdit()->text(); + if (!jid.isEmpty()){ + addHistory(jid); + goUrl(jid, node); + } + return true; + } + } else + if (e->type() == eEventDiscoItem){ + if (!m_bInProcess) + return false; + EventDiscoItem *edi = static_cast(e); + DiscoItem *item = edi->item(); + ListViewItem *it = findItem(COL_ID_DISCO_ITEMS, item->id); + if (it){ + if (item->jid.isEmpty()){ + it->setText(COL_ID_DISCO_ITEMS, QString::null); + if (it != m_list->topLevelItem(0)){ + checkDone(); + adjustColumn(it); + return true; + } + QString err; + if (!item->name.isEmpty()){ + err = item->name; + }else if (!item->node.isEmpty()){ + err = i18n("Error %1") .arg(item->node.toULong()); + } + if (!err.isEmpty()){ + unsigned mode = it->text(COL_MODE).toLong(); + if (((mode & BROWSE_BROWSE) == 0) || (it->text(COL_ID_BROWSE).isEmpty() & m_bError)) + stop(err); + m_bError = true; + } + checkDone(); + adjustColumn(it); + return true; + } + if (it->child(0) == NULL){ + it->setExpandable(true); + if ((it == m_list->topLevelItem(0)) || (it == m_list->currentItem())) + it->setOpen(true); + } + ListViewItem *i; + for(int c = 0; c < m_list->topLevelItemCount(); c++) + { + ListViewItem *i= static_cast(m_list->topLevelItem(c)); + if ((i->text(COL_JID) == item->jid) && + (i->text(COL_NODE) == item->node)) + return true; + } + i = new ListViewItem(it); + i->setText(COL_JID, item->jid); + i->setText(COL_NAME, item->name.isEmpty() ? item->jid : item->name); + i->setText(COL_NODE, item->node); + int mode = 0; + if (JabberPlugin::plugin->getBrowseType() & BROWSE_DISCO){ + i->setText(COL_ID_DISCO_INFO, m_client->discoInfo(item->jid, item->node)); + mode |= BROWSE_INFO; + } + i->setText(COL_MODE, QString::number(mode)); + if (JabberPlugin::plugin->getAllLevels()) + loadItem(i); + return true; + } + it = findItem(COL_ID_DISCO_INFO, item->id); + if (it){ + if (item->jid.isEmpty()){ + it->setText(COL_ID_DISCO_INFO, QString::null); + checkDone(); + adjustColumn(it); + return true; + } + if (it->text(COL_NAME) == it->text(COL_JID)) + it->setText(COL_NAME, item->name); + it->setText(COL_CATEGORY, item->category); + it->setText(COL_TYPE, item->type); + it->setText(COL_FEATURES, item->features); + if ((JabberPlugin::plugin->getAllLevels()) || (it == m_list->currentItem())) + loadItem(it); + setItemPict(it); + if (it == m_list->currentItem()) + currentChanged(it); + return true; + } + it = findItem(COL_ID_BROWSE, item->id); + if (it){ + if (item->jid.isEmpty()){ + it->setText(COL_ID_BROWSE, QString::null); + if (it != m_list->topLevelItem(0)){ + checkDone(); + adjustColumn(it); + return true; + } + QString err; + if (!item->name.isEmpty()){ + err = item->name; + }else if (!item->node.isEmpty()){ + err = i18n("Error %1") .arg(item->node.toULong()); + } + if (!err.isEmpty()){ + unsigned mode = it->text(COL_MODE).toLong(); + if (((mode & BROWSE_DISCO) == 0) || (it->text(COL_ID_DISCO_ITEMS).isEmpty() & m_bError)) + stop(err); + m_bError = true; + } + checkDone(); + adjustColumn(it); + return true; + } + ListViewItem* i=NULL; + if (it->text(COL_JID) != item->jid){ + + for(int c = 0; c < it->childCount(); c++) + { + i= static_cast(it->child(0)); + if ((i->text(COL_JID) == item->jid) && + (i->text(COL_NODE) == item->node)) + break; + } + if (i) //Fixme warning C4701: potentially uninitialized local variable 'i' used + { + it = i; + }else{ + if (it->child(0) == NULL){ + it->setExpandable(true); + if ((it == m_list->topLevelItem(0)) || (it == m_list->currentItem())) + it->setOpen(true); + } + it = new ListViewItem(it); + it->setText(COL_JID, item->jid); + it->setText(COL_MODE, "0"); + if (JabberPlugin::plugin->getAllLevels()) + loadItem(it); + } + } + if (it->text(COL_NAME).isEmpty() || (it->text(COL_NAME) == it->text(COL_JID))) + it->setText(COL_NAME, item->name); + it->setText(COL_NODE, QString::null); + it->setText(COL_CATEGORY, item->category); + it->setText(COL_TYPE, item->type); + it->setText(COL_FEATURES, item->features); + if (JabberPlugin::plugin->getAllLevels() || (it == m_list->currentItem())) + loadItem(it); + setItemPict(it); + return true; + } + } + return false; +} + +void JabberBrowser::configFinished() +{ + m_config = NULL; +} + +void JabberBrowser::regFinished() +{ + m_reg = NULL; +} + +void JabberBrowser::setNavigation() +{ + Command cmd; + cmd->id = CmdBack; + cmd->flags = m_historyPos ? 0 : COMMAND_DISABLED; + cmd->param = this; + EventCommandDisabled(cmd).process(); + + cmd->id = CmdForward; + cmd->flags = (m_historyPos + 1 < (int)(m_history.size())) ? 0 : COMMAND_DISABLED; + cmd->param = this; + EventCommandDisabled(cmd).process(); +} + +void JabberBrowser::currentChanged(ListViewItem*) +{ + Command cmd; + cmd->id = CmdBrowseInfo; + cmd->flags = m_list->currentItem() ? 0 : COMMAND_DISABLED; + cmd->param = this; + EventCommandDisabled(cmd).process(); + + cmd->id = CmdBrowseSearch; + cmd->flags = haveFeature("jabber:iq:search") ? 0 : COMMAND_DISABLED; + EventCommandDisabled(cmd).process(); + + cmd->id = CmdRegister; + cmd->flags = haveFeature("jabber:iq:register") ? 0 : COMMAND_DISABLED; + EventCommandDisabled(cmd).process(); + + cmd->id = CmdBrowseConfigure; + cmd->flags = haveFeature("jabber:iq:data") ? 0 : COMMAND_DISABLED; + EventCommandDisabled(cmd).process(); + + ListViewItem *item = m_list->currentItem(); + if (item == NULL) + return; + loadItem(item); +} + +void JabberBrowser::loadItem(ListViewItem *item) +{ + bool bProcess = false; + unsigned mode = item->text(COL_MODE).toLong(); + if (JabberPlugin::plugin->getBrowseType() & BROWSE_DISCO){ + if (((mode & BROWSE_DISCO) == 0) && item->text(COL_ID_DISCO_ITEMS).isEmpty()){ + item->setText(COL_ID_DISCO_ITEMS, m_client->discoItems(item->text(COL_JID), item->text(COL_NODE))); + mode |= BROWSE_DISCO; + bProcess = true; + } + if (((mode & BROWSE_INFO) == 0) && item->text(COL_ID_DISCO_INFO).isEmpty()){ + item->setText(COL_ID_DISCO_INFO, m_client->discoInfo(item->text(COL_JID), item->text(COL_NODE))); + mode |= BROWSE_INFO; + bProcess = true; + } + } + if (JabberPlugin::plugin->getBrowseType() & BROWSE_BROWSE){ + if (((mode & BROWSE_BROWSE) == 0) && item->text(COL_ID_BROWSE).isEmpty() && haveFeature("iq:id:browse", item->text(COL_FEATURES))){ + item->setText(COL_ID_BROWSE, m_client->browse(item->text(COL_JID))); + mode |= BROWSE_BROWSE; + bProcess = true; + } + } + item->setText(COL_MODE, QString::number(mode)); + if (!m_bInProcess && bProcess){ + m_bInProcess = true; + startProcess(); + } +} + +void JabberBrowser::changeMode() +{ + if (JabberPlugin::plugin->getAllLevels()){ + if (m_list->firstChild()) + changeMode(m_list->firstChild()); + }else{ + if (m_list->firstChild()) + loadItem(m_list->firstChild()); + if (m_list->currentItem()) + loadItem(m_list->currentItem()); + } +} + +void JabberBrowser::changeMode(ListViewItem *item) +{ + loadItem(item); + for(int c = 0; c < item->childCount(); c++) + { +// ListViewItem *i = static_cast(item->child(c)); + changeMode(item); + } +} + +void JabberBrowser::dragStart() +{ +/* + ListViewItem *item = m_list->currentItem(); + if (item == NULL) + return; + Contact *contact; + QString resource; + JabberUserData *data = m_client->findContact(item->text(COL_JID), QString::null, false, contact, resource); + if (data == NULL){ + m_client->findContact(item->text(COL_JID), item->text(COL_NAME), true, contact, resource); + contact->setFlags(CONTACT_DRAG); + } + m_list->startDrag(new ContactDragObject(m_list, contact)); +*/ +} + +void JabberBrowser::stop(const QString &err) +{ + if (!m_bInProcess) + return; + m_bInProcess = false; + Command cmd; + cmd->id = CmdUrl; + cmd->text = I18N_NOOP("JID"); + cmd->icon = "run"; + cmd->bar_grp = 0x2000; + cmd->flags = BTN_COMBO_CHECK; + cmd->param = this; + EventCommandChange(cmd).process(); + if (!err.isEmpty()){ + Command cmd; + cmd->id = CmdUrl; + cmd->param = this; + EventCommandWidget eWidget(cmd); + eWidget.process(); + QWidget *parent = eWidget.widget(); + if (parent == NULL) + parent = this; + BalloonMsg::message(err, parent); + } +} + +const unsigned MAX_HISTORY = 10; + +void JabberBrowser::addHistory(const QString &str) +{ + QStringList l = JabberPlugin::plugin->getBrowserHistory().split(';'); + l.removeAll(str); + l.prepend(str); + QString res; + Command cmd; + cmd->id = CmdUrl; + cmd->param = this; + EventCommandWidget eWidget(cmd); + eWidget.process(); + CToolCombo *cmbUrl = dynamic_cast(eWidget.widget()); + if (cmbUrl) + cmbUrl->clear(); + unsigned i = 0; + Q_FOREACH(const QString &str, l) { + if (i++ > MAX_HISTORY) + break; + if (!res.isEmpty()) + res += ';'; + cmbUrl->addItem(str); + res += quoteChars(str, ";"); + } + JabberPlugin::plugin->setBrowserHistory(res); +} + +bool JabberBrowser::haveFeature(const char *feature) +{ + QString features; + if (m_list->currentItem()) + features = m_list->currentItem()->text(COL_FEATURES); + return haveFeature(feature, features); +} + +bool JabberBrowser::haveFeature(const char *feature, const QString &features) +{ + if (features.isEmpty()) + return false; + QString ff = features; + while (!ff.isEmpty()){ + QString f = getToken(ff, '\n'); + if (f == feature) + return true; + } + return false; +} + +void JabberBrowser::showReg() +{ + if (m_reg){ + m_reg->initTitle(); + QTimer::singleShot(0, m_reg, SLOT(setNext())); + m_reg->show(); + } +} + +void JabberBrowser::showConfig() +{ + if (m_config){ + m_config->initTitle(); + QTimer::singleShot(0, m_config, SLOT(setNext())); + m_config->show(); + } +} + +ListViewItem *JabberBrowser::findItem(unsigned col, const QString &id) +{ + if (m_list->firstChild() == NULL) + return NULL; + return findItem(col, id, m_list->firstChild()); +} + +ListViewItem *JabberBrowser::findItem(unsigned col, const QString &id, ListViewItem *item) +{ + if (item->text(col) == id) + return item; + for(int c = 0; c < item->childCount(); c++) + { + ListViewItem *i= static_cast(item->child(c)); + ListViewItem *res = findItem(col, id, i); + if (res) + return res; + } + return NULL; +} + +void JabberBrowser::checkDone() +{ + if (m_list->firstChild() && checkDone(m_list->firstChild())) + stop(QString::null); +} + +bool JabberBrowser::checkDone(ListViewItem *item) +{ + if (!item->text(COL_ID_DISCO_ITEMS).isEmpty() || + !item->text(COL_ID_DISCO_INFO).isEmpty() || + !item->text(COL_ID_BROWSE).isEmpty()){ + return false; + } + for(int c = 0; c < item->childCount(); c++) + { + ListViewItem *i= static_cast(item->child(c)); + if (!checkDone(i)) + return false; + } + return true; +} + +void JabberBrowser::setItemPict(ListViewItem *item) +{ + const char *name = "Jabber"; + QString category = item->text(COL_CATEGORY); + QString type = item->text(COL_TYPE); + if (category == "headline"){ + name = "info"; + }else if (category == "directory"){ + name = "find"; + }else if (category == "conference"){ + name = "chat"; + }else if (category == "proxy"){ + name = "connect"; + }else if (type == "icq"){ + name = "ICQ"; + }else if (type == "aim"){ + name = "AIM"; + }else if (type == "msn"){ + name = "MSN"; + }else if (type == "yahoo"){ + name = "Yahoo!"; + }else if (type == "jud"){ + name = "find"; + }else if (type == "sms"){ + name = "sms"; + }else if ((type == "x-gadugadu") || (type == "gg")){ + name = "GG"; + }else if ((type == "rss") || (type == "weather")){ + name = "info"; + } + item->setPixmap(COL_NAME, Pict(name)); +} + +void JabberBrowser::adjustColumn(ListViewItem *item) +{ + for (; item; item = static_cast(item->parent())){ + if (item->isExpandable() && !item->isOpen()) + return; + } + m_list->adjustColumn(); +} + +void JabberBrowser::search() +{ +} + +void JabberBrowser::textChanged(const QString&) +{ +} + +void JabberWizard::layOutButtonRow(QHBoxLayout *layout){} +void JabberWizard::layOutTitleRow(QHBoxLayout *layout, const QString &title){} + +#if 0 + +I18N_NOOP("Choose a user and password to register with the server"); + +#endif + +/* +#ifndef NO_MOC_INCLUDES +#include "jabberbrowser.moc" +#endif +*/ + diff --git a/plugins/jabber/jabberbrowser.h b/plugins/jabber/jabberbrowser.h new file mode 100644 index 0000000..85ec95e --- /dev/null +++ b/plugins/jabber/jabberbrowser.h @@ -0,0 +1,133 @@ +/*************************************************************************** + jabberbrowser.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _JABBERBROWSER_H +#define _JABBERBROWSER_H + +#include "jabberclient.h" + +#include +#include +#include +#include +#include + +class ListView; +class ListViewItem; +class QStatusBar; +class CToolBar; +class DiscoInfo; +class JabberWizard; +class QLabel; + +const unsigned COL_NAME = 0; +const unsigned COL_JID = 1; +const unsigned COL_NODE = 2; +const unsigned COL_CATEGORY = 3; +const unsigned COL_TYPE = 4; +const unsigned COL_FEATURES = 5; +const unsigned COL_ID_DISCO_ITEMS = 6; +const unsigned COL_ID_DISCO_INFO = 7; +const unsigned COL_ID_BROWSE = 8; +const unsigned COL_MODE = 9; + +class JabberSearch; +class JIDSearch; + +class JabberWizard : public QWizard, public SIM::EventReceiver +{ + Q_OBJECT +public: + JabberWizard(QWidget *parent, const QString &title, const QString &icon, JabberClient *client, const QString &jid, const QString &node, const QString &type); + JabberSearch *m_search; + QLabel *m_result; + void initTitle(); +protected slots: + void setNext(); + void search(); + void textChanged(const QString&); + void slotSelected(const QString&); +protected: + virtual bool processEvent(SIM::Event *e); + virtual void layOutButtonRow(QHBoxLayout *layout); + virtual void layOutTitleRow(QHBoxLayout *layout, const QString &title); + QString m_type; + QString m_id; +}; + +class JabberBrowser : public QMainWindow, public SIM::EventReceiver +{ + Q_OBJECT +public: + JabberBrowser(); + ~JabberBrowser(); + void goUrl(const QString &url, const QString &node); + void save(); + void setClient(JabberClient *client); + DiscoInfo *m_info; + ListView *m_list; +signals: + void enableOptions(bool); + void addSearch(QWidget*, SIM::Client*, const QString&); +protected slots: + void selectionChanged(); + void currentChanged(ListViewItem*); + void dragStart(); + void showReg(); + void showConfig(); + void search(); + void textChanged(const QString&); + void configFinished(); + void regFinished(); +protected: + virtual bool processEvent(SIM::Event *e); + void setNavigation(); + void stop(const QString &err); + void go(const QString &url, const QString &node); + void addHistory(const QString &str); + bool haveFeature(const char*); + bool haveFeature(const char*, const QString&); + ListViewItem *findItem(unsigned col, const QString &id); + ListViewItem *findItem(unsigned col, const QString &id, ListViewItem *item); + void setItemPict(ListViewItem *item); + void adjustColumn(ListViewItem *item); + void loadItem(ListViewItem *item); + void checkDone(); + bool checkDone(ListViewItem*); + void startProcess(); + void changeMode(); + void changeMode(ListViewItem *item); + void showEvent(QShowEvent*); + bool m_bInProcess; + JabberClient *m_client; + CToolBar *m_bar; + std::vector m_history; + std::vector m_nodes; + QString m_historyStr; + int m_historyPos; + JabberWizard *m_reg; + JabberWizard *m_config; + JIDSearch *m_search; + QString m_search_id; + QString m_reg_id; + QString m_config_id; + bool m_bError; + friend class DiscoInfo; +}; + +#endif + diff --git a/plugins/jabber/jabberbuffer.cpp b/plugins/jabber/jabberbuffer.cpp new file mode 100644 index 0000000..056ca76 --- /dev/null +++ b/plugins/jabber/jabberbuffer.cpp @@ -0,0 +1,52 @@ +/*************************************************************************** + jabberbuffer.h - description + ------------------- + begin : Mon Jan 08 2006 + copyright : (C) 2007 by Christian Ehrlicher + email : ch.ehrlicher@gmx.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "jabberbuffer.h" + +#include + +using namespace SIM; + +JabberBuffer::JabberBuffer(unsigned size) + : Buffer(size) +{} + +JabberBuffer::JabberBuffer(const QByteArray &ba) + : Buffer(ba) +{} + +JabberBuffer::~JabberBuffer() +{} + +JabberBuffer &JabberBuffer::operator << (const QString &s) +{ + QByteArray utf8 = s.toUtf8(); + Buffer::pack(utf8.data(), utf8.length()); + return *this; +} + +JabberBuffer &JabberBuffer::operator << (const QByteArray &s) +{ + Buffer::pack(s.data(), s.length()); + return *this; +} + +JabberBuffer &JabberBuffer::operator << (const char *s) +{ + Buffer::pack(s, strlen(s)); + return *this; +} diff --git a/plugins/jabber/jabberbuffer.h b/plugins/jabber/jabberbuffer.h new file mode 100644 index 0000000..ca24655 --- /dev/null +++ b/plugins/jabber/jabberbuffer.h @@ -0,0 +1,51 @@ +/*************************************************************************** + jabberbuffer.h - description + ------------------- + begin : Mon Jan 08 2006 + copyright : (C) 2007 by Christian Ehrlicher + email : ch.ehrlicher@gmx.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +#ifndef _JABBERBUFFER_H +#define _JABBERBUFFER_H + +#include "buffer.h" +#include "socket/socket.h" +#include "socket/clientsocket.h" +#include + +class JabberBuffer : public Buffer +{ +public: + JabberBuffer(unsigned size = 0); + JabberBuffer(const QByteArray &ba); + virtual ~JabberBuffer(); + + JabberBuffer &operator << (const QString &s); + JabberBuffer &operator << (const QByteArray &s); + JabberBuffer &operator << (const char *s); // interpreted as utf-8 +}; + +class JabberClientSocket : public SIM::ClientSocket +{ +public: + JabberClientSocket(SIM::ClientSocketNotify *notify, SIM::Socket *sock = NULL) + : ClientSocket(notify, sock) {}; + ~JabberClientSocket() {}; + + virtual JabberBuffer &readBuffer() { return m_readJabberBuffer; } + virtual JabberBuffer &writeBuffer() { return m_writeJabberBuffer; } +protected: + JabberBuffer m_readJabberBuffer; + JabberBuffer m_writeJabberBuffer; +}; + +#endif // _JABBERBUFFER_H diff --git a/plugins/jabber/jabberclient.cpp b/plugins/jabber/jabberclient.cpp new file mode 100644 index 0000000..17e6d1b --- /dev/null +++ b/plugins/jabber/jabberclient.cpp @@ -0,0 +1,2816 @@ +/*************************************************************************** + jabberclient.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "simapi.h" + +#ifndef WIN32 +#include +#endif + +#include + +#include "html.h" +#include "icons.h" +#include "log.h" +#include "unquot.h" +#include "core.h" +#include "core_events.h" +#include "contacts/clientdataiterator.h" +#include "contacts/contact.h" +#include "contacts/group.h" + +#include "jabberclient.h" +#include "jabber.h" +#include "jabberconfig.h" +#include "jabber_ssl.h" +#include "jabberadd.h" +#include "jabberinfo.h" +#include "jabberhomeinfo.h" +#include "jabberworkinfo.h" +#include "jabberaboutinfo.h" +#include "jabberpicture.h" +#include "jabbermessage.h" +#include "jabberbrowser.h" +#include "infoproxy.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace SIM; + +#ifndef XML_STATUS_OK +#define XML_STATUS_OK 1 +#define XML_STATUS_ERROR 0 +#endif + +unsigned PING_TIMEOUT = 50; + +DataDef jabberUserData[] = + { + { "", DATA_ULONG, 1, DATA(2) }, // Sign + { "LastSend", DATA_ULONG, 1, 0 }, + { "ID", DATA_UTF, 1, 0 }, + { "Node", DATA_UTF, 1, 0 }, + { "Resource", DATA_UTF, 1, 0 }, + { "Name", DATA_UTF, 1, 0 }, + { "", DATA_ULONG, 1, DATA(1) }, // Status + { "FirstName", DATA_UTF, 1, 0 }, + { "Nick", DATA_UTF, 1, 0 }, + { "Desc", DATA_UTF, 1, 0 }, + { "BirthDay", DATA_UTF, 1, 0 }, + { "Url", DATA_UTF, 1, 0 }, + { "OrgName", DATA_UTF, 1, 0 }, + { "OrgUnit", DATA_UTF, 1, 0 }, + { "Role", DATA_UTF, 1, 0 }, + { "Title", DATA_UTF, 1, 0 }, + { "Street", DATA_UTF, 1, 0 }, + { "ExtAddr", DATA_UTF, 1, 0 }, + { "City", DATA_UTF, 1, 0 }, + { "Region", DATA_UTF, 1, 0 }, + { "PCode", DATA_UTF, 1, 0 }, + { "Country", DATA_UTF, 1, 0 }, + { "EMail", DATA_UTF, 1, 0 }, + { "Phone", DATA_UTF, 1, 0 }, + { "StatusTime", DATA_ULONG, 1, 0 }, + { "OnlineTime", DATA_ULONG, 1, 0 }, + { "Subscribe", DATA_ULONG, 1, 0 }, + { "Group", DATA_UTF, 1, 0 }, + { "", DATA_BOOL, 1, 0 }, // bChecked + { "", DATA_STRING, 1, 0 }, // TypingId + { "", DATA_BOOL, 1, 0 }, // SendTypingEvents + { "", DATA_BOOL, 1, 0 }, // IsTyping + { "", DATA_ULONG, 1, 0 }, // ComposeId + { "", DATA_BOOL, 1, DATA(1) }, // richText + { "", DATA_BOOL, 1, 0 }, + { "PhotoWidth", DATA_LONG, 1, 0 }, + { "PhotoHeight", DATA_LONG, 1, 0 }, + { "LogoWidth", DATA_LONG, 1, 0 }, + { "LogoHeight", DATA_LONG, 1, 0 }, + { "", DATA_ULONG, 1, 0 }, // nResources + { "", DATA_STRLIST, 1, 0 }, // Resources + { "", DATA_STRLIST, 1, 0 }, // ResourceStatus + { "", DATA_STRLIST, 1, 0 }, // ResourceReply + { "", DATA_STRLIST, 1, 0 }, // ResourceStatusTime + { "", DATA_STRLIST, 1, 0 }, // ResourceOnlineTime + { "AutoReply", DATA_UTF, 1, 0 }, + { "", DATA_STRLIST, 1, 0 }, // ResourceClientName + { "", DATA_STRLIST, 1, 0 }, // ResourceClientVersion + { "", DATA_STRLIST, 1, 0 }, // ResourceClientOS + { NULL, DATA_UNKNOWN, 0, 0 } + }; + +static DataDef jabberClientData[] = + { + { "Server", DATA_STRING, 1, "jabber.org" }, + { "Port", DATA_ULONG, 1, DATA(5222) }, + { "UseSSL", DATA_BOOL, 1, 0 }, + { "UsePlain", DATA_BOOL, 1, 0 }, + { "UseVHost", DATA_BOOL, 1, 0 }, + { "", DATA_BOOL, 1, 0 }, + { "Priority", DATA_ULONG, 1, DATA(5) }, + { "ListRequest", DATA_UTF, 1, 0 }, + { "VHost", DATA_UTF, 1, 0 }, + { "Typing", DATA_BOOL, 1, DATA(1) }, + { "RichText", DATA_BOOL, 1, DATA(1) }, + { "UseVersion", DATA_BOOL, 1, DATA(1) }, + { "ProtocolIcons", DATA_BOOL, 1, DATA(1) }, + { "MinPort", DATA_ULONG, 1, DATA(1024) }, + { "MaxPort", DATA_ULONG, 1, DATA(0xFFFF) }, + { "Photo", DATA_UTF, 1, 0 }, + { "Logo", DATA_UTF, 1, 0 }, + { "AutoSubscribe", DATA_BOOL, 1, DATA(1) }, + { "AutoAccept", DATA_BOOL, 1, DATA(1) }, + { "UseHTTP", DATA_BOOL, 1, 0 }, + { "URL", DATA_STRING, 1, 0 }, + { "InfoUpdated", DATA_BOOL, 1, 0 }, + { "", DATA_STRUCT, sizeof(JabberUserData) / sizeof(Data), DATA(jabberUserData) }, + { NULL, DATA_UNKNOWN, 0, 0 } + }; + +JabberClient::JabberClient(JabberProtocol *protocol, Buffer *cfg) : TCPClient(protocol, cfg) +{ + load_data(jabberClientData, &data, cfg); + QString jid = data.owner.ID.str(); + //log(L_DEBUG, "JID: %s", jid.toUtf8().data()); + + //For old configs, where server part in own jid is missing + if (!jid.isEmpty() && jid.indexOf('@')==-1) + { + jid += '@'; + if (getUseVHost()) + { + jid += getVHost(); + } + else + { + jid += getServer(); + } + data.owner.ID.str()=jid; + } + if (data.owner.Resource.str().isEmpty()) + { + QString resource = PACKAGE; + data.owner.Resource.str() = resource.simplified(); + } + + TCPClient::changeStatus(this->protocol()->status("offline")); + + QString listRequests = getListRequest(); + while (!listRequests.isEmpty()){ + QString item = getToken(listRequests, ';', false); + JabberListRequest lr; + lr.bDelete = false; + lr.jid = getToken(item, ','); + lr.grp = getToken(item, ','); + if (!item.isEmpty()) + lr.bDelete = true; + m_listRequests.push_back(lr); + } + setListRequest(QString::null); + + m_bSSL = false; + m_curRequest = NULL; + m_msg_id = 0; + m_bJoin = false; + init(); +} + +JabberClient::~JabberClient() +{ + TCPClient::changeStatus(this->protocol()->status("offline")); + //TCPClient::setStatus(STATUS_OFFLINE, false); + free_data(jabberClientData, &data); + freeData(); +} + +const DataDef *JabberProtocol::userDataDef() +{ + return jabberUserData; +} + +bool JabberClient::compareData(void *d1, void *d2) +{ + JabberUserData *data1 = toJabberUserData((SIM::clientData*)d1); // FIXME unsafe type conversion + JabberUserData *data2 = toJabberUserData((SIM::clientData*)d2); // FIXME unsafe type conversion + return (data1->ID.str().toLower() == data2->ID.str().toLower()); +} + +void JabberClient::setID(const QString &id) +{ + data.owner.ID.str() = id; +} + +QByteArray JabberClient::getConfig() +{ + QString lr; + for (list::iterator it = m_listRequests.begin(); it != m_listRequests.end(); ++it){ + if (!lr.isEmpty()) + lr += ';'; + lr += quoteChars(it->jid, ",;"); + lr += ','; + lr += quoteChars(it->grp, ",;"); + if (it->bDelete) + lr += ",1"; + } + setListRequest(lr); + QByteArray res = Client::getConfig(); + if (res.length()) + res += '\n'; + return res += save_data(jabberClientData, &data); +} + +QString JabberClient::name() +{ + QString res = "Jabber."; + res += data.owner.ID.str(); + return res; +} + +QWidget *JabberClient::setupWnd() +{ + return new JabberConfig(NULL, this, false); +} + +bool JabberClient::isMyData(clientData *&_data, Contact *&contact) +{ + if (_data->Sign.toULong() != JABBER_SIGN) + return false; + QString resource; + JabberUserData *data = toJabberUserData(_data); + JabberUserData *my_data = findContact(data->ID.str(), QString::null, false, contact, resource); + if (my_data){ + data = my_data; + }else{ + contact = NULL; + } + return true; +} + +bool JabberClient::createData(clientData *&_data, Contact *contact) +{ + JabberUserData *data = toJabberUserData(_data); + JabberUserData *new_data = toJabberUserData((SIM::clientData*)contact->clientData.createData(this)); // FIXME unsafe type conversion + new_data->ID.str() = data->ID.str(); + _data = (clientData*)new_data; + return true; +} + +void JabberClient::connect_ready() +{ + if (!getUseSSL() || m_bSSL){ + connected(); + return; + } + m_bSSL = true; + // FIXME HACKHACKHACK!!!11 alarm + SSLClient *ssl = new JabberSSL(socket()->socket(), (bool)!(getServer().compare("talk.google.com"))); + socket()->setSocket(ssl); + ssl->startEncryption(); +} + +void JabberClient::connected() +{ + socket()->readBuffer().init(0); + socket()->readBuffer().packetStart(); + socket()->setRaw(true); + log(L_DEBUG, "Connect ready"); + startHandshake(); + TCPClient::connect_ready(); + reset(); +} + +void JabberClient::packet_ready() +{ + if (socket()->readBuffer().writePos() == 0) + return; + JabberPlugin *plugin = static_cast(protocol()->plugin()); + EventLog::log_packet(socket()->readBuffer(), false, plugin->JabberPacket); + //log(L_DEBUG, "JABBER PACKET: %s\n", socket()->readBuffer().data()); + if (!parse(socket()->readBuffer(), true)) + socket()->error_state("XML parse error"); + socket()->readBuffer().init(0); + socket()->readBuffer().packetStart(); +} + +bool JabberClient::processEvent(Event *e) +{ + TCPClient::processEvent(e); + switch (e->type()) { + case eEventAddContact: { + EventAddContact *ec = static_cast(e); + EventAddContact::AddContact *ac = ec->addContact(); + if (!ac->proto.isEmpty() && (protocol()->description()->text == ac->proto)){ + Contact *contact = NULL; + QString resource; + findContact(ac->addr, ac->nick, true, contact, resource); + if (contact && contact->getGroup() != (int)ac->group){ + contact->setGroup(ac->group); + EventContact e(contact, EventContact::eChanged); + e.process(); + } + ec->setContact(contact); + return true; + } + break; + } + case eEventDeleteContact: { + EventDeleteContact *ec = static_cast(e); + QString addr = ec->alias(); + ContactList::ContactIterator it; + Contact *contact; + while ((contact = ++it) != NULL){ + JabberUserData *data; + ClientDataIterator itc(contact->clientData, this); + while ((data = toJabberUserData(++itc)) != NULL){ + if (data->ID.str() == addr){ + contact->clientData.freeData(data); + ClientDataIterator itc(contact->clientData); + if (++itc == NULL) + delete contact; + return true; + } + } + } + break; + } + case eEventGoURL: { + EventGoURL *u = static_cast(e); + QString url = u->url(); + QString proto; + int n = url.indexOf(':'); + if (n < 0) + return false; + proto = url.left(n); + if (proto != "jabber") + return false; + url = url.mid(n + 1); + while (url.startsWith("/")) + url = url.mid(1); + QString s = unquoteString(url); + QString jid = getToken(s, '/'); + if (!jid.isEmpty()){ + Contact *contact; + QString resource; + findContact(jid, s, true, contact, resource); + Command cmd; + cmd->id = MessageGeneric; + cmd->menu_id = MenuMessage; + cmd->param = (void*)(contact->id()); + EventCommandExec(cmd).process(); + return true; + } + break; + } + case eEventTemplateExpanded: { + EventTemplate *et = static_cast(e); + EventTemplate::TemplateExpand *t = et->templateExpand(); + setStatus((unsigned long)(t->param), quoteString(t->tmpl, quoteNOBR, false)); + break; + } + case eEventContact: { + EventContact *ec = static_cast(e); + Contact *contact = ec->contact(); + switch(ec->action()) { + case EventContact::eDeleted: { + ClientDataIterator it(contact->clientData, this); + JabberUserData *data; + while ((data = toJabberUserData(++it)) != NULL){ + listRequest(data, QString::null, QString::null, true); + } + break; + } + case EventContact::eChanged: { + QString grpName; + QString name; + name = contact->getName(); + Group *grp = NULL; + if (contact->getGroup()) + grp = getContacts()->group(contact->getGroup()); + if (grp) + grpName = grp->getName(); + ClientDataIterator it(contact->clientData, this); + JabberUserData *data; + while ((data = toJabberUserData(++it)) != NULL){ + if (grpName == data->Group.str()){ + listRequest(data, name, grpName, false); + continue; + } + if (!data->Name.str().isEmpty()){ + if (name == data->Name.str()) + listRequest(data, name, grpName, false); + continue; + } + if (name == data->ID.str()) + listRequest(data, name, grpName, false); + } + break; + } + default: + break; + } + break; + } + case eEventGroup: { + EventGroup *ev = static_cast(e); + if (ev->action() != EventGroup::eChanged) + return false; + Group *grp = ev->group(); + QString grpName = grp->getName(); + ContactList::ContactIterator itc; + Contact *contact; + while ((contact = ++itc) != NULL){ + if (contact->getGroup() != (int)grp->id()) + continue; + ClientDataIterator it(contact->clientData, this); + JabberUserData *data; + while ((data = toJabberUserData(++it)) != NULL){ + if (grpName == data->Group.str()) + listRequest(data, contact->getName(), grpName, false); + } + } + break; + } + case eEventMessageCancel: { + EventMessage *em = static_cast(e); + Message *msg = em->msg(); + for (list::iterator it = m_waitMsg.begin(); it != m_waitMsg.end(); ++it){ + if ((*it) == msg){ + m_waitMsg.erase(it); + delete msg; + return true; + } + } + break; + } + case eEventMessageAccept: { + EventMessageAccept *ema = static_cast(e); + for (list::iterator it = m_ackMsg.begin(); it != m_ackMsg.end(); ++it){ + if ((*it)->id() == ema->msg()->id()){ + JabberFileMessage *msg = static_cast(*it); + m_ackMsg.erase(it); + Contact *contact; + QString resource; + JabberUserData *data = findContact(msg->getFrom(), QString::null, false, contact, resource); + if (data){ + JabberFileTransfer *ft = new JabberFileTransfer(static_cast(msg), data, this); + ft->setDir(ema->dir()); + ft->setOverwrite(ema->mode()); + EventMessageAcked(msg).process(); + ft->connect(); + } + EventMessageDeleted(msg).process(); + if (data == NULL) + delete msg; + return true; + } + } + break; + } + case eEventMessageDecline: { + EventMessageDecline *emd = static_cast(e); + for (list::iterator it = m_ackMsg.begin(); it != m_ackMsg.end(); ++it){ + if ((*it)->id() == emd->msg()->id()){ + JabberFileMessage *msg = static_cast(*it); + m_ackMsg.erase(it); + QString reason = emd->reason(); + if (reason.isEmpty()) + reason = i18n("File transfer declined"); + ServerRequest req(this, "error", NULL, msg->getFrom(), msg->getID()); + req.start_element("error"); + req.add_attribute("code", "403"); + req.add_text(reason); + req.send(); + EventMessageDeleted(msg).process(); + delete msg; + return true; + } + } + break; + } + case eEventClientVersion: { + EventClientVersion *ecv = static_cast(e); + ClientVersionInfo* info = ecv->info(); + if (!info->jid.isEmpty()){ + Contact *contact; + QString resource; + JabberUserData* data = findContact(info->jid, QString::null, false, contact, resource); + if (!data) + return false; + unsigned i; + for (i = 1; i <= data->nResources.toULong(); i++){ + if (resource == get_str(data->Resources, i)) + break; + } + if (i <= data->nResources.toULong()){ + set_str(&data->ResourceClientName, i, info->name); + set_str(&data->ResourceClientVersion, i, info->version); + set_str(&data->ResourceClientOS, i, info->os); + } + } + break; + } + default: + break; + } + return false; +} + +void JabberClient::changeStatus(const SIM::IMStatusPtr& status) +{ + QDateTime now = QDateTime::currentDateTime(); + data.owner.StatusTime.asULong() = now.toTime_t(); + if (currentStatus()->id() == "offline") + data.owner.OnlineTime.asULong() = now.toTime_t(); + TCPClient::changeStatus(status); + QSharedPointer jabberstatus = status.dynamicCast(); + socket()->writeBuffer().packetStart(); + QString priority = QString::number(getPriority()); + QString show = jabberstatus->show(); + QString type = jabberstatus->type(); + + if (getInvisible()) { + type = "invisible"; + } + socket()->writeBuffer() << "writeBuffer() << " type=\'" << type << "\'"; + socket()->writeBuffer() << ">\n"; + if (!show.isEmpty()) + socket()->writeBuffer() << "" << show << "\n"; + if (!status->text().isEmpty()) + socket()->writeBuffer() << "" << status->text() << "\n"; + if (!priority.isEmpty()) + socket()->writeBuffer() << "" << priority << "\n"; + socket()->writeBuffer() << ""; + sendPacket(); + EventClientChanged(this).process(); + if (status->id() == "offline") { + if (socket()){ + socket()->writeBuffer().packetStart(); + socket()->writeBuffer() + << "\n"; + sendPacket(); + } + // TODO + /* + Contact *contact; + ContactList::ContactIterator it; + QDateTime now(QDateTime::currentDateTime()); + data.owner.StatusTime.asULong() = now.toTime_t(); + while ((contact = ++it) != NULL) { + JabberUserData *data; + ClientDataIterator it(contact->clientData, this); + while ((data = toJabberUserData(++it)) != NULL){ + if (data->Status.toULong() == STATUS_OFFLINE) + continue; + data->StatusTime.asULong() = now.toTime_t(); + setOffline(data); + StatusMessage *m = new StatusMessage(); + m->setContact(contact->id()); + m->setClient(dataName(data)); + m->setFlags(MESSAGE_RECEIVED); + m->setStatus(STATUS_OFFLINE); + EventMessageReceived e(m); + if(!e.process()) + delete m; + } + } + */ + } +} + +void JabberClient::setStatus(unsigned status) +{ + if (getInvisible() && (status != STATUS_OFFLINE)) + { + if (m_status != status) + { + m_status = status; + EventClientChanged(this).process(); + } + return; + } + ARRequest ar; + ar.contact = NULL; + ar.status = status; + ar.receiver = this; + ar.param = (void*)(long)status; + EventARRequest(&ar).process(); +} + +void JabberClient::setStatus(unsigned status, const QString &ar) +{ + if (status != m_status) { + QDateTime now = QDateTime::currentDateTime(); + data.owner.StatusTime.asULong() = now.toTime_t(); + if (m_status == STATUS_OFFLINE) + data.owner.OnlineTime.asULong() = now.toTime_t(); + m_status = status; + socket()->writeBuffer().packetStart(); + QString priority = QString::number(getPriority()); + const char *show = NULL; + const char *type = NULL; + if (getInvisible()){ + type = "invisible"; + }else{ + switch (status){ + case STATUS_AWAY: + show = "away"; + break; + case STATUS_NA: + show = "xa"; + break; + case STATUS_DND: + show = "dnd"; + break; + case STATUS_OCCUPIED: + show = "occupied"; + break; + case STATUS_FFC: + show = "chat"; + break; + case STATUS_OFFLINE: + priority = QString::null; + type = "unavailable"; + break; + } + } + socket()->writeBuffer() << "writeBuffer() << " type=\'" << type << "\'"; + socket()->writeBuffer() << ">\n"; + if (show) + socket()->writeBuffer() << "" << show << "\n"; + if (!ar.isEmpty()) + socket()->writeBuffer() << "" << ar << "\n"; + if (!priority.isEmpty()) + socket()->writeBuffer() << "" << priority << "\n"; + socket()->writeBuffer() << ""; + sendPacket(); + EventClientChanged(this).process(); + } + if (status == STATUS_OFFLINE){ + if (socket()){ + socket()->writeBuffer().packetStart(); + socket()->writeBuffer() + << "\n"; + sendPacket(); + } + Contact *contact; + ContactList::ContactIterator it; + QDateTime now(QDateTime::currentDateTime()); + data.owner.StatusTime.asULong() = now.toTime_t(); + while ((contact = ++it) != NULL){ + JabberUserData *data; + ClientDataIterator it(contact->clientData, this); + while ((data = toJabberUserData(++it)) != NULL){ + if (data->Status.toULong() == STATUS_OFFLINE) + continue; + data->StatusTime.asULong() = now.toTime_t(); + setOffline(data); + StatusMessage *m = new StatusMessage(); + m->setContact(contact->id()); + m->setClient(dataName(data)); + m->setFlags(MESSAGE_RECEIVED); + m->setStatus(STATUS_OFFLINE); + EventMessageReceived e(m); + if(!e.process()) + delete m; + } + } + } +} + +void JabberClient::disconnected() +{ + for (list::iterator it = m_requests.begin(); it != m_requests.end(); ++it) + delete *it; + m_requests.clear(); + if (m_curRequest){ + delete m_curRequest; + m_curRequest = NULL; + } + list::iterator itm; + for (itm = m_ackMsg.begin(); itm != m_ackMsg.end(); ++itm){ + Message *msg = *itm; + EventMessageDeleted(msg).process(); + delete msg; + } + for (itm = m_waitMsg.begin(); itm != m_waitMsg.end(); itm = m_waitMsg.begin()){ + Message *msg = *itm; + msg->setError(I18N_NOOP("Client go offline")); + EventMessageSent(msg).process(); + delete msg; + } + m_ackMsg.clear(); + init(); +} + +void JabberClient::init() +{ + m_id = QString::null; + m_depth = 0; + m_id_seed = 0xAAAA; + m_bSSL = false; +} + +void JabberClient::sendPacket() +{ + JabberPlugin *plugin = static_cast(protocol()->plugin()); + EventLog::log_packet(socket()->writeBuffer(), true, plugin->JabberPacket); + socket()->write(); +} + +void JabberClient::element_start(const QString& el, const QXmlAttributes& attrs) +{ + QString element = el.toLower(); + QString id; + if (m_depth) + { + if (m_curRequest) + { + m_curRequest->element_start(element, attrs); + } + else + { + if (element == "iq") + { + QString id = attrs.value("id"); + QString type = attrs.value("type"); + //log(L_DEBUG, "IQ: type = %s", type.toUtf8().data()); + if(id.isEmpty() || type == "set" || type == "get") + { + m_curRequest = new IqRequest(this); + m_curRequest->element_start(element, attrs); + } + else + { + list::iterator it; + for (it = m_requests.begin(); it != m_requests.end(); ++it) + { + if ((*it)->m_id == id) + break; + } + if (it != m_requests.end()) + { + m_curRequest = *it; + m_requests.erase(it); + m_curRequest->element_start(element, attrs); + } + else + { + log(L_WARN, "Packet %s not found", id.toLatin1().data()); + } + } + } + else if (element == "presence") + { + m_curRequest = new PresenceRequest(this); + m_curRequest->element_start(element, attrs); + } + else if (element == "message") + { + m_curRequest = new MessageRequest(this); + m_curRequest->element_start(element, attrs); + } + else if (element == "stream:error") + { + m_curRequest = new StreamErrorRequest(this); + m_curRequest->element_start(element, attrs); + } + else if (element != "a") + { + log(L_DEBUG, "Bad tag %s", qPrintable(element)); + } + } + }else{ + if (element == "stream:stream"){ + id = attrs.value("id"); + } + log(L_DEBUG, "Handshake %s (%s)", qPrintable(id), qPrintable(element)); + handshake(id); + } + m_depth++; +} + +void JabberClient::element_end(const QString& el) +{ + m_depth--; + if (m_curRequest){ + QString element = el.toLower(); + m_curRequest->element_end(element); + if (m_depth == 1){ + delete m_curRequest; + m_curRequest = NULL; + } + } +} + +void JabberClient::char_data(const QString& str) +{ + if (m_curRequest) + m_curRequest->char_data(str); +} + +QString JabberClient::get_unique_id() +{ + QString s("a"); + s += QString::number(m_id_seed,16); + m_id_seed += 0x10; + return s; +} + +JabberClient::ServerRequest::ServerRequest(JabberClient *client, const char *type, + const QString &from, const QString &to, const QString &id) +{ + m_client = client; + if (type == NULL) + return; + m_id = id.isEmpty() ? m_client->get_unique_id() : id; + + if (m_client->socket() == NULL) + return; + m_client->socket()->writeBuffer().packetStart(); + m_client->socket()->writeBuffer() << "socket()->writeBuffer() <<" id=\'" << encodeXMLattr(m_id) << "\'"; + + if (!from.isEmpty()) + m_client->socket()->writeBuffer() << " from=\'" << encodeXMLattr(from) << "\'"; + if (!to.isEmpty()) + m_client->socket()->writeBuffer() << " to=\'" << encodeXMLattr(to) << "\'"; + m_client->socket()->writeBuffer() << ">\n"; +} + +JabberClient::ServerRequest::~ServerRequest() +{ +} + +void JabberClient::ServerRequest::send() +{ + end_element(false); + while (!m_els.isEmpty()){ + end_element(false); + } + m_client->socket()->writeBuffer() + << "\n"; + m_client->sendPacket(); +} + +void JabberClient::ServerRequest::element_start(const QString&, const QXmlAttributes&) +{ +} + +void JabberClient::ServerRequest::element_end(const QString&) +{ +} + +void JabberClient::ServerRequest::char_data(const QString&) +{ +} + +void JabberClient::ServerRequest::start_element(const QString &name) +{ + end_element(true); + m_client->socket()->writeBuffer() << "<" << name; + m_element = name; +} + +void JabberClient::ServerRequest::add_attribute(const QString &name, const QString &value) +{ + if(value.isEmpty()) + return; + m_client->socket()->writeBuffer() + << " " << name + << "=\'" << JabberClient::encodeXMLattr(value) << "\'"; +} + +void JabberClient::ServerRequest::add_attribute(const QString &name, const char *value) +{ + if(value) + add_attribute(name, QString::fromUtf8(value)); +} + +void JabberClient::ServerRequest::end_element(bool bNewLevel) +{ + if (bNewLevel){ + if (m_element.length()){ + m_client->socket()->writeBuffer() << ">\n"; + m_els.push(m_element); + } + }else{ + if (m_element.length()){ + m_client->socket()->writeBuffer() << "/>\n"; + }else if (m_els.count()){ + m_element = m_els.top(); + m_els.pop(); + m_client->socket()->writeBuffer() << "\n"; + } + } + m_element = QString::null; +} + +void JabberClient::ServerRequest::add_text(const QString &value) +{ + if (m_element.length()){ + m_client->socket()->writeBuffer() << ">"; + m_els.push(m_element); + m_element = QString::null; + } + m_client->socket()->writeBuffer() << JabberClient::encodeXML(value); +} + +void JabberClient::ServerRequest::text_tag(const QString &name, const QString &value) +{ + if (value.isEmpty()) + return; + end_element(true); + m_client->socket()->writeBuffer() + << "<" << name << ">" + << JabberClient::encodeXML(value) + << "\n"; +} + +void JabberClient::ServerRequest::add_condition(const QString &condition, bool bXData) +{ + QString cond = condition; + while (cond.length()){ + QString item = getToken(cond, ';'); + if (item == "x:data"){ + bXData = true; + start_element("x"); + add_attribute("xmlns", "jabber:x:data"); + add_attribute("type", "submit"); + } + QString key = getToken(item, '='); + if (bXData){ + start_element("field"); + add_attribute("var", key); + text_tag("value", item); + end_element(); + }else{ + text_tag(key, item); + } + } +} + +const char *JabberClient::ServerRequest::_GET = "get"; +const char *JabberClient::ServerRequest::_SET = "set"; +const char *JabberClient::ServerRequest::_RESULT = "result"; + +void JabberClient::startHandshake() +{ + socket()->writeBuffer().packetStart(); + socket()->writeBuffer() + << "\n" + << "\n"; + sendPacket(); +} + +void JabberClient::handshake(const QString &id) +{ + if (id.isEmpty()){ + socket()->error_state("Bad session ID"); + return; + } + m_id = id; + if (getRegister()){ + auth_register(); + }else{ + if (getUsePlain()){ + auth_plain(); + }else{ + auth_digest(); + } + } +} + +void JabberClient::auth_ok() +{ + if (getRegister()){ + setRegister(false); + setClientStatus(STATUS_OFFLINE); + TCPClient::setStatus(getManualStatus(), getCommonStatus()); + return; + } + setState(Connected); + setPreviousPassword(QString::null); + rosters_request(); + if (getInfoUpdated()){ + setClientInfo(&data.owner); + }else{ + info_request(NULL, false); + } + setStatus(m_logonStatus); + QTimer::singleShot(PING_TIMEOUT * 1000, this, SLOT(ping())); +} + +void JabberClient::auth_failed() +{ + m_reconnect = NO_RECONNECT; + socket()->error_state(I18N_NOOP("Login failed"), AuthError); +} + +QString JabberClient::encodeXML(const QString &str) +{ + return quoteString(str, quoteNOBR, false); +} +QString JabberClient::encodeXMLattr(const QString &str) +{ + return quoteString(str, quoteXMLattr, false); +} + +JabberUserData *JabberClient::findContact(const QString &_jid, const QString &name, bool bCreate, Contact *&contact, QString &resource, bool bJoin) +{ + resource = QString::null; + QString jid = _jid; + int n = jid.indexOf('/'); + if (n >= 0){ + resource = jid.mid(n + 1); + jid = jid.left(n); + } + ContactList::ContactIterator it; + while ((contact = ++it) != NULL){ + JabberUserData *data; + ClientDataIterator it(contact->clientData, this); + while ((data = toJabberUserData(++it)) != NULL){ + if (jid.toUpper() != data->ID.str().toUpper()) + continue; + if (!resource.isEmpty()) + data->Resource.str() = resource; + if (!name.isEmpty()) + data->Name.str() = name; + return data; + } + } + if (!bCreate) + return NULL; + it.reset(); + QString sname; + if (!name.isEmpty()){ + sname = name; + }else{ + sname = jid; + int pos = sname.indexOf('@'); + if (pos > 0) + sname = sname.left(pos); + } + if (bJoin){ + while ((contact = ++it) != NULL){ + if (contact->getName().toLower() == sname.toLower()){ + JabberUserData *data = toJabberUserData((SIM::clientData*) contact->clientData.createData(this)); // FIXME unsafe type conversion + data->ID.str() = jid; + if (!resource.isEmpty()) + data->Resource.str() = resource; + if (!name.isEmpty()) + data->Name.str() = name; + info_request(data, false); + EventContact e(contact, EventContact::eChanged); + e.process(); + m_bJoin = true; + return data; + } + } + } + contact = getContacts()->contact(0, true); + JabberUserData *data = toJabberUserData((SIM::clientData*) contact->clientData.createData(this)); // FIXME unsafe type conversion + data->ID.str() = jid; + if (!resource.isEmpty()) + data->Resource.str() = resource; + if (!name.isEmpty()) + data->Name.str() = name; + contact->setName(sname); + info_request(data, false); + EventContact e(contact, EventContact::eChanged); + e.process(); + return data; +} + +static void addIcon(QSet *s, const QString &icon, const QString &statusIcon) +{ + if (!s || statusIcon == icon) + return; + s->insert(icon); +} + +QString JabberClient::get_icon(JabberUserData *data, unsigned status, bool invisible) +{ + const CommandDef *def = protocol()->statusList(); + for (; !def->text.isNull(); def++){ + if (def->id == status) + break; + } + if ((def == NULL) || (def->text.isNull())) + return "Jabber_offline"; + QString dicon = def->icon; + if (invisible) + dicon = "Jabber_invisible"; + if (getProtocolIcons()){ + QString id = data->ID.str(); + int host = id.indexOf( '@' ); + + QString h; + if (host != -1) + h = id.mid(host + 1); + else + h = id; + + int p = h.indexOf( '.' ); + if (p) + h = h.left( p ); + if (h == "icq"){ + if (invisible){ + dicon = "ICQ_invisible"; + }else{ + switch (status){ + case STATUS_ONLINE: + dicon = "ICQ_online"; + break; + case STATUS_OFFLINE: + dicon = "ICQ_offline"; + break; + case STATUS_AWAY: + dicon = "ICQ_away"; + break; + case STATUS_NA: + dicon = "ICQ_na"; + break; + case STATUS_DND: + dicon = "ICQ_dnd"; + break; + case STATUS_OCCUPIED: + dicon = "ICQ_occupied"; + break; + case STATUS_FFC: + dicon = "ICQ_ffc"; + break; + } + } + }else if (h == "aim"){ + switch (status){ + case STATUS_ONLINE: + dicon = "AIM_online"; + break; + case STATUS_OFFLINE: + dicon = "AIM_offline"; + break; + case STATUS_AWAY: + dicon = "AIM_away"; + break; + } + }else if (h == "msn"){ + if (invisible){ + dicon = "MSN_invisible"; + }else{ + switch (status){ + case STATUS_ONLINE: + dicon = "MSN_online"; + break; + case STATUS_OFFLINE: + dicon = "MSN_offline"; + break; + case STATUS_AWAY: + dicon = "MSN_away"; + break; + case STATUS_NA: + dicon = "MSN_na"; + break; + case STATUS_DND: + dicon = "MSN_dnd"; + break; + case STATUS_OCCUPIED: + dicon = "MSN_occupied"; + break; + } + } + }else if (h == "yahoo"){ + switch (status){ + case STATUS_ONLINE: + dicon = "Yahoo!_online"; + break; + case STATUS_OFFLINE: + dicon = "Yahoo!_offline"; + break; + case STATUS_AWAY: + dicon = "Yahoo!_away"; + break; + case STATUS_NA: + dicon = "Yahoo!_na"; + break; + case STATUS_DND: + dicon = "Yahoo!_dnd"; + break; + case STATUS_OCCUPIED: + dicon = "Yahoo!_occupied"; + break; + case STATUS_FFC: + dicon = "Yahoo!_ffc"; + break; + } + }else if (h == "sms"){ + switch (status){ + case STATUS_ONLINE: + dicon = "sms_online"; + break; + case STATUS_OFFLINE: + dicon = "sms_offline"; + break; + case STATUS_AWAY: + dicon = "sms_away"; + break; + case STATUS_NA: + dicon = "sms_na"; + break; + case STATUS_DND: + dicon = "sms_dnd"; + break; + case STATUS_OCCUPIED: + dicon = "sms_occupied"; + break; + case STATUS_FFC: + dicon = "sms_ffc"; + break; + } + }else if ((h == "x-gadugadu") || (h == "gg")){ + switch (status){ + case STATUS_ONLINE: + dicon = "GG_online"; + break; + case STATUS_OFFLINE: + dicon = "GG_offline"; + break; + case STATUS_AWAY: + dicon = "GG_away"; + break; + case STATUS_NA: + dicon = "GG_na"; + break; + case STATUS_DND: + dicon = "GG_dnd"; + break; + case STATUS_OCCUPIED: + dicon = "GG_occupied"; + break; + case STATUS_FFC: + dicon = "GG_ffc"; + break; + } + } + } + return dicon; +} + +void JabberClient::contactInfo(void *_data, unsigned long &curStatus, unsigned &style, QString &statusIcon, QSet *icons) +{ + JabberUserData *data = toJabberUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + QString dicon = get_icon(data, data->Status.toULong(), data->invisible.toBool()); + if (data->Status.toULong() > curStatus) + { + curStatus = data->Status.toULong(); + if(!statusIcon.isEmpty() && icons) + { + icons->insert(statusIcon); + } + statusIcon = dicon; + } + else + { + if (!statusIcon.isEmpty()) + { + addIcon(icons, dicon, statusIcon); + } + else + { + statusIcon = dicon; + } + } + for (unsigned i = 1; i <= data->nResources.toULong(); i++){ + QString dicon = get_icon(data, get_str(data->ResourceStatus, i).toUInt(), false); + addIcon(icons, dicon, statusIcon); + } + if (((data->Subscribe.toULong() & SUBSCRIBE_TO) == 0) && !isAgent(data->ID.str())) + style |= CONTACT_UNDERLINE; + if (icons && data->IsTyping.toBool()) + addIcon(icons, "typing", statusIcon); +} + +QString JabberClient::buildId(JabberUserData *data) +{ + return data->ID.str(); +} + +QWidget *JabberClient::searchWindow(QWidget *parent) +{ + if (getState() != Connected) + return NULL; + return new JabberAdd(this, parent); +} + +void JabberClient::ping() +{ + if (getState() != Connected) + return; + socket()->writeBuffer().packetStart(); + socket()->writeBuffer() << "\n"; + sendPacket(); + QTimer::singleShot(PING_TIMEOUT * 1000, this, SLOT(ping())); +} + +QString JabberClient::contactName(void *clientData) +{ + QString res = Client::contactName(clientData); + res += ": "; + JabberUserData *data = toJabberUserData((SIM::clientData*)clientData); // FIXME unsafe type conversion + QString name = data->ID.str(); + if (!data->Nick.str().isEmpty()){ + res += data->Nick.str(); + res += " ("; + res += name; + res += ')'; + }else{ + res += name; + } + return res; +} + + +QString JabberClient::contactTip(void *_data) +{ + JabberUserData *data = toJabberUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + QString res; + if (data->nResources.toULong() == 0){ + res = "invisible.toBool()); + res += "\">"; + res += i18n("Offline"); + res += "
"; + res += "ID: "; + res += data->ID.str(); + if (!data->Resource.str().isEmpty()){ + res += '/'; + res += data->Resource.str(); + } + res += ""; + + if (data->StatusTime.toULong()){ + res += "
"; + res += i18n("Last online"); + res += ": "; + res += formatDateTime(data->StatusTime.toULong()); + } + QString &reply = data->AutoReply.str(); + if (!reply.isEmpty()){ + res += "
"; + res += reply.replace('\n', "
"); + } + }else{ + for (unsigned i = 1; i <= data->nResources.toULong(); i++){ + unsigned status = get_str(data->ResourceStatus, i).toUInt(); + res += ""; + QString statusText; + for (const CommandDef *cmd = protocol()->statusList(); !cmd->text.isEmpty(); cmd++){ + if (cmd->id == status){ + statusText = i18n(cmd->text); + res += statusText; + break; + } + } + res += "
ID: "; + res += data->ID.str(); + QString resource = get_str(data->Resources, i); + if (!resource.isEmpty()){ + res += '/'; + res += resource; + } + res += ""; + + unsigned onlineTime = get_str(data->ResourceOnlineTime, i).toUInt(); + unsigned statusTime = get_str(data->ResourceStatusTime, i).toUInt(); + if (onlineTime){ + res += "
"; + res += i18n("Online"); + res += ": "; + res += formatDateTime(onlineTime); + } + if (statusTime != onlineTime){ + res += "
"; + res += statusText; + res += ": "; + res += formatDateTime(statusTime); + } + + QString clientName = get_str(data->ResourceClientName, i); + QString clientVersion = get_str(data->ResourceClientVersion, i); + QString clientOS = get_str(data->ResourceClientOS, i); + if (!clientName.isEmpty()) { + res += "
" + clientName + ' ' + clientVersion; + if (!clientOS.isEmpty()) + res += " / " + clientOS; + } + + const QString &reply = get_str(data->ResourceReply, i); + if (!reply.isEmpty()){ + res += "

"; + QString r = reply; + r = r.replace('\n', "
"); + res += r; + } + if (i < data->nResources.toULong()) + res += "
_________
"; + } + } + + if (data->LogoWidth.toLong() && data->LogoHeight.toLong()){ + QString logoFileName = logoFile(data); + QImage img(logoFileName); + if (!img.isNull()){ + QPixmap pict = QPixmap::fromImage(img); + int w = pict.width(); + int h = pict.height(); + if (h > w){ + if (h > 60){ + w = w * 60 / h; + h = 60; + } + }else{ + if (w > 60){ + h = h * 60 / w; + w = 60; + } + } + res += "
"; + } + } + if (data->PhotoWidth.toLong() && data->PhotoHeight.toLong()){ + QString photoFileName = photoFile(data); + QImage img(photoFileName); + if (!img.isNull()){ + QPixmap pict = QPixmap::fromImage(img); + int w = pict.width(); + int h = pict.height(); + if (h > w){ + if (h > 60){ + w = w * 60 / h; + h = 60; + } + }else{ + if (w > 60){ + h = h * 60 / w; + w = 60; + } + } + res += "
"; + } + } + return res; +} + +void JabberClient::setOffline(JabberUserData *data) +{ + data->Status.asULong() = STATUS_OFFLINE; + data->composeId.asULong() = 0; + data->Resources.clear(); + data->ResourceReply.clear(); + data->ResourceStatus.clear(); + data->ResourceStatusTime.clear(); + data->ResourceOnlineTime.clear(); + data->nResources.asULong() = 0; + data->TypingId.str() = QString::null; + if (data->IsTyping.toBool()){ + data->IsTyping.asBool() = false; + Contact *contact; + QString resource; + if (findContact(data->ID.str(), QString::null, false, contact, resource)){ + EventContact e(contact, EventContact::eStatus);; + e.process(); + } + } +} + +const unsigned MAIN_INFO = 1; +const unsigned HOME_INFO = 2; +const unsigned WORK_INFO = 3; +const unsigned ABOUT_INFO = 4; +const unsigned PHOTO_INFO = 5; +const unsigned LOGO_INFO = 6; +const unsigned NETWORK = 7; + +static CommandDef jabberWnd[] = + { + CommandDef ( + MAIN_INFO, + " ", + "Jabber_online", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + HOME_INFO, + I18N_NOOP("Home info"), + "home", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + WORK_INFO, + I18N_NOOP("Work info"), + "work", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + ABOUT_INFO, + I18N_NOOP("About info"), + "info", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + PHOTO_INFO, + I18N_NOOP("Photo"), + "pict", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + LOGO_INFO, + I18N_NOOP("Logo"), + "pict", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef (), + }; + +static CommandDef cfgJabberWnd[] = + { + CommandDef ( + MAIN_INFO, + " ", + "Jabber_online", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + HOME_INFO, + I18N_NOOP("Home info"), + "home", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + WORK_INFO, + I18N_NOOP("Work info"), + "work", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + ABOUT_INFO, + I18N_NOOP("About info"), + "info", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + PHOTO_INFO, + I18N_NOOP("Photo"), + "pict", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + LOGO_INFO, + I18N_NOOP("Logo"), + "pict", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + NETWORK, + I18N_NOOP("Network"), + "network", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef (), + }; + +CommandDef *JabberClient::infoWindows(Contact*, void *_data) +{ + JabberUserData *data = toJabberUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + QString name = i18n(protocol()->description()->text); + name += ' '; + name += data->ID.str(); + jabberWnd[0].text_wrk = name; + return jabberWnd; +} + +CommandDef *JabberClient::configWindows() +{ + QString title = name(); + int n = title.indexOf('.'); + if (n > 0) + title = title.left(n) + ' ' + title.mid(n + 1); + cfgJabberWnd[0].text_wrk = title; + return cfgJabberWnd; +} + +QWidget *JabberClient::infoWindow(QWidget *parent, Contact*, void *_data, unsigned id) +{ + JabberUserData *data = toJabberUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + switch (id){ + case MAIN_INFO: + return new JabberInfo(parent, data, this); + case HOME_INFO: + return new InfoProxy(parent, new JabberHomeInfo(parent, data, this), i18n("Home info")); + case WORK_INFO: + return new InfoProxy(parent, new JabberWorkInfo(parent, data, this), i18n("Work info")); + case ABOUT_INFO: + return new InfoProxy(parent, new JabberAboutInfo(parent, data, this), i18n("About info")); + case PHOTO_INFO: + return new JabberPicture(parent, data, this, true); + case LOGO_INFO: + return new JabberPicture(parent, data, this, false); + } + return NULL; +} + +QWidget *JabberClient::configWindow(QWidget *parent, unsigned id) +{ + switch (id){ + case MAIN_INFO: + return new JabberInfo(parent, NULL, this); + case HOME_INFO: + return new InfoProxy(parent, new JabberHomeInfo(parent, NULL, this), i18n("Home info")); + case WORK_INFO: + return new InfoProxy(parent, new JabberWorkInfo(parent, NULL, this), i18n("Work info")); + case ABOUT_INFO: + return new InfoProxy(parent, new JabberAboutInfo(parent, NULL, this), i18n("About info")); + case PHOTO_INFO: + return new JabberPicture(parent, NULL, this, true); + case LOGO_INFO: + return new JabberPicture(parent, NULL, this, false); + case NETWORK: + return new JabberConfig(parent, this, true); + } + return NULL; +} + +void JabberClient::updateInfo(Contact *contact, void *data) +{ + if (getState() != Connected){ + Client::updateInfo(contact, data); + return; + } + if (data == NULL) + data = &this->data.owner; + info_request(toJabberUserData((SIM::clientData*)data), false); // FIXME unsafe type conversion +} + +QString JabberClient::resources(void *_data) +{ + JabberUserData *data = toJabberUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + QString resource; + if (data->nResources.toULong() > 1){ + for (unsigned i = 1; i <= data->nResources.toULong(); i++){ + if (!resource.isEmpty()) + resource += ';'; + QString dicon = get_icon(data, get_str(data->ResourceStatus, i).toUInt(), false); + resource += dicon; //QString::number(dicon); + resource += ','; + resource += quoteChars(get_str(data->Resources, i), ";"); + } + } + return resource; +} + +bool JabberClient::canSend(unsigned type, void *_data) +{ + if ((_data == NULL) || (((clientData*)_data)->Sign.toULong() != JABBER_SIGN)) + return false; + if (getState() != Connected) + return false; + JabberUserData *data = toJabberUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + switch (type) + { + case MessageGeneric: + case MessageFile: + case MessageContacts: + case MessageUrl: + return true; + case MessageAuthRequest: + return ((data->Subscribe.toULong() & SUBSCRIBE_TO) == 0); + case MessageAuthGranted: + return ((data->Subscribe.toULong() & SUBSCRIBE_FROM) == 0); + case MessageAuthRefused: + return (data->Subscribe.toULong() & SUBSCRIBE_FROM); + case MessageJabberOnline: + return isAgent(data->ID.str()) && (data->Status.toULong() == STATUS_OFFLINE); + case MessageJabberOffline: + return isAgent(data->ID.str()) && (data->Status.toULong() != STATUS_OFFLINE); + } + return false; +} + +class JabberImageParser : public HTMLParser +{ +public: + JabberImageParser(unsigned bgColor); + QString parse(const QString &text); +protected: + virtual void text(const QString &text); + virtual void tag_start(const QString &tag, const list &attrs); + virtual void tag_end(const QString &tag); + void startBody(const list &attrs); + void endBody(); + QString res; + bool m_bPara; + bool m_bBody; + unsigned m_bgColor; +}; + +JabberImageParser::JabberImageParser(unsigned bgColor) +{ + m_bPara = false; + m_bBody = true; + m_bgColor = bgColor; +} + +QString JabberImageParser::parse(const QString &text) +{ + list attrs; + startBody(attrs); + HTMLParser::parse(text); + endBody(); + return res; +} + +void JabberImageParser::text(const QString &text) +{ + if (m_bBody) + res += quoteString(text); +} + +static const char *_tags[] = + { + "abbr", + "acronym", + "address", + "blockquote", + "cite", + "code", + "dfn", + "div", + "em", + "h1", + "h2", + "h3", + "h4", + "h5", + "h6", + "kbd", + "p", + "pre", + "q", + "samp", + "span", + "strong", + "var", + "a", + "dl", + "dt", + "dd", + "ol", + "ul", + "li", + NULL + }; + +static const char *_styles[] = + { + "color", + "background-color", + "font-family", + "font-size", + "font-style", + "font-weight", + "text-align", + "text-decoration", + NULL + }; + +void JabberImageParser::startBody(const list &attrs) +{ + m_bBody = true; + res = QString::null; + list newStyles; + list::const_iterator it; + for (it = attrs.begin(); it != attrs.end(); ++it){ + QString name = *it; + ++it; + QString value = *it; + if (name == "style"){ + list styles = parseStyle(value); + for (list::iterator it = styles.begin(); it != styles.end(); ++it){ + QString name = *it; + ++it; + QString value = *it; + for (const char **s = _styles; *s; s++){ + if (name == *s){ + newStyles.push_back(name); + newStyles.push_back(value); + break; + } + } + } + } + } + for (it = newStyles.begin(); it != newStyles.end(); ++it){ + QString name = *it; + ++it; + if (name == "background-color") + break; + } + if (it == newStyles.end()){ + char b[15]; + sprintf(b, "#%06X", m_bgColor & 0xFFFFFF); + newStyles.push_back("background-color"); + newStyles.push_back(b); + } + res += ""; +} + +void JabberImageParser::endBody() +{ + if (m_bBody){ + res += ""; + m_bBody = false; + } +} + +void JabberImageParser::tag_start(const QString &tag, const list &attrs) +{ + if (tag == "html"){ + m_bBody = false; + res = QString::null; + return; + } + if (tag == "body"){ + startBody(attrs); + return; + } + if (!m_bBody) + return; + if (tag == "img"){ + QString src; + QString alt; + for (list::const_iterator it = attrs.begin(); it != attrs.end(); ++it){ + QString name = *it; + ++it; + QString value = *it; + if (name == "src") + src = value; + if (name == "alt") + alt = value; + } + if (!alt.isEmpty()){ + res += unquoteString(alt); + return; + } + if (src.left(10) == "sim:icons/"){ + QStringList smiles = getIcons()->getSmile(src.mid(10)); + if (!smiles.empty()){ + res += smiles.front(); + return; + } + } + text(alt); + return; + } + if (tag == "p"){ + if (m_bPara){ + res += "
"; + m_bPara = false; + } + return; + } + if (tag == "br"){ + res += "
"; + return; + } + for (const char **t = _tags; *t; t++){ + if (tag == *t){ + res += '<'; + res += tag; + for (list::const_iterator it = attrs.begin(); it != attrs.end(); ++it){ + QString name = *it; + ++it; + QString value = *it; + if (name == "style"){ + list styles = parseStyle(value); + list newStyles; + for (list::iterator it = styles.begin(); it != styles.end(); ++it){ + QString name = *it; + ++it; + QString value = *it; + for (const char **s = _styles; *s; s++){ + if (name == *s){ + newStyles.push_back(name); + newStyles.push_back(value); + break; + } + } + } + value = makeStyle(newStyles); + } + if ((name != "style") && (name != "href")) + continue; + res += ' '; + res += name; + if (!value.isEmpty()){ + res += "=\'"; + res += quoteString(value); + res += "\'"; + } + } + res += '>'; + return; + } + } + if (tag == "b"){ + res += ""; + return; + } + if (tag == "i"){ + res += ""; + return; + } + if (tag == "u"){ + res += ""; + return; + } + if (tag == "font"){ + res += "::const_iterator it = attrs.begin(); it != attrs.end(); ++it){ + QString name = *it; + ++it; + QString value = *it; + if (name == "color"){ + if (!style.isEmpty()) + style += ';'; + style += "color: "; + style += value; + continue; + } + } + if (!style.isEmpty()){ + res += " style=\'"; + res += style; + res += "\'"; + } + res += '>'; + return; + } + return; +} + +void JabberImageParser::tag_end(const QString &tag) +{ + if (tag == "body"){ + endBody(); + return; + } + if (!m_bBody) + return; + if (tag == "p"){ + m_bPara = true; + return; + } + for (const char **t = _tags; *t; t++){ + if (tag == *t){ + res += "'; + return; + } + } + if ((tag == "b") || (tag == "i") || (tag == "u") || (tag == "font")){ + res += ""; + return; + } +} + +static QString removeImages(const QString &text, unsigned bgColor) +{ + JabberImageParser p(bgColor); + return p.parse(text); +} + +bool JabberClient::send(Message *msg, void *_data) +{ + if ((getState() != Connected) || (_data == NULL)) + return false; + JabberUserData *data = toJabberUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + switch (msg->type()){ + case MessageAuthRefused:{ + QString grp; + Group *group = NULL; + Contact *contact = getContacts()->contact(msg->contact()); + if (contact && contact->getGroup()) + group = getContacts()->group(contact->getGroup()); + if (group) + grp = group->getName(); + listRequest(data, data->Name.str(), grp, false); + if (data->Subscribe.toULong() & SUBSCRIBE_FROM){ + socket()->writeBuffer().packetStart(); + socket()->writeBuffer() + << "ID.str() + << "\' type=\'unsubscribed\'>\n" + << encodeXML(msg->getPlainText()) + << "\n"; + sendPacket(); + if ((msg->getFlags() & MESSAGE_NOHISTORY) == 0){ + msg->setClient(dataName(data)); + EventSent(msg).process(); + } + EventMessageSent(msg).process(); + delete msg; + return true; + } + } + case MessageGeneric:{ + Contact *contact = getContacts()->contact(msg->contact()); + if ((contact == NULL) || (data == NULL)) + return false; + QString text = msg->getPlainText(); + EventSend e(msg, text.toUtf8()); + e.process(); + text = QString::fromUtf8( e.localeText() ); + socket()->writeBuffer().packetStart(); + socket()->writeBuffer() + << "ID.str(); + if(!msg->getResource().isEmpty()) + { + socket()->writeBuffer() << QString("/") << encodeXMLattr(msg->getResource()); + } + if (getTyping()){ + data->composeId.asULong() = ++m_msg_id; + QString msg_id = "msg"; + msg_id += QString::number(data->composeId.asULong()); + socket()->writeBuffer() + << "\' id=\'" << msg_id; + } + if (text.startsWith("-----BEGIN PGP MESSAGE-----")){ + socket()->writeBuffer() + << "\'>\nThis message is encrypted.\n"; + }else{ + socket()->writeBuffer() + << "\'>\n" << encodeXML(text) << "\n"; + if (data->richText.toBool() && getRichText() && (msg->getFlags() & MESSAGE_RICHTEXT)){ + socket()->writeBuffer() + << "\n" + << removeImages(msg->getRichText(), msg->getBackground()) + << "\n\n"; + } + } + if (getTyping()){ + socket()->writeBuffer() + << "\n" + << "\n" + << "\n"; + } + if (text.startsWith("-----BEGIN PGP MESSAGE-----")){ + text.truncate(text.indexOf("\n-----END PGP MESSAGE-----")); + socket()->writeBuffer() + << "" + << text.remove(0, text.indexOf("\n\n") + 2) + << "\n"; + } + socket()->writeBuffer() + << ""; + sendPacket(); + if ((msg->getFlags() & MESSAGE_NOHISTORY) == 0){ + if (data->richText.toBool()){ + msg->setClient(dataName(data)); + EventSent(msg).process(); + }else{ + Message m(MessageGeneric); + m.setContact(msg->contact()); + m.setClient(dataName(data)); + m.setText(msg->getPlainText()); + EventSent(msg).process(); + } + } + EventMessageSent(msg).process(); + delete msg; + return true; + } + case MessageUrl:{ + Contact *contact = getContacts()->contact(msg->contact()); + if ((contact == NULL) || (data == NULL)) + return false; + UrlMessage *m = static_cast(msg); + socket()->writeBuffer().packetStart(); + socket()->writeBuffer() + << "ID.str(); + if (!msg->getResource().isEmpty()){ + socket()->writeBuffer() + << QString("/") << encodeXMLattr(msg->getResource()); + } + socket()->writeBuffer() + << "\'>\n" << encodeXML(m->getUrl()); + QString t = m->getPlainText(); + if (!t.isEmpty()){ + socket()->writeBuffer() + << "\n" << encodeXML(m->getPlainText()); + } + socket()->writeBuffer() + << "\n"; + if (data->richText.toBool() && getRichText()){ + socket()->writeBuffer() + << "\n" + << "getUrl()) << "\'>" + << encodeXML(m->getUrl()) << ""; + if (!t.isEmpty()){ + socket()->writeBuffer() + << "
\n" + << removeImages(msg->getRichText(), msg->getBackground()); + } + socket()->writeBuffer() + << "\n\n"; + } + socket()->writeBuffer() + << "
"; + sendPacket(); + if ((msg->getFlags() & MESSAGE_NOHISTORY) == 0){ + if (data->richText.toBool()){ + msg->setClient(dataName(data)); + EventSent(msg).process(); + }else{ + Message m(MessageGeneric); + m.setContact(msg->contact()); + m.setClient(dataName(data)); + m.setText(msg->getPlainText()); + EventSent(msg).process(); + } + } + EventMessageSent(msg).process(); + delete msg; + return true; + } + case MessageContacts:{ + Contact *contact = getContacts()->contact(msg->contact()); + if ((contact == NULL) || (data == NULL)) + return false; + ContactsMessage *m = static_cast(msg); + QStringList jids; + QStringList names; + QString contacts = m->getContacts(); + QString nc; + while (!contacts.isEmpty()){ + QString item = getToken(contacts, ';'); + QString url = getToken(item, ','); + QString proto = getToken(url, ':'); + if (proto == "sim"){ + Contact *contact = getContacts()->contact(url.toLong()); + if (contact){ + clientData *data; + ClientDataIterator it(contact->clientData); + while ((data = ++it) != NULL){ + Contact *c = contact; + if (!isMyData(data, c)) + continue; + JabberUserData *d = toJabberUserData(data); + jids.append(d->ID.str()); + names.append(c->getName()); + if (!nc.isEmpty()) + nc += ';'; + nc += "jabber:"; + nc += d->ID.str(); + nc += ','; + if (c->getName() == d->ID.str()){ + nc += d->ID.str(); + }else{ + nc += c->getName(); + nc += " ("; + nc += d->ID.str(); + nc += ')'; + } + } + } + } + } + if (jids.isEmpty()){ + msg->setError(I18N_NOOP("No contacts for send")); + EventMessageSent(msg).process(); + delete msg; + return true; + } + m->setContacts(nc); + socket()->writeBuffer().packetStart(); + socket()->writeBuffer() + << "ID.str(); + if (!msg->getResource().isEmpty()){ + socket()->writeBuffer() + << QString("/") << encodeXMLattr(msg->getResource()); + } + socket()->writeBuffer() + << "\'>\n\n"; + QStringList::ConstIterator iti = jids.constBegin(); + QStringList::ConstIterator itn = names.constBegin(); + for (; iti != jids.constEnd(); ++iti, ++itn){ + socket()->writeBuffer() + << "\n\n\n"; + } + socket()->writeBuffer() + << "\n"; + iti = jids.constBegin(); + for (; iti != jids.constEnd(); ++iti, ++itn){ + socket()->writeBuffer() + << encodeXML(*iti) + << "\n"; + } + socket()->writeBuffer() + << "\n"; + if (data->richText.toBool() && getRichText()){ + socket()->writeBuffer() + << "\n"; + iti = jids.constBegin(); + for (; iti != jids.constEnd(); ++iti, ++itn){ + socket()->writeBuffer() + << encodeXML(*iti) + << "
\n"; + } + socket()->writeBuffer() + << "\n\n"; + } + socket()->writeBuffer() + << "
"; + sendPacket(); + if ((msg->getFlags() & MESSAGE_NOHISTORY) == 0){ + if (data->richText.toBool()){ + msg->setClient(dataName(data)); + EventSent(msg).process(); + }else{ + Message m(MessageGeneric); + m.setContact(msg->contact()); + m.setClient(dataName(data)); + m.setText(msg->getPlainText()); + EventSent(&m).process(); + } + } + EventMessageSent(msg).process(); + delete msg; + return true; + } + case MessageFile:{ + m_waitMsg.push_back(msg); + JabberFileTransfer *ft = static_cast(static_cast(msg)->m_transfer); + if (ft == NULL) + ft = new JabberFileTransfer(static_cast(msg), data, this); + ft->listen(); + return true; + } + case MessageAuthRequest:{ + socket()->writeBuffer().packetStart(); + socket()->writeBuffer() + << "ID.str() + << "\' type=\'subscribe\'>\n" + << encodeXML(msg->getPlainText()) + << "\n"; + sendPacket(); + if ((msg->getFlags() & MESSAGE_NOHISTORY) == 0){ + msg->setClient(dataName(data)); + EventSent(msg).process(); + } + EventMessageSent(msg).process(); + delete msg; + return true; + } + case MessageAuthGranted:{ + socket()->writeBuffer().packetStart(); + socket()->writeBuffer() + << "ID.str() + << "\' type=\'subscribed\'>"; + sendPacket(); + if ((msg->getFlags() & MESSAGE_NOHISTORY) == 0){ + msg->setClient(dataName(data)); + EventSent(msg).process(); + } + EventMessageSent(msg).process(); + delete msg; + return true; + } + case MessageJabberOnline: + if (isAgent(data->ID.str()) && (data->Status.toULong() == STATUS_OFFLINE)){ + socket()->writeBuffer().packetStart(); + socket()->writeBuffer() + << "ID.str() + << "\'>"; + sendPacket(); + delete msg; + return true; + } + break; + case MessageJabberOffline: + if (isAgent(data->ID.str()) && (data->Status.toULong() != STATUS_OFFLINE)){ + socket()->writeBuffer().packetStart(); + socket()->writeBuffer() + << "ID.str() + << "\' type=\'unavailable\'>"; + sendPacket(); + delete msg; + return true; + } + break; + case MessageTypingStart: + if (getTyping()){ + socket()->writeBuffer().packetStart(); + socket()->writeBuffer() + << "ID.str() + << "\'>\n\n\n" + << data->TypingId.str() + << "\n\n"; + sendPacket(); + delete msg; + return true; + } + break; + case MessageTypingStop: + if (getTyping()){ + socket()->writeBuffer().packetStart(); + socket()->writeBuffer() + << "ID.str() + << "\'>\n\n" + << data->TypingId.str() + << "\n\n"; + sendPacket(); + delete msg; + return true; + } + break; + } + return false; +} + +QString JabberClient::dataName(void *_data) +{ + QString res = name(); + JabberUserData *data = toJabberUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + res += '+'; + res += data->ID.str(); + res = res.replace('/', '_'); + return res; +} + +void JabberClient::listRequest(JabberUserData *data, const QString &name, const QString &grp, bool bDelete) +{ + QString jid = data->ID.str(); + list::iterator it; + for (it = m_listRequests.begin(); it != m_listRequests.end(); ++it){ + if (jid == it->jid){ + m_listRequests.erase(it); + break; + } + } + JabberListRequest lr; + lr.jid = jid; + lr.name = name; + lr.grp = grp; + lr.bDelete = bDelete; + m_listRequests.push_back(lr); + processList(); +} + +JabberListRequest *JabberClient::findRequest(const QString &jid, bool bRemove) +{ + list::iterator it; + for (it = m_listRequests.begin(); it != m_listRequests.end(); ++it){ + if (it->jid == jid){ + if (bRemove){ + m_listRequests.erase(it); + return NULL; + } + return &(*it); + } + } + return NULL; +} + + +bool JabberClient::isAgent(const QString &jid) +{ + if (jid.indexOf('@')==-1) + return true; + return false; +} + +class JabberClient::JabberAuthMessage : public AuthMessage +{ +public: + JabberAuthMessage(std::vector &tempMessages, unsigned type, Buffer *cfg=NULL) + : AuthMessage(type, cfg) + , tempMessages(tempMessages) + { + tempMessages.push_back(this); + } + virtual ~JabberAuthMessage() + { + remove(tempMessages, this); + } + + static bool remove(std::vector&messages, JabberAuthMessage *value) + { + std::vector::iterator it = find(messages.begin(), messages.end(), value); + if (it != messages.end()) + { + messages.erase(it); + return true; + } + return false; + } + JabberAuthMessage & operator=( const JabberAuthMessage & ) { return *this; } + +private: + std::vector &tempMessages; +}; + +void JabberClient::auth_request(const QString &jid, unsigned type, const QString &text, bool bCreate) +{ + Contact *contact; + QString resource; + JabberUserData *data = findContact(jid, QString::null, false, contact, resource); + if (isAgent(jid) || ((type == MessageAuthRequest) && getAutoAccept())){ + switch (type){ + case MessageAuthRequest:{ + if (data == NULL) + data = findContact(jid, QString::null, true, contact, resource); + socket()->writeBuffer().packetStart(); + socket()->writeBuffer() + << "ID.str() + << "\' type=\'subscribed\'>"; + sendPacket(); + socket()->writeBuffer().packetStart(); + socket()->writeBuffer() + << "ID.str() + << "\' type=\'subscribe\'>\n" + << "\n"; + sendPacket(); + EventContact e(contact, EventContact::eChanged); + e.process(); + return; + } + case MessageAuthGranted:{ + if (data == NULL) + data = findContact(jid, QString::null, true, contact, resource); + data->Subscribe.asULong() |= SUBSCRIBE_TO; + EventContact e(contact, EventContact::eChanged); + e.process(); + return; + } + + } + } + if ((data == NULL) && bCreate){ + data = findContact(jid, QString::null, true, contact, resource); + contact->setFlags(CONTACT_TEMP); + } + if (data == NULL) + return; + if (((type == MessageAuthGranted) || (type ==MessageAuthRefused)) && + (contact->getFlags() & CONTACT_TEMP)){ + contact->setFlags(contact->getFlags() & ~CONTACT_TEMP); + EventContact e(contact, EventContact::eChanged); + e.process(); + return; + } + JabberAuthMessage *msg = new JabberAuthMessage(tempAuthMessages, type); + msg->setContact(contact->id()); + msg->setClient(dataName(data)); + msg->setFlags(MESSAGE_RECEIVED); + if(!text.isEmpty()) + msg->setText(unquoteString(text)); + EventMessageReceived e(msg); + e.process(); + if (JabberAuthMessage::remove(tempAuthMessages, msg)) + { + delete msg; + } + if (type == MessageAuthGranted) { + data->Subscribe.asULong() |= SUBSCRIBE_TO; + EventContact e(contact, EventContact::eChanged); + e.process(); + } else + if (type == MessageAuthRefused) { + data->Subscribe.asULong() &= ~SUBSCRIBE_TO; + EventContact e(contact, EventContact::eChanged); + e.process(); + } +} + +void JabberClient::setInvisible(bool bState) +{ + if (getInvisible() == bState) + return; + TCPClient::setInvisible(bState); + if (getStatus() == STATUS_OFFLINE) + return; + unsigned status = getStatus(); + m_status = STATUS_OFFLINE; + if (getInvisible()){ + setStatus(status, NULL); + return; + } + setStatus(status); +} + +QString JabberClient::VHost() +{ + if (data.UseVHost.toBool() && !data.VHost.str().isEmpty()) + return data.VHost.str(); + return data.Server.str(); +} + +static char PICT_PATH[] = "pictures/"; + +QString JabberClient::photoFile(JabberUserData *data) +{ + QString f = PICT_PATH; + f += "photo."; + f += data->ID.str(); + f = user_file(f); + return f; +} + +QString JabberClient::logoFile(JabberUserData *data) +{ + QString f = PICT_PATH; + f += "logo."; + f += data->ID.str(); + f = user_file(f); + return f; +} + +void JabberClient::setupContact(Contact *contact, void *_data) +{ + JabberUserData *data = toJabberUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + QString mail = data->EMail.str(); + contact->setEMails(mail, name()); + QString phones; + if (!data->Phone.str().isEmpty()){ + phones = data->Phone.str(); + phones += ",Home Phone,"; + phones += QString::number(PHONE); + } + contact->setPhones(phones, name()); + + if (contact->getFirstName().isEmpty() && !data->FirstName.str().isEmpty()) + contact->setFirstName(data->FirstName.str(), name()); + + if (contact->getName().isEmpty()) + contact->setName(data->ID.str()); +} + +QImage JabberClient::userPicture(JabberUserData *d) +{ + JabberUserData *_d = d ? d : &data.owner; + QImage img; + + if (_d->PhotoWidth.toLong() && _d->PhotoHeight.toLong()) { + img = QImage(photoFile(_d)); + } else if (_d->LogoWidth.toLong() && _d->LogoHeight.toLong()) { + img = QImage(logoFile(_d)); + } + if(img.isNull()) + return img; + + int w = img.width(); + int h = img.height(); + if (h > w){ + if (h > 60){ + w = w * 60 / h; + h = 60; + } + }else{ + if (w > 60){ + h = h * 60 / w; + w = 60; + } + } + + return img.scaled(w, h); +} + +QImage JabberClient::userPicture(unsigned id) +{ + if (id==0) + return QImage(); + Contact *contact = getContacts()->contact(id); + if(!contact) + return QImage(); + ClientDataIterator it(contact->clientData, this); + + JabberUserData *d; + while ((d = toJabberUserData(++it)) != NULL){ + QImage img = userPicture(d); + if(!img.isNull()) + return img; + } + return QImage(); +} + +JabberUserData* JabberClient::toJabberUserData(SIM::clientData * data) +{ + // This function is used to more safely preform type conversion from SIM::clientData* into JabberUserData* + // It will at least warn if the content of the structure is not JabberUserData + // Brave wariors may uncomment abort() function call to know for sure about wrong conversion ;-) + if (! data) return NULL; + if (data->Sign.asULong() != JABBER_SIGN) + { + QString Signs[] = { + "Unknown(0)" , // 0x0000 + "ICQ_SIGN", // 0x0001 + "JABBER_SIGN", // 0x0002 + "MSN_SIGN", // 0x0003 + "Unknown(4)" // 0x0004 + "LIVEJOURNAL_SIGN",// 0x0005 + "SMS_SIGN", // 0x0006 + "Unknown(7)", // 0x0007 + "Unknown(8)", // 0x0008 + "YAHOO_SIGN" // 0x0009 + }; + QString Sign; + if (data->Sign.toULong()<=9) // is always >=0 as it is unsigned int + Sign = Signs[data->Sign.toULong()]; + else + Sign = QString("Unknown(%1)").arg(Sign.toULong()); + + log(L_ERROR, + "ATTENTION!! Unsafly converting %s user data into JABBER_SIGN", + Sign.toLatin1().data()); +// abort(); + } + return (JabberUserData*) data; +} + +// vim: set expandtab: + diff --git a/plugins/jabber/jabberclient.h b/plugins/jabber/jabberclient.h new file mode 100644 index 0000000..668799b --- /dev/null +++ b/plugins/jabber/jabberclient.h @@ -0,0 +1,541 @@ +/*************************************************************************** + jabberclient.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _JABBERCLIENT_H +#define _JABBERCLIENT_H + +#include +#include +#include +#include + +#include "simapi.h" +#include "sax.h" +#include "socket/socket.h" +#include "socket/serversocketnotify.h" +#include "socket/tcpclient.h" +#include "jabberstatus.h" + +#include "jabberbuffer.h" + +using namespace std; + +class JabberProtocol; +class JabberClient; + +const unsigned JABBER_SIGN = 0x0002; + +const unsigned SUBSCRIBE_NONE = 0; +const unsigned SUBSCRIBE_FROM = 1; +const unsigned SUBSCRIBE_TO = 2; +const unsigned SUBSCRIBE_BOTH = (SUBSCRIBE_FROM | SUBSCRIBE_TO); + +struct JabberUserData : public SIM::clientData +{ + SIM::Data ID; + SIM::Data Node; + SIM::Data Resource; + SIM::Data Name; + SIM::Data Status; + SIM::Data FirstName; + SIM::Data Nick; + SIM::Data Desc; + SIM::Data Bday; + SIM::Data Url; + SIM::Data OrgName; + SIM::Data OrgUnit; + SIM::Data Title; + SIM::Data Role; + SIM::Data Street; + SIM::Data ExtAddr; + SIM::Data City; + SIM::Data Region; + SIM::Data PCode; + SIM::Data Country; + SIM::Data EMail; + SIM::Data Phone; + SIM::Data StatusTime; + SIM::Data OnlineTime; + SIM::Data Subscribe; + SIM::Data Group; + SIM::Data bChecked; + SIM::Data TypingId; + SIM::Data SendTypingEvents; + SIM::Data IsTyping; + SIM::Data composeId; + SIM::Data richText; + SIM::Data invisible; + SIM::Data PhotoWidth; + SIM::Data PhotoHeight; + SIM::Data LogoWidth; + SIM::Data LogoHeight; + SIM::Data nResources; + SIM::Data Resources; + SIM::Data ResourceStatus; + SIM::Data ResourceReply; + SIM::Data ResourceStatusTime; + SIM::Data ResourceOnlineTime; + SIM::Data AutoReply; + SIM::Data ResourceClientName; + SIM::Data ResourceClientVersion; + SIM::Data ResourceClientOS; +}; + +struct JabberClientData +{ + SIM::Data Server; + SIM::Data Port; + SIM::Data UseSSL; + SIM::Data UsePlain; + SIM::Data UseVHost; + SIM::Data Register; + SIM::Data Priority; + SIM::Data ListRequest; + SIM::Data VHost; + SIM::Data Typing; + SIM::Data RichText; + SIM::Data UseVersion; + SIM::Data ProtocolIcons; + SIM::Data MinPort; + SIM::Data MaxPort; + SIM::Data Photo; + SIM::Data Logo; + SIM::Data AutoSubscribe; + SIM::Data AutoAccept; + SIM::Data UseHTTP; + SIM::Data URL; + SIM::Data InfoUpdated; + JabberUserData owner; +}; + +struct JabberAgentsInfo +{ + SIM::Data VHost; + SIM::Data ID; + SIM::Data Name; + SIM::Data Search; + SIM::Data Register; + JabberClient *Client; +}; + +struct JabberAgentInfo +{ + SIM::Data ReqID; + SIM::Data VHost; + SIM::Data ID; + SIM::Data Field; + SIM::Data Type; + SIM::Data Label; + SIM::Data Value; + SIM::Data Desc; + SIM::Data Options; + SIM::Data OptionLabels; + SIM::Data nOptions; + SIM::Data bRequired; +}; + +struct JabberSearchData +{ + SIM::Data ID; + SIM::Data JID; + SIM::Data First; + SIM::Data Last; + SIM::Data Nick; + SIM::Data EMail; + SIM::Data Status; + SIM::Data Fields; + SIM::Data nFields; +}; + +struct JabberListRequest +{ + QString jid; + QString grp; + QString name; + bool bDelete; +}; + +struct DiscoItem +{ + QString id; + QString jid; + QString node; + QString name; + QString type; + QString category; + QString features; +}; + +// XEP-0092 Software Version +struct ClientVersionInfo +{ + QString jid; + QString node; + QString name; + QString version; + QString os; +}; + +// XEP-0012 Last Activity +struct ClientLastInfo +{ + QString jid; + unsigned int seconds; +}; + +// XEP-0090 Entity Time +struct ClientTimeInfo +{ + QString jid; + QString utc; + QString tz; + QString display; +}; + +class JabberClient : public SIM::TCPClient, public SAXParser +{ + Q_OBJECT +public: + class ServerRequest + { + public: + ServerRequest(JabberClient *client, const char *type, const QString &from, const QString &to, const QString &id=QString()); + virtual ~ServerRequest(); + void send(); + void start_element(const QString &name); + void end_element(bool bNewLevel = false); + void add_attribute(const QString &name, const char *value); + void add_attribute(const QString &name, const QString &value); + void add_condition(const QString &cond, bool bXData); + void add_text(const QString &text); + void text_tag(const QString &name, const QString &value); + static const char *_GET; + static const char *_SET; + static const char *_RESULT; + protected: + virtual void element_start(const QString& el, const QXmlAttributes& attrs); + virtual void element_end(const QString& el); + virtual void char_data(const QString& str); + QString m_element; + QStack m_els; + QString m_id; + JabberClient *m_client; + friend class JabberClient; + }; + + class IqRequest : public ServerRequest + { + public: + IqRequest(JabberClient *client); + ~IqRequest(); + public: + virtual void element_start(const QString& el, const QXmlAttributes& attrs); + virtual void element_end(const QString& el); + virtual void char_data(const QString& str); + QString *m_data; + QString m_url; + QString m_descr; + QString m_query; + QString m_from; + QString m_id; + QString m_type; + QString m_file_name; + unsigned m_file_size; + }; + + class PresenceRequest : public ServerRequest + { + public: + PresenceRequest(JabberClient *client); + ~PresenceRequest(); + protected: + virtual void element_start(const QString& el, const QXmlAttributes& attrs); + virtual void element_end(const QString& el); + virtual void char_data(const QString& str); + QString m_from; + QString m_data; + QString m_type; + QString m_status; + QString m_show; + QString m_stamp1; + QString m_stamp2; + }; + + class MessageRequest : public ServerRequest + { + public: + MessageRequest(JabberClient *client); + ~MessageRequest(); + protected: + virtual void element_start(const QString& el, const QXmlAttributes& attrs); + virtual void element_end(const QString& el); + virtual void char_data(const QString& str); + QString m_from; + QString *m_data; + QString m_body; + QString m_richText; + QString m_subj; + QString m_error; + QString m_contacts; + QString m_target; + QString m_desc; + QString m_enc; + vector m_targets; + vector m_descs; + + bool m_bBody; + bool m_bRosters; + bool m_bError; + QString m_id; + bool m_bCompose; + bool m_bEvent; + bool m_bRichText; + bool m_bEnc; + unsigned m_errorCode; + }; + + class StreamErrorRequest : public ServerRequest + { + public: + StreamErrorRequest(JabberClient *client); + ~StreamErrorRequest(); + protected: + virtual void element_start(const QString& el, const QXmlAttributes& attrs); + virtual void element_end(const QString& el); + virtual void char_data(const QString& str); + QString *m_data; + QString m_descr; + }; + + JabberClient(JabberProtocol*, Buffer *cfg); + ~JabberClient(); + virtual QString name(); + virtual QString dataName(void*); + virtual QWidget *setupWnd(); + virtual QByteArray getConfig(); + virtual QImage userPicture(unsigned id); + QImage userPicture(JabberUserData *d); + + void setID(const QString &id); + QString getID() + { + return data.owner.ID.str(); + } + PROP_STR(Server); + PROP_STR(VHost); + PROP_USHORT(Port); + PROP_BOOL(UseSSL); + PROP_BOOL(UsePlain); + PROP_BOOL(UseVHost); + PROP_BOOL(Register); + PROP_ULONG(Priority); + PROP_UTF8(ListRequest); + PROP_BOOL(Typing); + PROP_BOOL(RichText); + PROP_BOOL(UseVersion); + PROP_BOOL(ProtocolIcons); + PROP_USHORT(MinPort); + PROP_USHORT(MaxPort); + PROP_UTF8(Photo); + PROP_UTF8(Logo); + PROP_BOOL(AutoSubscribe); + PROP_BOOL(AutoAccept); + PROP_BOOL(UseHTTP); + PROP_STR(URL); + PROP_BOOL(InfoUpdated); + + QString buildId(JabberUserData *data); + JabberUserData *findContact(const QString &jid, const QString &name, bool bCreate, SIM::Contact *&contact, QString &resource, bool bJoin=true); + bool add_contact(const char *id, unsigned grp); + QString get_agents(const QString &jid); + QString get_agent_info(const QString &jid, const QString &node, const QString &type); + void auth_request(const QString &jid, unsigned type, const QString &text, bool bCreate); + QString search(const QString &jid, const QString &node, const QString &condition); + QString process(const QString &jid, const QString &node, const QString &condition, const QString &type); + + static QString get_attr(const char *name, const char **attrs); + virtual void setupContact(SIM::Contact*, void *data); + virtual void updateInfo(SIM::Contact *contact, void *data); + + JabberClientData data; + + JabberListRequest *findRequest(const QString &jid, bool bRemove); + + QString VHost(); + bool isAgent(const QString &jid); + virtual bool send(SIM::Message*, void*); + void listRequest(JabberUserData *data, const QString &name, const QString &grp, bool bDelete); + void sendFileRequest(SIM::FileMessage *msg, unsigned short port, JabberUserData *data, const QString &url, unsigned size); + void sendFileAccept(SIM::FileMessage *msg, JabberUserData *data); + + list m_ackMsg; + list m_waitMsg; + + QString photoFile(JabberUserData*); + QString logoFile(JabberUserData*); + list m_requests; + + QString discoItems(const QString &jid, const QString &node); + QString discoInfo(const QString &jid, const QString &node); + QString browse(const QString &jid); + QString versionInfo(const QString &jid, const QString &node = QString::null); + QString timeInfo(const QString &jid, const QString &node); + QString lastInfo(const QString &jid, const QString &node); + QString statInfo(const QString &jid, const QString &node); + void addLang(ServerRequest *req); + void info_request(JabberUserData *user_data, bool bVCard); + virtual void setClientInfo(void *data); + void changePassword(const QString &pass); + + // reimplement socket() to get correct Buffer + virtual JabberClientSocket *socket() { return static_cast(TCPClient::socket()); } + virtual JabberClientSocket *createClientSocket() { return new JabberClientSocket(this, createSocket()); } + + virtual void changeStatus(const SIM::IMStatusPtr& status); + + JabberUserData* toJabberUserData(SIM::clientData *); // More safely type conversion from generic SIM::clientData into JabberUserData +protected slots: + void ping(); + void auth_failed(); + void auth_ok(); +protected: + virtual bool processEvent(SIM::Event *e); + SIM::Socket *createSocket(); + + virtual QString contactName(void *clientData); + virtual void setStatus(unsigned status); + void setStatus(unsigned status, const QString &ar); + virtual void disconnected(); + virtual void connect_ready(); + virtual void packet_ready(); + virtual void setInvisible(bool bState); + virtual bool isMyData(SIM::clientData*&, SIM::Contact*&); + virtual bool createData(SIM::clientData*&, SIM::Contact*); + virtual bool compareData(void*, void*); + virtual bool canSend(unsigned, void*); + virtual void contactInfo(void *data, unsigned long &curStatus, unsigned &style, QString &statusIcon, QSet *icons = NULL); + virtual QString resources(void *data); + virtual QString contactTip(void *data); + virtual QWidget *searchWindow(QWidget *parent); + virtual SIM::CommandDef *infoWindows(SIM::Contact *contact, void *data); + virtual QWidget *infoWindow(QWidget *parent, SIM::Contact *contact, void *data, unsigned id); + virtual SIM::CommandDef *configWindows(); + virtual QWidget *configWindow(QWidget *parent, unsigned id); + + void init(); + void sendPacket(); + void startHandshake(); + void connected(); + void handshake(const QString &id); + void rosters_request(); + void setOffline(JabberUserData *data); + + static QString encodeXML(const QString &str); + static QString encodeXMLattr(const QString &str); + QString m_id; + unsigned m_depth; + + QString get_unique_id(); + unsigned m_id_seed; + unsigned m_msg_id; + + bool m_bHTTP; + + void element_start(const QString& el, const QXmlAttributes& attrs); + void element_end(const QString& el); + void char_data(const QString& str); + + list m_listRequests; + ServerRequest *m_curRequest; + + class JabberAuthMessage; + vector tempAuthMessages; + + QString get_icon(JabberUserData *data, unsigned status, bool invisible); + + void processList(); + + void auth_plain(); + void auth_digest(); + void auth_register(); + bool m_bSSL; + bool m_bJoin; + + friend class ServerRequest; + friend class RostersRequest; + friend class PresenceRequest; + friend class JabberBrowser; + +private: +}; + +class JabberFileTransfer : public SIM::FileTransfer, public SIM::ClientSocketNotify, public SIM::ServerSocketNotify +{ +public: + JabberFileTransfer(SIM::FileMessage *msg, JabberUserData *data, JabberClient *client); + ~JabberFileTransfer(); + void listen(); + void connect(); +protected: + JabberClient *m_client; + JabberUserData *m_data; + enum State + { + None, + Listen, + ListenWait, + Header, + Send, + Wait, + Connect, + ReadHeader, + Receive + }; + State m_state; + virtual bool error_state(const QString &err, unsigned code = 0); + virtual void packet_ready(); + virtual void connect_ready(); + virtual void write_ready(); + virtual void startReceive(unsigned pos); + virtual void bind_ready(unsigned short port); + virtual bool error(const QString &err); + virtual bool accept(SIM::Socket *s, unsigned long ip); + bool get_line(const QByteArray &str); + void send_line(const QString &str); + void send_line(const QByteArray &str); + void send_line(const char *str); + unsigned m_startPos; + unsigned m_endPos; + unsigned m_answer; + QString m_url; + JabberClientSocket *m_socket; +}; + +class JabberSearch; + +struct agentRegisterInfo +{ + QString id; + unsigned err_code; + QString error; +}; + +#endif + +// vim: set expandtab: + + diff --git a/plugins/jabber/jabberconfig.cpp b/plugins/jabber/jabberconfig.cpp new file mode 100644 index 0000000..433ea8b --- /dev/null +++ b/plugins/jabber/jabberconfig.cpp @@ -0,0 +1,195 @@ +/*************************************************************************** + jabberconfig.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "simapi.h" + +#include +#include +#include +#include +#include +#include + +#include "simgui/linklabel.h" +#include "misc.h" + +#include "jabberclient.h" +#include "jabberconfig.h" +#include "jabber.h" + +using namespace SIM; + +JabberConfig::JabberConfig(QWidget *parent, JabberClient *client, bool bConfig) : QWidget(parent) + //: JabberConfigBase(parent) +{ + setupUi(this); + m_client = client; + m_bConfig = bConfig; + QTimer::singleShot(0, this, SLOT(changed())); + edtID->setText(m_client->getID()); + edtPasswd->setText(m_client->getPassword()); + edtServer->setText(m_client->getServer()); + edtPort->setValue(m_client->getPort()); + edtPriority->setValue(m_client->getPriority()); + edtResource->setText(m_client->data.owner.Resource.str()); + edtVHost->setText(m_client->data.VHost.str()); + if (m_bConfig){ + tabCfg->removeTab(tabCfg->indexOf(tabJabber)); + }else{ + lblServer->hide(); + edtServer->hide(); + lblPort->hide(); + edtPort->hide(); + chkSSL1->hide(); + edtServer1->setText(i18n("jabber.org")); + edtPort1->setValue(m_client->getPort()); + } + chkSSL->setChecked(m_client->getUseSSL()); + chkSSL1->setChecked(m_client->getUseSSL()); + chkPlain->setChecked(m_client->getUsePlain()); + edtMinPort->setValue(m_client->getMinPort()); + edtMaxPort->setValue(m_client->getMaxPort()); + chkVHost->setChecked(m_client->getUseVHost()); + chkTyping->setChecked(m_client->getTyping()); + chkRichText->setChecked(m_client->getRichText()); + chkIcons->setChecked(m_client->getProtocolIcons()); + chkSubscribe->setChecked(m_client->getAutoSubscribe()); + chkAccept->setChecked(m_client->getAutoAccept()); + chkVersion->setChecked(m_client->getUseVersion()); + lnkPublic->setText(i18n("List of public servers")); + lnkPublic->setUrl("http://www.xmpp.net/servers"); + connect(edtID, SIGNAL(textChanged(const QString&)), this, SLOT(changed(const QString&))); + connect(edtPasswd, SIGNAL(textChanged(const QString&)), this, SLOT(changed(const QString&))); + connect(edtServer, SIGNAL(textChanged(const QString&)), this, SLOT(changed(const QString&))); + connect(edtPort, SIGNAL(valueChanged(const QString&)), this, SLOT(changed(const QString&))); + connect(chkSSL, SIGNAL(toggled(bool)), this, SLOT(toggledSSL(bool))); + connect(chkSSL1, SIGNAL(toggled(bool)), this, SLOT(toggledSSL(bool))); + connect(chkVHost, SIGNAL(toggled(bool)), this, SLOT(toggledVHost(bool))); + chkHTTP->setChecked(m_client->getUseHTTP()); + edtUrl->setText(m_client->getURL()); + edtVHost->setEnabled(m_client->getUseVHost()); +} + +void JabberConfig::apply(Client*, void*) +{ +} + +void JabberConfig::apply() +{ + if (m_bConfig){ + m_client->setServer(edtServer->text()); + m_client->setPort(edtPort->text().toUShort()); + }else{ + m_client->setServer(edtServer1->text()); + m_client->setPort(edtPort1->text().toUShort()); + } + m_client->setUseVHost(false); + if (chkVHost->isChecked()){ + m_client->data.VHost.str() = edtVHost->text(); + if (!edtVHost->text().isEmpty()) + m_client->setUseVHost(true); + } + QString jid = edtID->text(); + int n = jid.indexOf('@'); + if (n >= 0){ + QString host = jid.mid(n + 1); + m_client->data.VHost.str() = host; + m_client->setUseVHost(true); + } else if (chkVHost->isChecked()){ + jid += '@'; + jid += edtVHost->text(); + } else { + jid += '@'; + jid += edtServer1->text(); + } + if (!m_bConfig){ + m_client->setID(jid); + m_client->setPassword(edtPasswd->text()); + m_client->setRegister(chkRegister->isChecked()); + } + if (m_bConfig){ + m_client->setUseSSL(chkSSL1->isChecked()); + }else{ + m_client->setUseSSL(chkSSL->isChecked()); + } + m_client->setUsePlain(chkPlain->isChecked()); + m_client->setMinPort(edtMinPort->text().toUShort()); + m_client->setMaxPort(edtMaxPort->text().toUShort()); + m_client->setTyping(chkTyping->isChecked()); + m_client->setRichText(chkRichText->isChecked()); + m_client->setUseVersion(chkVersion->isChecked()); + m_client->setAutoSubscribe(chkSubscribe->isChecked()); + m_client->setAutoAccept(chkAccept->isChecked()); + if (m_client->getProtocolIcons() != chkIcons->isChecked()){ + m_client->setProtocolIcons(chkIcons->isChecked()); + EventRepaintView e; + e.process(); + } + m_client->data.owner.Resource.str() = edtResource->text(); + m_client->setPriority(edtPriority->text().toLong()); + m_client->setUseHTTP(chkHTTP->isChecked()); + m_client->setURL(edtUrl->text()); +} + +void JabberConfig::toggledSSL(bool bState) +{ + unsigned port = edtPort1->text().toUShort(); + if (m_bConfig) + port = edtPort->text().toUShort(); + if (port == 0) + port = 5222; + if (bState){ + port++; + }else{ + port--; + } + edtPort->setValue(port); + edtPort1->setValue(port); +} + +void JabberConfig::toggledVHost(bool bState) +{ + edtVHost->setEnabled(bState); +} + +void JabberConfig::changed(const QString&) +{ + changed(); +} + +void JabberConfig::changed() +{ + bool bOK = !edtID->text().isEmpty() && + !edtPasswd->text().isEmpty(); + if (bOK){ + if (m_bConfig){ + bOK = !edtServer->text().isEmpty() && + edtPort->text().toUShort(); + }else{ + bOK = !edtServer1->text().isEmpty() && + edtPort1->text().toUShort(); + } + } + emit okEnabled(bOK); +} + +/* +#ifndef NO_MOC_INCLUDES +#include "jabberconfig.moc" +#endif +*/ + diff --git a/plugins/jabber/jabberconfig.h b/plugins/jabber/jabberconfig.h new file mode 100644 index 0000000..d72f5e5 --- /dev/null +++ b/plugins/jabber/jabberconfig.h @@ -0,0 +1,47 @@ +/*************************************************************************** + jabberconfig.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _JABBERCONFIG_H +#define _JABBERCONFIG_H + +#include "ui_jabberconfigbase.h" +#include "event.h" + +class JabberClient; + +class JabberConfig : public QWidget, public Ui::JabberConfigBase +{ + Q_OBJECT +public: + JabberConfig(QWidget *parent, JabberClient *client, bool bConfig); +signals: + void okEnabled(bool); +public slots: + void apply(); + void apply(SIM::Client*, void*); +protected slots: + void changed(); + void changed(const QString&); + void toggledSSL(bool); + void toggledVHost(bool); +protected: + bool m_bConfig; + JabberClient *m_client; +}; + +#endif + diff --git a/plugins/jabber/jabberconfigbase.ui b/plugins/jabber/jabberconfigbase.ui new file mode 100644 index 0000000..5ce00d4 --- /dev/null +++ b/plugins/jabber/jabberconfigbase.ui @@ -0,0 +1,605 @@ + + + JabberConfigBase + + + + 0 + 0 + 388 + 375 + + + + Form1 + + + + 11 + + + + + 0 + + + + &Jabber + + + + 11 + + + + + &Register new account + + + + + + + + + Username: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Password: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + QLineEdit::Password + + + + + + + Server: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Port: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + 1 + + + 65355 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Use &SSL + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + &Network + + + + 11 + + + + + + + Server: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Port: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + 1 + + + 65535 + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + + + + Use &SSL + + + + + + + Use &plain text login + + + + + + + Port range for direct connections: + + + false + + + + + + + + + 1024 + + + 65534 + + + + + + + - + + + false + + + + + + + 1024 + + + 65534 + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + + QFrame::HLine + + + QFrame::Sunken + + + + + + + Use &HTTP polling + + + + + + + + + URL: + + + false + + + + + + + + + + + + + 0 + 0 + + + + Note: For HTTP-polling using proxy settings for HTTP + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + false + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + &Options + + + + 11 + + + + + + + Resource: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Priority: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + + + + Manualy specify Jabber host: + + + + + + + false + + + + + + + + + Enable &typing notification + + + Alt+T + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Lucida Grande'; font-size:13pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://www.xmpp.org/extensions/xep-0022.html"><span style=" text-decoration: underline; color:#0000ff;">(XEP-0022)</span></a></p></body></html> + + + + + + + + + + + Send &rich text messages if possible + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Lucida Grande'; font-size:13pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://www.xmpp.org/extensions/xep-0071.html"><span style=" text-decoration: underline; color:#0000ff;">(XEP-0071)</span></a></p></body></html> + + + + + + + + + + + Send and request version info + + + + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Lucida Grande'; font-size:13pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://www.xmpp.org/extensions/xep-0092.html"><span style=" text-decoration: underline; color:#0000ff;">(XEP-0092)</span></a></p></body></html> + + + + + + + + + Use protocol &icons for agents contacts + + + Alt+I + + + + + + + Automatically send &subscribe request + + + Alt+S + + + + + + + Automatically &accept subscribe requests + + + Alt+A + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + + + + + + LinkLabel + QWidget +
simgui/linklabel.h
+
+
+ + chkRegister + chkSSL + chkPlain + edtMinPort + edtMaxPort + chkVHost + edtVHost + chkIcons + + + simgui/linklabel.h + + + +
diff --git a/plugins/jabber/jabberfiletransfer.cpp b/plugins/jabber/jabberfiletransfer.cpp new file mode 100644 index 0000000..df99915 --- /dev/null +++ b/plugins/jabber/jabberfiletransfer.cpp @@ -0,0 +1,469 @@ +/*************************************************************************** + jabberclient.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "simapi.h" +#include "buffer.h" +#include "log.h" +#include "message.h" +#include "misc.h" + +#include "jabber.h" +#include "jabberclient.h" +#include "jabbermessage.h" + +#include + +#include +#include +#include + +using namespace SIM; +using namespace std; + +JabberFileTransfer::JabberFileTransfer(FileMessage *msg, JabberUserData *data, JabberClient *client) + : FileTransfer(msg) +{ + m_data = data; + m_client = client; + m_state = None; + m_socket = new JabberClientSocket(this); + m_startPos = 0; + m_endPos = 0xFFFFFFFF; +} + +JabberFileTransfer::~JabberFileTransfer() +{ + for (list::iterator it = m_client->m_waitMsg.begin(); it != m_client->m_waitMsg.end(); ++it){ + if ((*it) == m_msg){ + m_client->m_waitMsg.erase(it); + break; + } + } + if (m_socket) + delete m_socket; +} + +void JabberFileTransfer::listen() +{ + if (m_file == NULL){ + for (;;){ + if (!openFile()){ + if (FileTransfer::m_state == FileTransfer::Done) + m_socket->error_state(QString::null); + return; + } + if (!isDirectory()) + break; + } + } + bind(m_client->getMinPort(), m_client->getMaxPort(), m_client); +} + +void JabberFileTransfer::startReceive(unsigned pos) +{ + m_startPos = pos; + JabberFileMessage *msg = static_cast(m_msg); + m_socket->connect(msg->getHost(), msg->getPort(), m_client); + m_state = Connect; + FileTransfer::m_state = FileTransfer::Connect; + if (m_notify) + m_notify->process(); +} + +void JabberFileTransfer::bind_ready(unsigned short port) +{ + if (m_state == None){ + m_state = Listen; + }else{ + m_state = ListenWait; + FileTransfer::m_state = FileTransfer::Listen; + if (m_notify) + m_notify->process(); + } + QString fname = m_file->fileName(); + fname = fname.replace('\\', '/'); + int n = fname.lastIndexOf('/'); + if (n >= 0) + fname = fname.mid(n + 1); + m_url = fname; + m_client->sendFileRequest(m_msg, port, m_data, m_url, m_fileSize); +} + +bool JabberFileTransfer::error(const QString &err) +{ + error_state(err, 0); + return true; +} + +bool JabberFileTransfer::accept(Socket *s, unsigned long) +{ + if (m_state == Listen){ + EventMessageAcked(m_msg).process(); + m_state = ListenWait; + } + log(L_DEBUG, "Accept connection"); + m_startPos = 0; + m_endPos = 0xFFFFFFFF; + m_socket->setSocket(s); + m_socket->readBuffer().init(0); + m_socket->readBuffer().packetStart(); + m_socket->setRaw(true); + m_answer = 400; + return true; +} + +bool JabberFileTransfer::error_state(const QString &err, unsigned) +{ + if (m_state == Wait) + return false; + if (FileTransfer::m_state != FileTransfer::Done){ + m_state = None; + FileTransfer::m_state = FileTransfer::Error; + m_msg->setError(err); + } + m_msg->m_transfer = NULL; + m_msg->setFlags(m_msg->getFlags() & ~MESSAGE_TEMP); + EventMessageSent(m_msg).process(); + return true; +} + +void JabberFileTransfer::packet_ready() +{ + if (m_socket->readBuffer().writePos() == 0) + return; + if (m_state != Receive){ + JabberPlugin *plugin = static_cast(m_client->protocol()->plugin()); + EventLog::log_packet(m_socket->readBuffer(), false, plugin->JabberPacket); + for (;;){ + QByteArray s; + if (!m_socket->readBuffer().scan("\n", s)) + break; + if (!s.isEmpty() && (s[(int)s.length() - 1] == '\r')) + s = s.left(s.length() - 1); + if (!get_line(s)) + break; + } + } + if (m_state == Receive){ + if (m_file == NULL){ + m_socket->error_state(QString::null, 0); + return; + } + unsigned size = m_socket->readBuffer().size() - m_socket->readBuffer().readPos(); + if (size > m_endPos - m_startPos) + size = m_endPos - m_startPos; + if (size){ + m_file->write(m_socket->readBuffer().data(m_socket->readBuffer().readPos()), size); + m_bytes += size; + m_totalBytes += size; + m_startPos += size; + m_transferBytes += size; + if (m_startPos == m_endPos){ + FileTransfer::m_state = FileTransfer::Done; + if (m_notify){ + m_notify->transfer(false); + m_notify->process(); + } + m_socket->error_state(QString::null); + } + if (m_notify) + m_notify->process(); + } + } + if (m_socket->readBuffer().readPos() == m_socket->readBuffer().writePos()) + m_socket->readBuffer().init(0); +} + +void JabberFileTransfer::connect_ready() +{ + JabberFileMessage *msg = static_cast(m_msg); + QString line; + line = "GET /"; + line += msg->getDescription(); + line += " HTTP/1.1\r\n" + "Host :"; + line += msg->getHost(); + line += "\r\n"; + if (m_startPos){ + line += "Range: "; + line += QString::number(m_startPos); + line += "-\r\n"; + } + m_startPos = 0; + m_endPos = 0xFFFFFFFF; + send_line(line); + FileTransfer::m_state = FileTransfer::Negotiation; + m_socket->readBuffer().init(0); + m_socket->readBuffer().packetStart(); + m_socket->setRaw(true); +} + +void JabberFileTransfer::write_ready() +{ + if (m_state != Send){ + ClientSocketNotify::write_ready(); + return; + } + if (m_transfer){ + m_transferBytes += m_transfer; + m_transfer = 0; + if (m_notify) + m_notify->process(); + } + if (m_startPos >= m_endPos){ + if (m_notify) + m_notify->transfer(false); + m_bytes += m_file->size() - m_endPos; + m_totalBytes += m_file->size() - m_endPos; + for (;;){ + if (!openFile()){ + m_state = None; + if (FileTransfer::m_state == FileTransfer::Done) + m_socket->error_state(QString::null); + break; + } + if (isDirectory()) + continue; + m_state = Wait; + FileTransfer::m_state = FileTransfer::Wait; + if (!((Client*)m_client)->send(m_msg, m_data)) + error_state(I18N_NOOP("File transfer failed"), 0); + break; + } + if (m_notify) + m_notify->process(); + m_socket->close(); + return; + } + QDateTime now(QDateTime::currentDateTime()); + if (now != m_sendTime){ + m_sendTime = now; + m_sendSize = 0; + } + if (m_sendSize > (m_speed << 18)){ + m_socket->pause(1); + return; + } + char buf[2048]; + unsigned tail = sizeof(buf); + if (tail > m_endPos - m_startPos) + tail = m_endPos - m_startPos; + int readn = m_file->read(buf, tail); + if (readn <= 0){ + m_socket->error_state("Read file error"); + return; + } + m_startPos += readn; + m_transfer = readn; + m_bytes += readn; + m_totalBytes += readn; + m_sendSize += readn; + m_socket->writeBuffer().pack(buf, readn); + m_socket->write(); +} + +bool JabberFileTransfer::get_line(const QByteArray &str) +{ + QByteArray line = str; + if (line.isEmpty()){ + if (m_state == Connect){ + m_socket->error_state(I18N_NOOP("File transfer failed")); + return true; + } + if (m_state == ReadHeader){ + if (m_endPos < m_startPos) + m_endPos = m_startPos; + if (m_file) + m_file->seek(m_startPos); + m_state = Receive; + FileTransfer::m_state = FileTransfer::Read; + m_bytes += m_startPos; + m_totalBytes += m_startPos; + m_fileSize = m_endPos; + m_totalSize = m_endPos; + if (m_notify){ + m_notify->process(); + m_notify->transfer(true); + } + return true; + } + if (m_file->size() < m_endPos) + m_endPos = m_file->size(); + if (m_startPos > m_endPos) + m_startPos = m_endPos; + if ((m_answer == 200) && (m_startPos == m_endPos)) + m_answer = 204; + if ((m_answer == 200) && ((m_startPos != 0) || (m_endPos < m_file->size()))) + m_answer = 206; + QString s; + s = "HTTP/1.0 "; + s += QString::number(m_answer); + switch (m_answer){ + case 200: + s += " OK"; + break; + case 204: + s += " No content"; + break; + case 206: + s += " Partial content"; + break; + case 400: + s += " Bad request"; + break; + case 404: + s += " Not found"; + break; + default: + s += " Error"; + } + send_line(s); + if ((m_answer == 200) || (m_answer == 206)){ + send_line("Content-Type: application/data"); + s = "Content-Length: "; + s += QString::number(m_endPos - m_startPos); + send_line(s); + } + if (m_answer == 206){ + s = "Range: "; + s += QString::number(m_startPos); + s += '-'; + s += QString::number(m_endPos); + send_line(s); + } + send_line(""); + if (m_answer < 300){ + m_file->seek(m_startPos); + FileTransfer::m_state = FileTransfer::Write; + m_state = Send; + m_bytes = m_startPos; + m_totalBytes += m_startPos; + if (m_notify){ + m_notify->process(); + m_notify->transfer(true); + } + write_ready(); + }else{ + m_socket->error_state("Bad request"); + } + return false; + } + if (m_state == ListenWait){ + QByteArray t = getToken(line, ' '); + if (t == "GET"){ + m_answer = 404; + t = getToken(line, ' '); + if (t[0] == '/'){ + if (m_url == QString::fromUtf8((t.data() + 1))) + m_answer = 200; + } + } + m_state = Header; + return true; + } + if (m_state == Connect){ + QByteArray t = getToken(line, ' '); + t = getToken(t, '/'); + if (t != "HTTP"){ + m_socket->error_state(I18N_NOOP("File transfer fail")); + return true; + } + unsigned code = getToken(line, ' ').toUInt(); + switch (code){ + case 200: + case 206: + m_startPos = 0; + m_endPos = 0xFFFFFFFF; + break; + case 204: + m_startPos = 0; + m_endPos = 0; + break; + } + m_state = ReadHeader; + return true; + } + if (m_state == ReadHeader){ + QByteArray t = getToken(line, ':'); + if (t == "Content-Length"){ + const char *p; + for (p = line.data(); *p; p++) + if ((*p > '0') && (*p < '9')) + break; + m_endPos = m_startPos + strtoul(p, NULL, 10); + } + if (t == "Range"){ + const char *p; + for (p = line.data(); *p; p++) + if ((*p > '0') && (*p < '9')) + break; + m_startPos = strtoul(p, NULL, 10); + for (; *p; p++) + if (*p == '-'){ + ++p; + break; + } + if ((*p > '0') && (*p < '9')) + m_endPos = m_startPos + strtoul(p, NULL, 10); + } + return true; + } + QByteArray t = getToken(line, ':'); + if (t == "Range"){ + const char *p = line.data(); + for (; *p; p++) + if (*p != ' ') + break; + m_startPos = strtoul(p, NULL, 10); + for (; *p; p++) + if (*p == '-'){ + p++; + break; + } + if ((*p >= '0') && (*p <= '9')) + m_endPos = strtoul(p, NULL, 10); + } + return true; +} + +void JabberFileTransfer::send_line(const QString &line) +{ + send_line(line.toUtf8().data()); +} + +void JabberFileTransfer::send_line(const QByteArray &line) +{ + send_line(line.data()); +} + +void JabberFileTransfer::send_line(const char *line) +{ + m_socket->writeBuffer().packetStart(); + m_socket->writeBuffer() << line << "\r\n"; + JabberPlugin *plugin = static_cast(m_client->protocol()->plugin()); + EventLog::log_packet(m_socket->writeBuffer(), true, plugin->JabberPacket); + m_socket->write(); +} + +void JabberFileTransfer::connect() +{ + m_nFiles = 1; + if (static_cast(m_msg)->getPort() == 0) + m_client->sendFileAccept(m_msg, m_data); + if (m_notify) + m_notify->createFile(m_msg->getDescription(), 0xFFFFFFFF, false); +} diff --git a/plugins/jabber/jabberhomeinfo.cpp b/plugins/jabber/jabberhomeinfo.cpp new file mode 100644 index 0000000..810ae2e --- /dev/null +++ b/plugins/jabber/jabberhomeinfo.cpp @@ -0,0 +1,102 @@ +/*************************************************************************** + jabberhomeinfo.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "jabberclient.h" +#include "jabberhomeinfo.h" +#include "jabber.h" +#include "contacts/contact.h" + +#include +#include + +using namespace SIM; + +JabberHomeInfo::JabberHomeInfo(QWidget *parent, JabberUserData *data, JabberClient *client) : QWidget(parent) + //: JabberHomeInfoBase(parent) +{ + setupUi(this); + m_client = client; + m_data = data; + if (m_data){ + edtStreet->setReadOnly(true); + edtExt->setReadOnly(true); + edtCity->setReadOnly(true); + edtState->setReadOnly(true); + edtZip->setReadOnly(true); + edtCountry->setReadOnly(true); + } + fill(m_data); +} + +void JabberHomeInfo::apply() +{ +} + +bool JabberHomeInfo::processEvent(Event *e) +{ + if (e->type() == eEventContact){ + EventContact *ec = static_cast(e); + if(ec->action() != EventContact::eChanged) + return false; + Contact *contact = ec->contact(); + if (contact->clientData.have(m_data)) + fill(m_data); + } else + if ((e->type() == eEventClientChanged) && (m_data == 0)){ + EventClientChanged *ecc = static_cast(e); + if (ecc->client() == m_client) + fill(m_data); + } else + if (m_data && (e->type() == eEventVCard)){ + EventVCard *evc = static_cast(e); + JabberUserData *data = evc->data(); + if (m_data->ID.str() == data->ID.str() && m_data->Node.str() == data->Node.str()) + fill(data); + } + return false; +} + +void JabberHomeInfo::fill(JabberUserData *data) +{ + if (data == NULL) data = &m_client->data.owner; + edtStreet->setPlainText(data->Street.str()); + edtExt->setPlainText(data->ExtAddr.str()); + edtCity->setText(data->City.str()); + edtState->setText(data->Region.str()); + edtZip->setText(data->PCode.str()); + edtCountry->setText(data->Country.str()); +} + +void JabberHomeInfo::apply(Client *client, void *_data) +{ + if (client != m_client) + return; + JabberUserData *data = m_client->toJabberUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + data->Street.str() = edtStreet->toPlainText(); + data->ExtAddr.str() = edtExt->toPlainText(); + data->City.str() = edtCity->text(); + data->Region.str() = edtState->text(); + data->PCode.str() = edtZip->text(); + data->Country.str() = edtCountry->text(); +} + +/* +#ifndef NO_MOC_INCLUDES +#include "jabberhomeinfo.moc" +#endif +*/ + diff --git a/plugins/jabber/jabberhomeinfo.h b/plugins/jabber/jabberhomeinfo.h new file mode 100644 index 0000000..cdb53c5 --- /dev/null +++ b/plugins/jabber/jabberhomeinfo.h @@ -0,0 +1,43 @@ +/*************************************************************************** + jabberhomeinfo.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _JABBERHOMEINFO_H +#define _JABBERHOMEINFO_H + +#include "ui_jabberhomeinfobase.h" +#include "event.h" + +struct JabberUserData; +class JabberClient; + +class JabberHomeInfo : public QWidget, public Ui::LocationInfo, public SIM::EventReceiver +{ + Q_OBJECT +public: + JabberHomeInfo(QWidget *parent, JabberUserData *data, JabberClient *client); +public slots: + void apply(); + void apply(SIM::Client*, void*); +protected: + virtual bool processEvent(SIM::Event *e); + void fill(JabberUserData *data); + JabberUserData *m_data; + JabberClient *m_client; +}; + +#endif + diff --git a/plugins/jabber/jabberhomeinfobase.ui b/plugins/jabber/jabberhomeinfobase.ui new file mode 100644 index 0000000..ee0386d --- /dev/null +++ b/plugins/jabber/jabberhomeinfobase.ui @@ -0,0 +1,126 @@ + + + LocationInfo + + + + 0 + 0 + 409 + 283 + + + + Form2 + + + + 11 + + + 6 + + + + + + + + + + + + + + + + + City: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + Zip code: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + Country: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + State: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + Address: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + + + + + + + diff --git a/plugins/jabber/jabberinfo.cpp b/plugins/jabber/jabberinfo.cpp new file mode 100644 index 0000000..2417e20 --- /dev/null +++ b/plugins/jabber/jabberinfo.cpp @@ -0,0 +1,261 @@ +/*************************************************************************** + jabberinfo.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include "icons.h" +#include "misc.h" + +#include "contacts/contact.h" +#include "simgui/ballonmsg.h" +#include "simgui/datepicker.h" + +#include "jabberclient.h" +#include "jabberinfo.h" + +using namespace SIM; + +JabberInfo::JabberInfo(QWidget *parent, JabberUserData *data, JabberClient *client) : QWidget(parent) +{ + setupUi(this); + m_client = client; + m_data = data; + btnUrl->setWindowIcon(Icon("home")); + connect(btnUrl, SIGNAL(clicked()), this, SLOT(goUrl())); + edtOnline->setReadOnly(true); + edtNA->setReadOnly(true); + edtID->setReadOnly(true); + edtClient->setReadOnly(true); + if (m_data){ + edtFirstName->setReadOnly(true); + edtNick->setReadOnly(true); + disableWidget(edtDate); + edtUrl->setReadOnly(true); + edtAutoReply->setReadOnly(true); + tabWnd->removeTab(tabWnd->indexOf(password)); + }else{ + connect(edtUrl, SIGNAL(textChanged(const QString&)), this, SLOT(urlChanged(const QString&))); + connect(this, SIGNAL(raise(QWidget*)), topLevelWidget(), SLOT(raisePage(QWidget*))); + edtAutoReply->hide(); + } + fill(); + connect(cmbResource, SIGNAL(activated(int)), this, SLOT(resourceActivated(int))); +} + +void JabberInfo::apply() +{ + if ((m_data == NULL) && (m_client->getState() == Client::Connected)){ + QString errMsg; + QWidget *errWidget = edtCurrent; + if (!edtPswd1->text().isEmpty() || !edtPswd2->text().isEmpty()){ + if (edtCurrent->text().isEmpty()){ + errMsg = i18n("Input current password"); + }else{ + if (edtPswd1->text() != edtPswd2->text()){ + errMsg = i18n("Confirm password does not match"); + errWidget = edtPswd2; + }else if (edtCurrent->text() != m_client->getPassword()){ + errMsg = i18n("Invalid password"); + } + } + } + if (!errMsg.isEmpty()){ + for (QWidget *p = parentWidget(); p; p = p->parentWidget()){ + QTabWidget *tb = qobject_cast(p); + if (!tb) + continue; + tb->setCurrentIndex(tb->indexOf(this)); + break; + } + emit raise(this); + BalloonMsg::message(errMsg, errWidget); + return; + } + if (!edtPswd1->text().isEmpty()) + m_client->changePassword(edtPswd1->text()); + // clear Textboxes + edtCurrent->clear(); + edtPswd1->clear(); + edtPswd2->clear(); + } +} + +void JabberInfo::resourceActivated(int i) +{ + JabberUserData *data = m_data; + if (data == NULL) data = &m_client->data.owner; + unsigned n = i + 1; + unsigned status = STATUS_OFFLINE; + unsigned statusTime; + unsigned onlineTime; + QString autoReply; + QString clientName, clientVersion, clientOS; + if ((n == 0) || (n > data->nResources.toULong())){ + status = m_data ? m_data->Status.toULong() : m_client->getStatus(); + statusTime = data->StatusTime.toULong(); + onlineTime = data->OnlineTime.toULong(); + }else{ + status = get_str(data->ResourceStatus, n).toUInt(); + statusTime = get_str(data->ResourceStatusTime, n).toUInt(); + onlineTime = get_str(data->ResourceOnlineTime, n).toUInt(); + autoReply = get_str(data->ResourceReply, n); + clientName = get_str(data->ResourceClientName, n); + clientVersion = get_str(data->ResourceClientVersion, n); + clientOS = get_str(data->ResourceClientOS, n); + } + int current = 0; + const char *text = NULL; + for (const CommandDef *cmd = m_client->protocol()->statusList(); cmd->id; cmd++){ + if (cmd->flags & COMMAND_CHECK_STATE) + continue; + if (status == cmd->id){ + current = cmbStatus->count(); + text = cmd->text.toLocal8Bit().data(); + } + cmbStatus->addItem(Icon(cmd->icon), i18n(cmd->text)); + } + cmbStatus->setCurrentIndex(current); + disableWidget(cmbStatus); + if (status == STATUS_OFFLINE){ + lblOnline->setText(i18n("Last online") + ':'); + edtOnline->setText(formatDateTime(statusTime)); + lblOnline->show(); + edtOnline->show(); + lblNA->hide(); + edtNA->hide(); + }else{ + if (onlineTime){ + edtOnline->setText(formatDateTime(onlineTime)); + lblOnline->show(); + edtOnline->show(); + }else{ + lblOnline->hide(); + edtOnline->hide(); + } + if ((status == STATUS_ONLINE) || (text == NULL)){ + lblNA->hide(); + edtNA->hide(); + }else{ + lblNA->setText(i18n(text)); + edtNA->setText(formatDateTime(statusTime)); + lblNA->show(); + edtNA->show(); + } + } + if (autoReply.isEmpty()){ + edtAutoReply->hide(); + }else{ + edtAutoReply->show(); + edtAutoReply->setPlainText(autoReply); + } + if (clientName.isEmpty()){ + edtClient->setEnabled(false); + }else{ + edtClient->setEnabled(true); + QString clientString = clientName + ' ' + clientVersion; + if (!clientOS.isEmpty()) + clientString += " / " + clientOS; + edtClient->setText(clientString); + } +} + +bool JabberInfo::processEvent(Event *e) +{ + if ((e->type() == eEventMessageReceived) && m_data){ + EventMessage *em = static_cast(e); + Message *msg = em->msg(); + if ((msg->type() == MessageStatus) && (m_client->dataName(m_data) == msg->client())) + fill(); + } else + if (e->type() == eEventContact){ + EventContact *ec = static_cast(e); + if(ec->action() != EventContact::eChanged) + return false; + Contact *contact = ec->contact(); + if (contact->clientData.have(m_data)) + fill(); + } else + if ((e->type() == eEventClientChanged) && (m_data == 0)){ + EventClientChanged *ecc = static_cast(e); + if (ecc->client() == m_client) + fill(); + } + return false; +} + +void JabberInfo::fill() +{ + JabberUserData *data = m_data; + if (data == NULL) data = &m_client->data.owner; + edtID->setText(data->ID.str()); + edtFirstName->setText(data->FirstName.str()); + edtNick->setText(data->Nick.str()); + edtDate->setDate(QDate::fromString(data->Bday.str(), Qt::ISODate)); + edtUrl->setText(data->Url.str()); + urlChanged(edtUrl->text()); + cmbResource->clear(); + if (data->nResources.toULong()){ + for (unsigned i = 1; i <= data->nResources.toULong(); i++) + cmbResource->addItem(get_str(data->Resources, i)); + cmbResource->setEnabled(data->nResources.toULong() > 1); + }else{ + if (!data->Resource.str().isEmpty()) + cmbResource->addItem(data->Resource.str()); + cmbResource->setEnabled(false); + } + resourceActivated(0); + if (m_data == NULL) + password->setEnabled(m_client->getState() == Client::Connected); +} + +void JabberInfo::apply(Client *client, void *_data) +{ + if (client != m_client) + return; + JabberUserData *data = m_client->toJabberUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + data->FirstName.str() = edtFirstName->text(); + data->Nick.str() = edtNick->text(); + data->Bday.str() = edtDate->getDate().toString(Qt::ISODate); + data->Url.str() = edtUrl->text(); +} + +void JabberInfo::goUrl() +{ + QString url = edtUrl->text(); + if (url.isEmpty()) + return; + EventGoURL e(url); + e.process(); +} + +void JabberInfo::urlChanged(const QString &text) +{ + btnUrl->setEnabled(!text.isEmpty()); +} + +/* +#ifndef NO_MOC_INCLUDES +#include "jabberinfo.moc" +#endif +*/ + diff --git a/plugins/jabber/jabberinfo.h b/plugins/jabber/jabberinfo.h new file mode 100644 index 0000000..5d21253 --- /dev/null +++ b/plugins/jabber/jabberinfo.h @@ -0,0 +1,48 @@ +/*************************************************************************** + jabberinfo.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _JABBERINFO_H +#define _JABBERINFO_H + +#include "ui_jabberinfobase.h" +#include "event.h" + +struct JabberUserData; +class JabberClient; + +class JabberInfo : public QWidget, public Ui::JabberInfo, public SIM::EventReceiver +{ + Q_OBJECT +public: + JabberInfo(QWidget *parent, JabberUserData *data, JabberClient *client); +signals: + void raise(QWidget*); +public slots: + void apply(); + void apply(SIM::Client*, void*); + void goUrl(); + void urlChanged(const QString&); + void resourceActivated(int); +protected: + virtual bool processEvent(SIM::Event *e); + void fill(); + JabberUserData *m_data; + JabberClient *m_client; +}; + +#endif + diff --git a/plugins/jabber/jabberinfobase.ui b/plugins/jabber/jabberinfobase.ui new file mode 100644 index 0000000..b3d790a --- /dev/null +++ b/plugins/jabber/jabberinfobase.ui @@ -0,0 +1,441 @@ + + + JabberInfo + + + + 0 + 0 + 400 + 301 + + + + Form1 + + + + 6 + + + 11 + + + + + + &Names + + + + 11 + + + 6 + + + + + + 75 + true + + + + ID: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + 75 + true + + + + + + + + QFrame::HLine + + + QFrame::Sunken + + + + + + + First Name: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Nick: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + Birth date: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + Homepage: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + 6 + + + 0 + + + + + + + + + + + + + + + + + 6 + + + 0 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + + + &Status + + + + + + Status: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + 0 + 0 + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 16 + + + + + + + + Resource: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Online: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Client: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + + + + + &Password + + + + 11 + + + 6 + + + + + New password: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + QLineEdit::Password + + + + + + + QLineEdit::Password + + + + + + + Retype new password: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + QFrame::HLine + + + QFrame::Sunken + + + + + + + Current password: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + QLineEdit::Password + + + + + + + + + + + + + DatePicker + QWidget +
simgui/datepicker.h
+
+
+ + tabWnd + edtID + edtFirstName + edtNick + edtUrl + btnUrl + cmbStatus + cmbResource + edtOnline + edtNA + + + simgui/datepicker.h + + + +
diff --git a/plugins/jabber/jabbermessage.cpp b/plugins/jabber/jabbermessage.cpp new file mode 100644 index 0000000..00a86f0 --- /dev/null +++ b/plugins/jabber/jabbermessage.cpp @@ -0,0 +1,243 @@ +/*************************************************************************** + jabbermessage.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "jabbermessage.h" +#include "jabber.h" +#include "core.h" + +#include + +using namespace SIM; + +static DataDef jabberMessageData[] = + { + { "Subject", DATA_UTF, 1, 0 }, + { NULL, DATA_UNKNOWN, 0, 0 } + }; + +JabberMessage::JabberMessage(Buffer *cfg) + : Message(MessageJabber, cfg) +{ + load_data(jabberMessageData, &data, cfg); +} + +JabberMessage::~JabberMessage() +{ + free_data(jabberMessageData, &data); +} + +QByteArray JabberMessage::save() +{ + QByteArray res = Message::save(); + QByteArray s = save_data(jabberMessageData, &data); + if (!s.isEmpty()){ + if (!res.isEmpty()) + res += '\n'; + res += s; + } + return res; +} + +QString JabberMessage::presentation() +{ + QString res = i18n("

Subject: %1

") + .arg(getSubject()); + res += Message::presentation(); + return res; +} + +static Message *createJabberMessage(Buffer *cfg) +{ + return new JabberMessage(cfg); +} + +static MessageDef defJabber = + { + NULL, + NULL, + MESSAGE_DEFAULT, + NULL, + NULL, + createJabberMessage, + NULL, + NULL + }; + +static DataDef jabberMessageErrorData[] = + { + { "Error", DATA_UTF, 1, 0 }, + { "Code", DATA_ULONG, 1, 0 }, + { NULL, DATA_UNKNOWN, 0, 0 } + }; + +JabberMessageError::JabberMessageError(Buffer *cfg) + : Message(MessageJabberError, cfg) +{ + load_data(jabberMessageErrorData, &data, cfg); +} + +JabberMessageError::~JabberMessageError() +{ + free_data(jabberMessageErrorData, &data); +} + +QByteArray JabberMessageError::save() +{ + QByteArray res = Message::save(); + QByteArray s = save_data(jabberMessageErrorData, &data); + if (!s.isEmpty()){ + if (!res.isEmpty()) + res += '\n'; + res += s; + } + return res; +} + +QString JabberMessageError::presentation() +{ + QString res = "

"; + res += i18n("Error"); + if (getCode()){ + res += ' '; + res += QString::number(getCode()); + } + QString err = getError(); + if (!err.isEmpty()){ + res += ": "; + res += err; + res += ""; + } + res += "
"; + res += i18n("Original message:"); + res += "

"; + res += Message::presentation(); + return res; +} + +static Message *createJabberMessageError(Buffer *cfg) +{ + return new JabberMessageError(cfg); +} + +#if 0 +i18n("Error", "%n errors", 1); +#endif + +static MessageDef defJabberError = + { + NULL, + NULL, + MESSAGE_DEFAULT, + "Error", + "%n errors", + createJabberMessageError, + NULL, + NULL + }; + +static Message *createJabberOnlineMessage(Buffer *cfg) +{ + return new AuthMessage(MessageJabberOnline, cfg); +} + +static MessageDef defJabberOnline = + { + NULL, + NULL, + MESSAGE_SILENT | MESSAGE_SENDONLY, + I18N_NOOP("Log On"), + NULL, + createJabberOnlineMessage, + NULL, + NULL + }; + +static Message *createJabberOfflineMessage(Buffer *cfg) +{ + return new AuthMessage(MessageJabberOffline, cfg); +} + +static MessageDef defJabberOffline = + { + NULL, + NULL, + MESSAGE_SILENT | MESSAGE_SENDONLY, + I18N_NOOP("Log Off"), + NULL, + createJabberOfflineMessage, + NULL, + NULL + }; + +static DataDef jabberMessageFileData[] = + { + { "", DATA_STRING, 1, 0 }, // ID + { "", DATA_STRING, 1, 0 }, + { "", DATA_STRING, 1, 0 }, // Host + { "", DATA_ULONG, 1, 0 }, // Port + { NULL, DATA_UNKNOWN, 0, 0 } + }; + +JabberFileMessage::JabberFileMessage(Buffer *cfg) + : FileMessage(MessageFile, cfg) +{ + load_data(jabberMessageFileData, &data, cfg); +} + +JabberFileMessage::~JabberFileMessage() +{ + free_data(jabberMessageFileData, &data); +} + +void JabberPlugin::registerMessages() +{ + Command cmd; + cmd->id = MessageJabber; + cmd->text = "Jabber"; + cmd->icon = "message"; + cmd->flags = COMMAND_DEFAULT; + cmd->param = &defJabber; + EventCreateMessageType(cmd).process(); + + cmd->id = MessageJabberOnline; + cmd->text = I18N_NOOP("Log On"); + cmd->icon = "Jabber_online"; + cmd->menu_grp = 0x3020; + cmd->param = &defJabberOnline; + EventCreateMessageType(cmd).process(); + + cmd->id = MessageJabberOffline; + cmd->text = I18N_NOOP("Log Off"); + cmd->icon = "Jabber_offline"; + cmd->param = &defJabberOffline; + EventCreateMessageType(cmd).process(); + + cmd->id = MessageJabberError; + cmd->text = I18N_NOOP("Error"); + cmd->icon = "error"; + cmd->param = &defJabberError; + EventCreateMessageType(cmd).process(); +} + +void JabberPlugin::unregisterMessages() +{ + EventRemoveMessageType(MessageJabber).process(); + EventRemoveMessageType(MessageJabberOnline).process(); + EventRemoveMessageType(MessageJabberOffline).process(); + EventRemoveMessageType(MessageJabberError).process(); +} + diff --git a/plugins/jabber/jabbermessage.h b/plugins/jabber/jabbermessage.h new file mode 100644 index 0000000..b069dae --- /dev/null +++ b/plugins/jabber/jabbermessage.h @@ -0,0 +1,91 @@ +/*************************************************************************** + jabbermessage.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _JABBERMESSAGE_H +#define _JABBERMESSAGE_H + +#include "cfg.h" +#include "message.h" + +#include + +const unsigned long MessageJabber = 0x201; +const unsigned long MessageJabberOnline = 0x202; +const unsigned long MessageJabberOffline = 0x203; +const unsigned long MessageJabberError = 0x204; + +struct JabberMessageData +{ + SIM::Data Subject; +}; + +class JabberMessage : public SIM::Message +{ +public: + JabberMessage(Buffer *cfg = NULL); + ~JabberMessage(); + PROP_UTF8(Subject); + virtual QByteArray save(); + virtual QString presentation(); + virtual unsigned baseType() { return SIM::MessageGeneric; } +protected: + JabberMessageData data; +}; + +struct JabberMessageErrorData +{ + SIM::Data Error; + SIM::Data Code; +}; + +class JabberMessageError : public SIM::Message +{ +public: + JabberMessageError(Buffer *cfg = NULL); + ~JabberMessageError(); + PROP_UTF8(Error); + PROP_ULONG(Code); + virtual QByteArray save(); + virtual QString presentation(); +protected: + JabberMessageErrorData data; +}; + +struct JabberMessageFileData +{ + SIM::Data ID; + SIM::Data From; + SIM::Data Host; + SIM::Data Port; +}; + +class JabberFileMessage : public SIM::FileMessage +{ +public: + JabberFileMessage(Buffer *cfg = NULL); + ~JabberFileMessage(); + PROP_STR(ID); + PROP_STR(From); + PROP_STR(Host); + PROP_USHORT(Port); + virtual unsigned baseType() { return SIM::MessageFile; } +protected: + JabberMessageFileData data; +}; + +#endif + diff --git a/plugins/jabber/jabberpicture.cpp b/plugins/jabber/jabberpicture.cpp new file mode 100644 index 0000000..ff922cb --- /dev/null +++ b/plugins/jabber/jabberpicture.cpp @@ -0,0 +1,178 @@ +/*************************************************************************** + jabberpicture.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "simapi.h" + +#include +#include +#include +#include +#include +#include + +#include "misc.h" + +#include "contacts/contact.h" +#include "simgui/ballonmsg.h" +#include "simgui/editfile.h" +#include "simgui/preview.h" + +#include "jabberclient.h" +#include "jabberpicture.h" + +using namespace SIM; + +#ifndef USE_KDE + +static FilePreview *createPreview(QWidget *parent) +{ + return new PictPreview(parent); +} + +#endif + +JabberPicture::JabberPicture(QWidget *parent, JabberUserData *data, JabberClient *client, bool bPhoto) : QWidget(parent) + //: JabberPictureBase(parent) +{ + setupUi(this); + m_data = data; + m_client = client; + m_bPhoto = bPhoto; + tabPict->setTabText(tabPict->indexOf(tab), m_bPhoto ? i18n("&Photo") : i18n("&Logo")); + if (m_data){ + edtPict->hide(); + btnClear->hide(); + }else{ + QString format = "*.bmp *.gif *.jpg *.jpeg"; +#ifdef USE_KDE + edtPict->setFilter(i18n("%1|Graphics") .arg(format)); +#else +edtPict->setFilter(i18n("Graphics(%1)") .arg(format)); + edtPict->setFilePreview(createPreview); +#endif + edtPict->setReadOnly(true); + connect(btnClear, SIGNAL(clicked()), this, SLOT(clearPicture())); + connect(edtPict, SIGNAL(textChanged(const QString&)), this, SLOT(pictSelected(const QString&))); + QString pict = m_bPhoto ? client->getPhoto() : client->getLogo(); + edtPict->setText(pict); + pictSelected(pict); + } + fill(); +} + +void JabberPicture::apply() +{ +} + +void JabberPicture::apply(Client *client, void*) +{ + if (client != m_client) + return; + QString pict = edtPict->text(); + if (lblPict->pixmap() == NULL) + pict = QString::null; + if (m_bPhoto){ + m_client->setPhoto(pict); + }else{ + m_client->setLogo(pict); + } +} + +bool JabberPicture::processEvent(Event *e) +{ + if (e->type() == eEventContact){ + EventContact *ec = static_cast(e); + if(ec->action() != EventContact::eChanged) + return false; + Contact *contact = ec->contact(); + if (contact->clientData.have(m_data)) + fill(); + } + return false; +} + +void JabberPicture::fill() +{ + if (m_data == NULL) + return; + if (m_bPhoto){ + if (m_data->PhotoHeight.toLong() && m_data->PhotoWidth.toLong()){ + QImage img(m_client->photoFile(m_data)); + setPict(img); + return; + } + }else{ + if (m_data->LogoHeight.toLong() && m_data->LogoWidth.toLong()){ + QImage img(m_client->logoFile(m_data)); + setPict(img); + return; + } + } + QImage img; + setPict(img); +} + +void JabberPicture::clearPicture() +{ + edtPict->setText(QString::null); +} + +void JabberPicture::pictSelected(const QString &file) +{ + if (file.isEmpty()){ + QImage img; + setPict(img); + return; + } + QFile f(file); + QImage img(file); + setPict(img); +} + +void JabberPicture::setPict(QImage &img) +{ + if (img.isNull()){ + lblPict->setText(i18n("Picture is not available")); + return; + } + int w = img.width(); + int h = img.height(); + if (h > w){ + if (h > 300){ + w = w * 300 / h; + h = 300; + } + }else{ + if (w > 300){ + h = h * 300 / w; + w = 300; + } + } + if ((w != img.width()) || (h != img.height())) + img = img.scaled(w, h, Qt::KeepAspectRatio, Qt::SmoothTransformation); + QPixmap pict; + pict = QPixmap::fromImage(img); + lblPict->setPixmap(pict); + lblPict->setMinimumSize(pict.size()); +} + +/* +#ifndef NO_MOC_INCLUDES +#include "jabberpicture.moc" +#endif +*/ + diff --git a/plugins/jabber/jabberpicture.h b/plugins/jabber/jabberpicture.h new file mode 100644 index 0000000..c7f75e3 --- /dev/null +++ b/plugins/jabber/jabberpicture.h @@ -0,0 +1,50 @@ +/*************************************************************************** + jabberpicture.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _JABBERPICTURE_H +#define _JABBERPICTURE_H + +#include "ui_jabberpicturebase.h" +#include "event.h" + +struct JabberUserData; +class JabberClient; + +class QImage; + +class JabberPicture : public QWidget, public Ui::JabberPictureBase, public SIM::EventReceiver +{ + Q_OBJECT +public: + JabberPicture(QWidget *parent, JabberUserData *data, JabberClient *client, bool bPhoto); +public slots: + void apply(); + void apply(SIM::Client*, void*); +protected slots: + void clearPicture(); + void pictSelected(const QString&); +protected: + virtual bool processEvent(SIM::Event *e); + void fill(); + void setPict(QImage &img); + bool m_bPhoto; + JabberUserData *m_data; + JabberClient *m_client; +}; + +#endif + diff --git a/plugins/jabber/jabberpicturebase.ui b/plugins/jabber/jabberpicturebase.ui new file mode 100644 index 0000000..3af8f28 --- /dev/null +++ b/plugins/jabber/jabberpicturebase.ui @@ -0,0 +1,123 @@ + + + + + JabberPictureBase + + + + 0 + 0 + 460 + 324 + + + + Form1 + + + + 11 + + + 6 + + + + + + &Photo + + + + 11 + + + 6 + + + + + + 7 + 7 + + + + + + + Qt::AlignCenter + + + false + + + + + + + &Clear + + + + + + + + 7 + 5 + + + + + + + + + + + + + EditFile + QWidget +
simgui/editfile.h
+ + -1 + -1 + + 0 + + 5 + 5 + + image0 +
+ + QWidget + QWidget +
QWidget
+ + -1 + -1 + + 0 + + 5 + 5 + + image1 + + text + +
+
+ + + 789c6dd2c10ac2300c00d07bbf2234b7229d1ddec44f503c0ae2a154410f53d0ed20e2bf6bdb656dd6861dd23d9a66591b0587fd1654235ebded6f0edcd53e419d87ae7b1f4f9b8f906d0bfe012317426a70b07bdc2f3ec77f8ed6b89559061a0343d06a124cc105596482585094bc0ae599b04646c9018926491b2205e140c485cace25755c175d0a967b622ff900b8cc9c7d29af594ea722d589167f813aa852ba07d94b9dce296e883fe7bb163f23896753 + + + 789c6dd2c10ac2300c00d07bbf2234b7229d1be245fc04c5a3201e4615f430059d0711ff5ddb2e6bb236ec90eed134cb5a19d8ef36602af5ecdbfeeac05dda0798d3abebde87e3faa374d3807fa0d633a52d38d8de6f679fe33fc776e196f53cd010188256a3600a292882096246517815ca99884606e18044a3a40d91824820924265a7923a2e8bcd05f33db1173e002913175f2a6be6d3294871a2d95fa00e8a94ee017b69d339d90df1e77c57ea072ede6758 + + +
diff --git a/plugins/jabber/jabbersearch.cpp b/plugins/jabber/jabbersearch.cpp new file mode 100644 index 0000000..4b9fd19 --- /dev/null +++ b/plugins/jabber/jabbersearch.cpp @@ -0,0 +1,721 @@ +/*************************************************************************** + jabbersearch.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "simgui/ballonmsg.h" +#include "icons.h" +#include "misc.h" + +#include "jabberclient.h" +#include "jabbersearch.h" +#include "jabber.h" +#include "jidadvsearch.h" + +using namespace std; +using namespace SIM; + +class CComboBox : public QComboBox +{ +public: + CComboBox(QWidget *parent, const char *name); + void addItem(const QString &label, const QString &value); + QString value(); +protected: + vector m_values; +}; + +CComboBox::CComboBox(QWidget *parent, const char *name) + : QComboBox(parent) +{ + setObjectName(name); + setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); +} + +void CComboBox::addItem(const QString &label, const QString &value) +{ + m_values.push_back(value); + insertItem(INT_MAX,label); +} + +QString CComboBox::value() +{ + unsigned index = currentIndex(); + if (index >= m_values.size()) + return QString::null; + return m_values[index]; +} + +const unsigned MAX_ELEMENTS = 8; + +JabberSearch::JabberSearch(QWidget *parent, const char *name) + : QWizardPage(parent) + , m_vlay(NULL) + , m_lay(NULL) +{ +} + +void JabberSearch::init(QWidget *receiver, JabberClient *client, const QString &jid, const QString &node, const QString &name, bool bRegister) +{ + m_client = client; + m_jid = jid; + m_node = node; + m_name = name; + m_receiver = receiver; + m_bXData = false; + m_bFirst = true; + m_bRegister = bRegister; + m_bDirty = false; +} + +struct defFlds +{ + const char *tag; + const char *name; + bool bRequired; +}; + +static defFlds fields[] = + { + { "username", I18N_NOOP("Username"), true }, + { "nick", I18N_NOOP("Nick"), false }, + { "email", I18N_NOOP("EMail"), false }, + { "first", I18N_NOOP("First Name"), false }, + { "last", I18N_NOOP("Last Name"), false }, + { "age_min", I18N_NOOP("Age min"), false }, + { "age_max", I18N_NOOP("Age max"), false }, + { "city", I18N_NOOP("City"), false }, + { NULL, NULL, false } + }; + +void JabberSearch::addWidget(JabberAgentInfo *data) +{ + QWidget *widget = NULL; + bool bJoin = false; + if (!data->Type.str().isEmpty()) + { + if (data->Type.str() == "x") + { + m_bXData = true; + QWidget *w; + foreach(w,m_widgets) + { + if(w) delete(w); + } + m_widgets.clear(); + foreach(w,m_labels) + { + if(w) delete(w); + } + m_labels.clear(); + foreach(w,m_descs) + { + if(w) delete(w); + } + m_descs.clear(); + m_instruction = QString::null; + } + else if (data->Type.str() == "title") + { + if (!data->Value.str().isEmpty()) + m_title = data->Value.str(); + } + else if (data->Type.str() == "text-single") + { + widget = new QLineEdit(this); + widget->setObjectName(data->Field.str()); + connect(widget, SIGNAL(returnPressed()), m_receiver, SLOT(search())); + connect(widget, SIGNAL(textChanged(const QString&)), m_receiver, SLOT(textChanged(const QString&))); + if (!data->Value.str().isEmpty()) + static_cast(widget)->setText(data->Value.str()); + } + else if (data->Type.str() == "text-private") + { + widget = new QLineEdit(this); + widget->setObjectName(data->Field.str()); + static_cast(widget)->setEchoMode(QLineEdit::Password); + connect(widget, SIGNAL(returnPressed()), m_receiver, SLOT(search())); + connect(widget, SIGNAL(textChanged(const QString&)), m_receiver, SLOT(textChanged(const QString&))); + if (!data->Value.str().isEmpty()) + static_cast(widget)->setText(data->Value.str()); + } + else if (data->Type.str() == "text-multi") + { + widget = new QTextEdit(this); + widget->setObjectName(data->Field.str()); + connect(widget, SIGNAL(returnPressed()), m_receiver, SLOT(search())); + if (!data->Value.str().isEmpty()) + static_cast(widget)->setText(data->Value.str()); + } + else if (data->Type.str() == "boolean" && !data->Label.str().isEmpty()) + { + widget = new QCheckBox(data->Label.str(), this); + widget->setObjectName(qPrintable(data->Field.str())); + if (!data->Value.str().isEmpty() && !data->Value.str().startsWith("0")) + static_cast(widget)->setChecked(true); + data->Label.clear(); + bJoin = true; + } + else if (data->Type.str() == "fixed") + { + if (!data->Value.str().isEmpty()) + { + QString text = i18(data->Value.str()); + text = text.replace(QRegExp(" +"), "\n"); + if (m_bFirst) + { + if (!m_label.isEmpty()) + m_label += '\n'; + m_label += text; + } + else + { + QLabel *label = new QLabel(text, this); + label->setWordWrap(true); + widget = label; + bJoin = true; + } + } + } + else if (data->Type.str() == "instructions") + { + if (!data->Value.str().isEmpty()) + { + QString text = i18(data->Value.str()); + text = text.replace(QRegExp(" +"), "\n"); + if (!m_instruction.isEmpty()) + m_instruction += '\n'; + m_instruction += text; + } + } + else if (data->Type.str() == "list-single") + { + CComboBox *box = new CComboBox(this, qPrintable(data->Field.str())); + int cur = 0; + int n = 0; + for (unsigned i = 0; i < data->nOptions.toULong(); i++){ + QString label = get_str(data->OptionLabels, i); + QString val = get_str(data->Options, i); + if(!label.isEmpty() && !val.isEmpty()) + { + box->addItem(i18(label), val); + if (data->Value.str() == val) + cur = n; + n++; + } + } + box->setCurrentIndex(cur); + widget = box; + } + else if (data->Type.str() == "key") + { + if (!data->Value.str().isEmpty()) + m_key = data->Value.str(); + } + else if (data->Type.str() == "password") + { + widget = new QLineEdit(this); + widget->setObjectName("password"); + static_cast(widget)->setEchoMode(QLineEdit::Password); + connect(widget, SIGNAL(returnPressed()), m_receiver, SLOT(search())); + connect(widget, SIGNAL(textChanged(const QString&)), m_receiver, SLOT(textChanged(const QString&))); + data->Label.str() = "Password"; + } + else if (data->Type.str() == "online") + { + widget = new QCheckBox(this); + widget->setObjectName("online"); + static_cast(widget)->setText(i18n("Online only")); + bJoin = true; + } + else if (data->Type.str() == "sex") + { + CComboBox *box = new CComboBox(this, qPrintable(data->Field.str())); + box->addItem(QString::null, "0"); + box->addItem(i18n("Male"), "1"); + box->addItem(i18n("Female"), "2"); + data->Label.str() == I18N_NOOP("Gender"); + widget = box; + } + else + { + defFlds *f; + for (f = fields; f->tag; f++) + if (data->Type.str() == QString::fromUtf8(f->tag)) + break; + if (f->tag) + { + widget = new QLineEdit(this); + widget->setObjectName(f->tag); + connect(widget, SIGNAL(returnPressed()), m_receiver, SLOT(search())); + connect(widget, SIGNAL(textChanged(const QString&)), m_receiver, SLOT(textChanged(const QString&))); + if (!data->Value.str().isEmpty()) + static_cast(widget)->setText(data->Value.str()); + data->Label.str() = QString::fromUtf8(f->name); + if (f->bRequired && m_bRegister) + data->bRequired.asBool() = true; + } + else if (!data->Label.str().isEmpty()) + { + widget = new QLineEdit(this); + widget->setObjectName(data->Field.str()); + connect(widget, SIGNAL(returnPressed()), m_receiver, SLOT(search())); + connect(widget, SIGNAL(textChanged(const QString&)), m_receiver, SLOT(textChanged(const QString&))); + if (!data->Value.str().isEmpty()) + static_cast(widget)->setText(data->Value.str()); + } + } + } + else + { + createLayout(); + m_widgets.clear(); + m_labels.clear(); + m_descs.clear(); + m_bDirty = true; + QTimer::singleShot(0, this, SLOT(setSize())); + return; + } + if (widget) + { + m_bFirst = false; + if (data->bRequired.toBool()) + m_required.push_back(widget); + QLabel *label = NULL; + if (!bJoin && !data->Label.str().isEmpty()) + { + QString text = i18(data->Label.str()); + if (!text.isEmpty() && (text[(int)(text.length() - 1)] != ':')) + text += ':'; + label = new QLabel(text, this); + label->setAlignment(Qt::AlignRight); + } + QWidget *help = NULL; + if (!data->Desc.str().isEmpty()) + help = new HelpButton(data->Desc.str(), this); + m_labels.push_back(label); + m_widgets.push_back(widget); + m_descs.push_back(help); + } +} + +void JabberSearch::setSize() +{ + if (!m_bDirty || (parent() == NULL)) + return; + m_bDirty = false; + for (QWidget *p = this; p; p = p->parentWidget()){ + QSize s = p->sizeHint(); + QSize s1 = QSize(p->width(), p->height()); + if (s.isValid()) + p->setMinimumSize(s); + p->resize(qMax(s.width(), s1.width()), qMax(s.height(), s1.height())); + if (p->layout()) + p->layout()->invalidate(); + if (p == topLevelWidget()) + break; + } + QWidget *t = topLevelWidget(); + QSize s = t->sizeHint(); + t->resize(qMax(t->width(), s.width()), qMax(t->height(), s.height())); + t->adjustSize(); +} + +#if 0 +static const char *any_data[] = + { + I18N_NOOP("First (Given)"), + I18N_NOOP("Last (Family)"), + I18N_NOOP("Nick (Alias)"), + I18N_NOOP("Email"), + I18N_NOOP("Select the speed of the search. \"Fast\" matches your string to the beginning of the field only (ie. \"b\" would yield Bob,Bill,etc...) \"Slower\" matches your string anywhere in the field (ie. \"b\" would yield Bob, Bill, Caleb, Robbie, etc...)"), + I18N_NOOP("Search Speed"), + I18N_NOOP("Fast / Less accurate"), + I18N_NOOP("Slower / More extensive") + I18N_NOOP("Full name") + I18N_NOOP("First Name") + I18N_NOOP("Last Name") + I18N_NOOP("Nickname") + I18N_NOOP("E-mail") + I18N_NOOP("Username") + I18N_NOOP("Password") + I18N_NOOP("Enter your MSN Messenger account and password. Example: user@hotmail.com. Nickname is optional.") + I18N_NOOP("Enter your AIM screenname or ICQ UIN and the password for that account") + I18N_NOOP("Enter your YAHOO! Messenger Username and Password.") + I18N_NOOP("Please enter your UIN and password") + I18N_NOOP("You need a x:data capable client to register.") + I18N_NOOP("Enter nick you want to register.") + I18N_NOOP("Complete the form to submit your searchable attributes in the Jabber User Directory") + I18N_NOOP("Fill in all of the fields to add yourself to the JUD.") + I18N_NOOP("Fill in a field to search for any matching Jabber User (POSIX regular expressions allowed)") + I18N_NOOP("Fill in a field to search for any matching Jabber users.") + I18N_NOOP("To register, please fill out the following form. Be as accurate as possible to make it easier for people to search for you.") + }; +#endif + +QString JabberSearch::i18(const char *text) +{ + if ((text == NULL) || (*text == 0)) + return QString(); + return i18(QString::fromUtf8(text)); +} + +QString JabberSearch::i18(const QString &res) +{ + if (res.isEmpty()) + return QString(); + for (int i = 0; i < res.length(); i++){ + if (res[i].unicode() >= 0x80) + return res; + } + return i18n(res); +} + +bool JabberSearch::canSearch() +{ + bool bRes = true; + + QList l = findChildren(); + QLineEdit *edit; + foreach(edit,l) + { + if (edit->echoMode() == QLineEdit::Password){ + if (edit->text().isEmpty()) + return false; + continue; + } + if (edit->text().isEmpty()){ + foreach(QWidget *w, m_required){; + if (w == (QWidget*)edit){ + return false; + } + } + } + if (!edit->text().isEmpty()) + bRes = true; + } + return bRes; +} + +QString JabberSearch::condition(QWidget *w) +{ + QString res; + if (m_bXData && (w == NULL)) + res += "x:data"; + + if (w == NULL) + w = this; + + QList list_edit = w->findChildren(); + foreach( QLineEdit *edit, list_edit ) + { + if (!edit->text().isEmpty()){ + if (!res.isEmpty()) + res += ';'; + res += edit->objectName(); + res += '='; + res += quoteChars(edit->text(), ";"); + } + } + + QList list_combo = w->findChildren(); + foreach( QComboBox *box, list_combo ) + { + if (box->currentText().isEmpty()){ + continue; + } + if (!res.isEmpty()) + res += ';'; + res += box->objectName(); + res += '='; + res += quoteChars(box->currentText(), ";"); + } + + QList list_check = w->findChildren(); + foreach( QCheckBox *check, list_check ) + { + if (!res.isEmpty()) + res += ';'; + res += check->objectName(); + res += check->isChecked() ? "=1" : "=0"; + } + + QList list_tedit = w->findChildren(); + foreach( QTextEdit *edit, list_tedit ) + { + if (!edit->toPlainText().isEmpty()){ + if (!res.isEmpty()) + res += ';'; + res += edit->objectName(); + res += '='; + res += quoteChars(edit->toPlainText(), ";"); + } + } + + if (!m_key.isEmpty() && (w == NULL)){ + if (!res.isEmpty()) + res += ';'; + res += "key="; + res += quoteChars(m_key, ";"); + } + return res; +} + +void JabberSearch::createLayout() +{ + unsigned start = 0; + unsigned nCols = 0; + unsigned nRows = 0; + m_vlay = new QVBoxLayout(this); + m_lay = new QGridLayout(this); + m_vlay->addLayout(m_lay); + m_vlay->setMargin(11); + m_lay->setSpacing(6); + m_vlay->addStretch(); + if (!m_widgets.empty()){ + nCols = (m_widgets.size() + MAX_ELEMENTS - 1) / MAX_ELEMENTS; + nRows = (m_widgets.size() + nCols - 1) / nCols; + start = 0; + if (!m_label.isEmpty()) + { + QLabel *label = new QLabel(m_label, this); + label->setWordWrap(true); + m_lay->addWidget(label, 0, 0, 1, nCols * 3 + 1); + m_label = QString::null; + start = 1; + } + unsigned row = start; + unsigned col = 0; + for (int i = 0; i < m_widgets.size(); i++, row++) + { + if (row >= nRows + start){ + row = 0; + col += 3; + } + if (m_labels[i]) + { + static_cast(m_labels[i])->setAlignment( Qt::AlignVCenter | Qt::AlignRight); + m_lay->addWidget(m_labels[i], row, col); + if (m_descs[i]) + { + m_lay->addWidget(m_widgets[i], row, col + 1, Qt::AlignVCenter); + m_lay->addWidget(m_descs[i], row, col + 2, Qt::AlignVCenter); + m_descs[i]->show(); + } + else + { + m_lay->addWidget(m_widgets[i], row, col + 1, 1, 1, Qt::AlignVCenter); + } + m_labels[i]->show(); + } + else + { + if (m_descs[i]) + { + m_lay->addWidget(m_widgets[i], row, col, 1, 2, Qt::AlignVCenter); + m_lay->addWidget(m_descs[i], row, col + 2, Qt::AlignBottom); + m_descs[i]->show(); + } + else + m_lay->addWidget(m_widgets[i], row, col, 1, 3, Qt::AlignVCenter); + + } + m_widgets[i]->show(); + } + } + if (!m_instruction.isEmpty()) + { + QLabel *label = new QLabel(m_instruction, this); + label->setWordWrap(true); + m_lay->addWidget(label, nRows + start, 0, 1, nCols * 3 - 1); + m_instruction = QString::null; + } +} + +HelpButton::HelpButton(const QString &help, QWidget *parent) + : QPushButton(parent) +{ + QIcon p = Icon("help"); + setIcon(p); + m_help = help; + connect(this, SIGNAL(clicked()), this, SLOT(click())); +// setMinimumSize(p.width() + 2, p.height() + 2); +// setMaximumSize(p.width() + 2, p.height() + 2); +} + +void HelpButton::click() +{ + BalloonMsg::message(m_help, this); +} + +JIDJabberSearch::JIDJabberSearch(QWidget *parent, const char *name) + : JabberSearch(parent, name) +{ + m_adv = NULL; +} + +void JIDJabberSearch::setAdvanced(JIDAdvSearch *adv) +{ + m_adv = adv; +} + +static const char *names[] = + { + "username", + "email", + "nick", + "first", + "last", + "user", + "fn", + "given", + "online", + NULL + }; + +const unsigned MAX_MAIN = 6; + +void JIDJabberSearch::createLayout() +{ + unsigned rowMain = 0; + QGridLayout *lay = new QGridLayout(this); + QGridLayout *alay = NULL; + lay->setSpacing(6); + unsigned nAdv = 0; + unsigned nMain = 0; + if (m_widgets.size() > (int)MAX_MAIN){ + alay = new QGridLayout(m_adv->grpSearch); + alay->setMargin(11); + alay->setSpacing(6); + for (int i = 0; i < m_widgets.size(); i++){ + if (nMain > MAX_MAIN){ + nAdv++; + continue; + } + const char **p; + for (p = names; *p; p++) + if ( m_widgets[i]->objectName() == *p ) + break; + if (*p == NULL){ + nAdv++; + continue; + } + nMain++; + } + } + unsigned nCols = (nAdv + MAX_ELEMENTS - 1) / MAX_ELEMENTS; + unsigned nRows = nCols ? (nAdv + nCols - 1) / nCols : 0; + unsigned start = 0; + unsigned row = 0; + unsigned col = 0; + nMain = 0; + for (int i = 0; i < m_widgets.size(); i++){ + bool bMain = false; + if (alay){ + if (nMain < MAX_MAIN){ + const char **p; + for (p = names; *p; p++) + if ( m_widgets[i]->objectName() == *p ) + break; + if (*p){ + nMain++; + bMain = true; + } + } + }else{ + bMain = true; + } + if (bMain){ + if (m_labels[i]){ + static_cast(m_labels[i])->setAlignment(Qt::AlignVCenter); + lay->addWidget(m_labels[i], rowMain, 0, 1, 2, Qt::AlignVCenter); + m_labels[i]->show(); + rowMain++; + } + if (m_descs[i]){ + lay->addWidget(m_widgets[i], rowMain, 0, Qt::AlignVCenter); + lay->addWidget(m_descs[i], rowMain, 1, Qt::AlignVCenter); + m_descs[i]->show(); + }else{ + lay->addWidget(m_widgets[i], rowMain, 0, 1, 2, Qt::AlignVCenter); + } + m_widgets[i]->show(); + rowMain++; + }else{ + if (row >= nRows + start){ + row = 0; + col += 3; + } + m_widgets[i]->setParent(m_adv->grpSearch); + m_widgets[i]->move(QPoint(0, 0)); + if (m_descs[i]){ + m_descs[i]->setParent(m_adv->grpSearch); + m_descs[i]->move(QPoint(0, 0)); + } + if (m_labels[i]){ + m_labels[i]->setParent(m_adv->grpSearch); + m_labels[i]->move(QPoint(0, 0)); + static_cast(m_labels[i])->setAlignment(Qt::AlignVCenter | Qt::AlignRight); + alay->addWidget(m_labels[i], row, col); + if (m_descs[i]){ + alay->addWidget(m_widgets[i], row, col + 1, Qt::AlignVCenter); + alay->addWidget(m_descs[i], row, col + 2, Qt::AlignVCenter); + m_descs[i]->show(); + }else{ + alay->addWidget(m_widgets[i], row, col + 1, 1, 2, Qt::AlignVCenter); + } + m_labels[i]->show(); + }else{ + if (m_descs[i]){ + alay->addWidget(m_widgets[i], row, col, 1, 2, Qt::AlignVCenter); + alay->addWidget(m_descs[i], row, col + 2, Qt::AlignBottom); + m_descs[i]->show(); + }else{ + alay->addWidget(m_widgets[i], row, col, 1, 3, Qt::AlignVCenter); + } + } + m_widgets[i]->show(); + row++; + } + } + if (alay){ + m_adv->lblTitle->setText(m_title); + m_adv->lblInstruction->setText(m_instruction); + } + m_instruction = QString::null; +} + +/* +#ifndef NO_MOC_INCLUDES +#include "jabbersearch.moc" +#endif +*/ + diff --git a/plugins/jabber/jabbersearch.h b/plugins/jabber/jabbersearch.h new file mode 100644 index 0000000..410fa68 --- /dev/null +++ b/plugins/jabber/jabbersearch.h @@ -0,0 +1,93 @@ +/*************************************************************************** + jabbersearch.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _JABBERSEARCH_H +#define _JABBERSEARCH_H + +#include +#include +#include +#include + +class JabberClient; +struct JabberAgentInfo; + +class HelpButton : public QPushButton +{ + Q_OBJECT +public: + HelpButton(const QString &help, QWidget *parent); +protected slots: + void click(); +protected: + QString m_help; +}; + +class JabberSearch : public QWizardPage +{ + Q_OBJECT +public: + JabberSearch(QWidget *parent = NULL, const char *name = NULL); + void init(QWidget *receiver, JabberClient *client, const QString &jid, const QString &node, const QString &name, bool bRegister); + bool canSearch(); + QString condition(QWidget *w); + const QString &id() { return m_jid; } + void addWidget(JabberAgentInfo *data); + JabberClient *m_client; + QString m_jid; + QString m_node; + QString m_title; +protected slots: + void setSize(); +protected: + virtual void createLayout(); + QString i18(const char *text); + QString i18(const QString &text); + + QString m_name; + QString m_instruction; + QString m_label; + QWidget *m_receiver; + QString m_key; + bool m_bDirty; + bool m_bXData; + bool m_bFirst; + bool m_bRegister; + QList m_required; + QList m_widgets; + QList m_labels; + QList m_descs; +private: + QVBoxLayout *m_vlay; + QGridLayout *m_lay; +}; + +class JIDAdvSearch; + +class JIDJabberSearch : public JabberSearch +{ + Q_OBJECT +public: + JIDJabberSearch(QWidget *parent = NULL, const char *name = NULL); + void setAdvanced(JIDAdvSearch *adv); +protected: + void createLayout(); + JIDAdvSearch *m_adv; +}; + +#endif + diff --git a/plugins/jabber/jabberstatus.cpp b/plugins/jabber/jabberstatus.cpp new file mode 100644 index 0000000..3d56f37 --- /dev/null +++ b/plugins/jabber/jabberstatus.cpp @@ -0,0 +1,78 @@ + +#include "jabberstatus.h" + + +JabberStatus::JabberStatus(const QString& id, const QString& name, bool hasText, const QString& defaultText, const QIcon& icon, + const QString& show, const QString& type) : IMStatus(), + m_id(id), + m_name(name), + m_hasText(hasText), + m_text(defaultText), + m_icon(icon), + m_show(show), + m_type(type) +{ +} + +JabberStatus::~JabberStatus() +{ +} + + +QString JabberStatus::id() const +{ + return m_id; +} + +QString JabberStatus::name() const +{ + return m_name; +} + +void JabberStatus::setText(const QString& t) +{ + m_text = t; +} + +QString JabberStatus::text() const +{ + return m_text; +} + +QIcon JabberStatus::icon() const +{ + return m_icon; +} + +QStringList JabberStatus::substatuses() +{ + return QStringList(); +} + +SIM::IMStatusPtr JabberStatus::substatus(const QString& id) +{ + return SIM::IMStatusPtr(); +} + +SIM::IMStatusPtr JabberStatus::clone() +{ + return SIM::IMStatusPtr(new JabberStatus(m_id, m_name, m_hasText, m_text, m_icon, m_show, m_type)); +} + +bool JabberStatus::hasText() const +{ + return m_hasText; +} + +QString JabberStatus::show() +{ + return m_show; +} + +QString JabberStatus::type() +{ + return m_type; +} + +// vim: set expandtab: + diff --git a/plugins/jabber/jabberstatus.h b/plugins/jabber/jabberstatus.h new file mode 100644 index 0000000..dd411a1 --- /dev/null +++ b/plugins/jabber/jabberstatus.h @@ -0,0 +1,44 @@ + +#ifndef JABBERSTATUS_H +#define JABBERSTATUS_H + +#include "contacts/imstatus.h" + +class JabberStatus : public SIM::IMStatus +{ +public: + JabberStatus(const QString& id, const QString& name, bool hasText, const QString& defaultText, const QIcon& icon, + const QString& show, const QString& type); + virtual ~JabberStatus(); + + virtual QString id() const; + virtual QString name() const; + virtual bool hasText() const; + virtual void setText(const QString& t); + virtual QString text() const; + virtual QIcon icon() const; + + virtual QStringList substatuses(); + virtual SIM::IMStatusPtr substatus(const QString& id); + virtual SIM::IMStatusPtr clone(); + + QString show(); + QString type(); + +private: + QString m_id; + QString m_name; + bool m_hasText; + QString m_text; + QIcon m_icon; + QString m_show; + QString m_type; + +}; + +typedef QSharedPointer JabberStatusPtr; + +#endif + +// vim: set expandtab: + diff --git a/plugins/jabber/jabberworkinfo.cpp b/plugins/jabber/jabberworkinfo.cpp new file mode 100644 index 0000000..b567268 --- /dev/null +++ b/plugins/jabber/jabberworkinfo.cpp @@ -0,0 +1,96 @@ +/*************************************************************************** + jabberworkinfo.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "jabberclient.h" +#include "jabberworkinfo.h" +#include "jabber.h" +#include "contacts/contact.h" + +#include +#include + +using namespace SIM; + +JabberWorkInfo::JabberWorkInfo(QWidget *parent, JabberUserData *data, JabberClient *client) : QWidget(parent) + //: JabberWorkInfoBase(parent) +{ + setupUi(this); + m_client = client; + m_data = data; + if (m_data){ + edtCompany->setReadOnly(true); + edtDepartment->setReadOnly(true); + edtTitle->setReadOnly(true); + edtRole->setReadOnly(true); + } + fill(m_data); +} + +void JabberWorkInfo::apply() +{ +} + +bool JabberWorkInfo::processEvent(Event *e) +{ + if (e->type() == eEventContact){ + EventContact *ec = static_cast(e); + if(ec->action() != EventContact::eChanged) + return false; + Contact *contact = ec->contact(); + if (contact->clientData.have(m_data)) + fill(m_data); + } else + if ((e->type() == eEventClientChanged) && (m_data == 0)){ + EventClientChanged *ecc = static_cast(e); + if (ecc->client() == m_client) + fill(m_data); + } else + if (m_data && (e->type() == eEventVCard)){ + EventVCard *evc = static_cast(e); + JabberUserData *data = evc->data(); + if (m_data->ID.str() == data->ID.str() && m_data->Node.str() == data->Node.str()) + fill(data); + } + return false; +} + +void JabberWorkInfo::fill(JabberUserData *data) +{ + if (data == NULL) data = &m_client->data.owner; + edtCompany->setText(data->OrgName.str()); + edtDepartment->setText(data->OrgUnit.str()); + edtTitle->setText(data->Title.str()); + edtRole->setText(data->Role.str()); +} + +void JabberWorkInfo::apply(Client *client, void *_data) +{ + if (client != m_client) + return; + JabberUserData *data = m_client->toJabberUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + data->OrgName.str() = edtCompany->text(); + data->OrgUnit.str() = edtDepartment->text(); + data->Title.str() = edtTitle->text(); + data->Role.str() = edtRole->text(); +} + +/* +#ifndef NO_MOC_INCLUDES +#include "jabberworkinfo.moc" +#endif +*/ + diff --git a/plugins/jabber/jabberworkinfo.h b/plugins/jabber/jabberworkinfo.h new file mode 100644 index 0000000..cc3c963 --- /dev/null +++ b/plugins/jabber/jabberworkinfo.h @@ -0,0 +1,43 @@ +/*************************************************************************** + jabberworkinfo.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _JABBERWORKINFO_H +#define _JABBERWORKINFO_H + +#include "ui_jabberworkinfobase.h" +#include "event.h" + +struct JabberUserData; +class JabberClient; + +class JabberWorkInfo : public QWidget, public Ui::JabberWorkInfoBase, public SIM::EventReceiver +{ + Q_OBJECT +public: + JabberWorkInfo(QWidget *parent, JabberUserData *data, JabberClient *client); +public slots: + void apply(); + void apply(SIM::Client*, void*); +protected: + virtual bool processEvent(SIM::Event *e); + void fill(JabberUserData *data); + JabberUserData *m_data; + JabberClient *m_client; +}; + +#endif + diff --git a/plugins/jabber/jabberworkinfobase.ui b/plugins/jabber/jabberworkinfobase.ui new file mode 100644 index 0000000..0b4bc45 --- /dev/null +++ b/plugins/jabber/jabberworkinfobase.ui @@ -0,0 +1,132 @@ + + + + + JabberWorkInfoBase + + + + 0 + 0 + 380 + 196 + + + + Form1 + + + + 11 + + + 6 + + + + + Department: + + + Qt::AlignVCenter|Qt::AlignRight + + + false + + + + + + + Company: + + + Qt::AlignVCenter|Qt::AlignRight + + + false + + + + + + + + + + + + + + + + Role: + + + Qt::AlignVCenter|Qt::AlignRight + + + false + + + + + + + Position: + + + Qt::AlignVCenter|Qt::AlignRight + + + false + + + + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Vertical + + + + + + + + QWidget + QWidget +
QWidget
+ + -1 + -1 + + 0 + + 5 + 5 + + image0 + + text + +
+
+ + + 789c6dd2c10ac2300c00d07bbf2234b7229d1be245fc04c5a3201e4615f430059d0711ff5ddb2e6bb236ec90eed134cb5a19d8ef36602af5ecdbfeeac05dda0798d3abebde87e3faa374d3807fa0d633a52d38d8de6f679fe33fc776e196f53cd010188256a3600a292882096246517815ca99884606e18044a3a40d91824820924265a7923a2e8bcd05f33db1173e002913175f2a6be6d3294871a2d95fa00e8a94ee017b69d339d90df1e77c57ea072ede6758 + + +
diff --git a/plugins/jabber/jidadvsearch.cpp b/plugins/jabber/jidadvsearch.cpp new file mode 100644 index 0000000..4824296 --- /dev/null +++ b/plugins/jabber/jidadvsearch.cpp @@ -0,0 +1,38 @@ +/*************************************************************************** + jidadvsearch.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "jidadvsearch.h" + +#include + +JIDAdvSearch::JIDAdvSearch(QWidget *parent) : QWidget(parent) + //: JIDAdvSearchBase(parent) +{ +} + +void JIDAdvSearch::showEvent(QShowEvent *e) +{ + QWidget::showEvent(e); + emit enableOptions(false); +} + +/* +#ifndef NO_MOC_INCLUDES +#include "jidadvsearch.moc" +#endif +*/ + diff --git a/plugins/jabber/jidadvsearch.h b/plugins/jabber/jidadvsearch.h new file mode 100644 index 0000000..93c1d72 --- /dev/null +++ b/plugins/jabber/jidadvsearch.h @@ -0,0 +1,37 @@ +/*************************************************************************** + jidadvsearch.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _JIDADVSEARCH_H +#define _JIDADVSEARCH_H + +#include "ui_jidadvsearchbase.h" + +#include + +class JIDAdvSearch : public QWidget, public Ui::JIDAdvSearch +{ + Q_OBJECT +public: + JIDAdvSearch(QWidget *parent); +signals: + void enableOptions(bool); +protected: + void showEvent(QShowEvent*); +}; + +#endif + diff --git a/plugins/jabber/jidadvsearchbase.ui b/plugins/jabber/jidadvsearchbase.ui new file mode 100644 index 0000000..fc347a5 --- /dev/null +++ b/plugins/jabber/jidadvsearchbase.ui @@ -0,0 +1,76 @@ + + + JIDAdvSearch + + + + 0 + 0 + 415 + 331 + + + + Form1 + + + + 6 + + + 11 + + + + + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + true + + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + true + + + + + + + + diff --git a/plugins/jabber/jidsearch.cpp b/plugins/jabber/jidsearch.cpp new file mode 100644 index 0000000..6175031 --- /dev/null +++ b/plugins/jabber/jidsearch.cpp @@ -0,0 +1,202 @@ +/*************************************************************************** + jidsearch.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include + +#include "icons.h" +#include "misc.h" + +#include "jabberclient.h" +#include "jidsearch.h" +#include "jabbersearch.h" +#include "jidadvsearch.h" +#include "jabber.h" +#include "contacts/contact.h" + +using namespace SIM; + +JIDSearch::JIDSearch(QWidget *parent, JabberClient *client, const QString &jid, + const QString &node, const QString &type) : QWidget(parent) + //: JIDSearchBase(parent) +{ + setupUi(this); + m_client = client; + m_jid = jid; + m_node = node; + m_type = type; + connect(btnBrowser, SIGNAL(clicked()), this, SLOT(browserClicked())); + connect(btnAdvanced, SIGNAL(clicked()), this, SLOT(advancedClicked())); + QIcon is = Icon("1rightarrow"); + btnBrowser->setIcon(is); + btnAdvanced->setIcon(is); + m_bInit = false; + m_adv = new JIDAdvSearch(this); + jidSearch->setAdvanced(m_adv); + m_bAdv = false; +} + +void JIDSearch::browserClicked() +{ + connect(this, SIGNAL(showClient(SIM::Client*)), topLevelWidget(), SLOT(showClient(SIM::Client*))); + emit showClient(m_client); + disconnect(this, SIGNAL(showClient(SIM::Client*)), topLevelWidget(), SLOT(showClient(SIM::Client*))); +} + +void JIDSearch::showEvent(QShowEvent *e) +{ + QWidget::showEvent(e); + if (!m_bInit){ + m_bInit = true; + connect(this, SIGNAL(setAdd(bool)), topLevelWidget(), SLOT(setAdd(bool))); + connect(this, SIGNAL(showResult(QWidget*)), topLevelWidget(), SLOT(showResult(QWidget*))); + connect(this, SIGNAL(addResult(QWidget*)), topLevelWidget(), SLOT(addResult(QWidget*))); + if(!m_adv->grpSearch->children().empty()) + { + emit addResult(m_adv); + } + else + { + btnAdvanced->hide(); + m_adv->hide(); + } + } + if (m_bAdv) + { + m_bAdv = false; + advancedClicked(); + } + emit setAdd(false); +} + +void JIDSearch::advancedClicked() +{ + if (m_bAdv){ + m_bAdv = false; + QIcon is = Icon("1rightarrow"); + btnAdvanced->setIcon(is); + emit showResult(NULL); + }else{ + m_bAdv = true; + QIcon is = Icon("1leftarrow"); + btnAdvanced->setIcon(is); + emit showResult(m_adv); + } +} + +void JIDSearch::search() +{ + QString condition = jidSearch->condition(NULL); + if (m_bAdv){ + if (!condition.isEmpty()) + condition += ';'; + condition += jidSearch->condition(m_adv); + advancedClicked(); + } + m_search_id = m_client->search(m_jid, m_node, condition); +} + +void JIDSearch::searchStop() +{ + m_search_id = QString::null; +} + +bool JIDSearch::processEvent(Event *e) +{ + if (e->type() == eEventJabberSearch){ + EventSearch *es = static_cast(e); + JabberSearchData *data = es->searchData(); + if (m_search_id != data->ID.str()) + return false; + if (data->JID.str().isEmpty()){ + QStringList l; + l.append(QString::null); + l.append(i18n("JID")); + for (unsigned i = 0; i < data->nFields.toULong(); i++){ + l.append(get_str(data->Fields, i * 2)); + l.append(i18n(get_str(data->Fields, i * 2 + 1))); + } + emit setColumns(l, 0, this); + return true; + } + QString icon = "Jabber"; + if (m_type == "icq"){ + icon = "ICQ"; + }else if (m_type == "aim"){ + icon = "AIM"; + }else if (m_type == "msn"){ + icon = "MSN"; + }else if (m_type == "yahoo"){ + icon = "Yahoo!"; + }else if (m_type == "sms"){ + icon = "sms"; + }else if ((m_type == "x-gadugadu") || (m_type == "gg")){ + icon = "GG"; + } + if (!data->Status.str().isEmpty()){ + if (data->Status.str() == "online"){ + icon += "_online"; + }else{ + icon += "_offline"; + } + } + QStringList l; + l.append(icon); + l.append(data->JID.str()); + l.append(data->JID.str()); + for (unsigned n = 0; n < data->nFields.toULong(); n++) + l.append(get_str(data->Fields, n)); + emit addItem(l, this); + } + if (e->type() == eEventJabberSearchDone){ + EventSearchDone *esd = static_cast(e); + QString id = esd->userID(); + if (m_search_id == id){ + m_search_id = QString::null; + emit searchDone(this); + } + } + return false; +} + +void JIDSearch::createContact(const QString &name, unsigned tmpFlags, Contact *&contact) +{ + QString resource; + if (m_client->findContact(name, QString::null, false, contact, resource)) + return; + if (m_client->findContact(name, QString::null, true, contact, resource, false) == NULL) + return; + contact->setFlags(contact->getFlags() | tmpFlags); +} + +#if 0 +i18n("User") +i18n("Full Name") +i18n("Middle Name") +i18n("Family Name") +i18n("email") +i18n("Birthday") +i18n("Organization Name") +i18n("Organization Unit") +#endif + +/* +#ifndef NO_MOC_INCLUDES +#include "jidsearch.moc" +#endif +*/ + diff --git a/plugins/jabber/jidsearch.h b/plugins/jabber/jidsearch.h new file mode 100644 index 0000000..aecbd56 --- /dev/null +++ b/plugins/jabber/jidsearch.h @@ -0,0 +1,63 @@ +/*************************************************************************** + jidsearch.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _JIDSEARCH_H +#define _JIDSEARCH_H + +#include "ui_jidsearchbase.h" +#include "event.h" + +#include + +struct JabberUserData; +class JabberClient; +class JIDAdvSearch; + +class JIDSearch : public QWidget, public Ui::JIDSearch, public SIM::EventReceiver +{ + Q_OBJECT +public: + JIDSearch(QWidget *parent, JabberClient *client, const QString &jid, const QString &m_node, const QString &type); + QString m_jid; + QString m_node; +signals: + void setAdd(bool); + void showClient(SIM::Client*); + void showResult(QWidget*); + void addResult(QWidget*); + void setColumns(const QStringList&, int, QWidget*); + void addItem(const QStringList&, QWidget*); + void searchDone(QWidget*); +protected slots: + void browserClicked(); + void advancedClicked(); + void search(); + void searchStop(); + void createContact(const QString&, unsigned tmpFlags, SIM::Contact *&contact); +protected: + virtual bool processEvent(SIM::Event *e); + void showEvent(QShowEvent*); + QString m_search_id; + QString m_type; + bool m_bInit; + bool m_bAdv; + JIDAdvSearch *m_adv; + JabberClient *m_client; +}; + +#endif + diff --git a/plugins/jabber/jidsearchbase.ui b/plugins/jabber/jidsearchbase.ui new file mode 100644 index 0000000..39a3110 --- /dev/null +++ b/plugins/jabber/jidsearchbase.ui @@ -0,0 +1,87 @@ + + + JIDSearch + + + + 0 + 0 + 184 + 355 + + + + Form1 + + + + 6 + + + 0 + + + + + GroupBox + + + + + + + 0 + 0 + + + + + + + + + + + &Advanced + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + Jabber &browser + + + + + + + + JIDJabberSearch + QWidget +
jabbersearch.h
+
+
+ + btnAdvanced + btnBrowser + + + +
diff --git a/plugins/livejournal/CMakeLists.txt b/plugins/livejournal/CMakeLists.txt new file mode 100644 index 0000000..9a7db89 --- /dev/null +++ b/plugins/livejournal/CMakeLists.txt @@ -0,0 +1,26 @@ +####################### +# livejournal library # +####################### +IF(BUILD_DROPPED) +SET(livejournal_SRCS + journalsearch.cpp + livejournal.cpp + livejournalcfg.cpp + msgjournal.cpp +) + +SET(livejournal_HDRS + journalsearch.h + livejournal.h + livejournalcfg.h + msgjournal.h +) + +SET(livejournal_UICS + journalsearchbase.ui + livejournalcfgbase.ui + msgjournalbase.ui +) + +SIM_ADD_PLUGIN(livejournal) +ENDIF(BUILD_DROPPED) diff --git a/plugins/livejournal/configure.in.in b/plugins/livejournal/configure.in.in new file mode 100644 index 0000000..ef18b62 --- /dev/null +++ b/plugins/livejournal/configure.in.in @@ -0,0 +1,4 @@ +if test "$have_ssl" != yes; then + AC_MSG_WARN([OpenSSL library disabled. LiveJournal plugin is disabled]) +fi +AM_CONDITIONAL(ENABLE_LIVEJOURNAL, test "$have_ssl" = "yes") diff --git a/plugins/livejournal/journalsearch.cpp b/plugins/livejournal/journalsearch.cpp new file mode 100644 index 0000000..bd239e8 --- /dev/null +++ b/plugins/livejournal/journalsearch.cpp @@ -0,0 +1,49 @@ +/*************************************************************************** + msnsearch.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "journalsearch.h" +#include "livejournal.h" +#include "contacts/contact.h" + +#include +#include + +using namespace SIM; + +JournalSearch::JournalSearch(LiveJournalClient *client, QWidget *parent) : QWidget(parent) +{ + setupUi(this); + m_client = client; + connect(this, SIGNAL(setAdd(bool)), topLevelWidget(), SLOT(setAdd(bool))); +} + +void JournalSearch::showEvent(QShowEvent *e) +{ + showEvent(e); + emit setAdd(true); +} + +void JournalSearch::createContact(unsigned tmpFlags, Contact *&contact) +{ + if (edtCommunity->text().isEmpty()) + return; + if (m_client->findContact(edtCommunity->text(), contact, false)) + return; + m_client->findContact(edtCommunity->text(), contact, true, false); + contact->setFlags(contact->getFlags() | tmpFlags); +} + diff --git a/plugins/livejournal/journalsearch.h b/plugins/livejournal/journalsearch.h new file mode 100644 index 0000000..087e073 --- /dev/null +++ b/plugins/livejournal/journalsearch.h @@ -0,0 +1,44 @@ +/*************************************************************************** + journalsearch.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _JOURNALSEARCH_H +#define _JOURNALSEARCH_H + +#include "contacts.h" + +#include "ui_journalsearchbase.h" + +#include + +class LiveJournalClient; + +class JournalSearch : public QWidget, public Ui::JournalSearchBase +{ + Q_OBJECT +public: + JournalSearch(LiveJournalClient *client, QWidget *parent); +signals: + void setAdd(bool); +protected slots: + void createContact(unsigned tmpFlags, SIM::Contact *&contact); +protected: + void showEvent(QShowEvent*); + LiveJournalClient *m_client; +}; + +#endif + diff --git a/plugins/livejournal/journalsearchbase.ui b/plugins/livejournal/journalsearchbase.ui new file mode 100644 index 0000000..2792906 --- /dev/null +++ b/plugins/livejournal/journalsearchbase.ui @@ -0,0 +1,55 @@ + + + JournalSearchBase + + + + 0 + 0 + 212 + 355 + + + + Form1 + + + + 6 + + + 0 + + + + + Add community + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + diff --git a/plugins/livejournal/livejournal.cpp b/plugins/livejournal/livejournal.cpp new file mode 100644 index 0000000..3362ba4 --- /dev/null +++ b/plugins/livejournal/livejournal.cpp @@ -0,0 +1,1492 @@ +/*************************************************************************** + livejournal.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "simapi.h" + +#include +#include +#include +#include +#include + + +#include + +#include "clientmanager.h" +#include "fetch.h" +#include "html.h" +#include "log.h" +#include "unquot.h" +#include "core.h" + + +#include "contacts/clientdataiterator.h" +#include "contacts/contact.h" + +#include "livejournal.h" +#include "livejournalcfg.h" +#include "msgjournal.h" +#include "journalsearch.h" + +using namespace std; +using namespace SIM; + +Plugin *createLiveJournalPlugin(unsigned base, bool, Buffer*) +{ + Plugin *plugin = new LiveJournalPlugin(base); + return plugin; +} + +static PluginInfo info = + { + NULL, + NULL, + VERSION, + createLiveJournalPlugin, + PLUGIN_PROTOCOL + }; + +EXPORT_PROC PluginInfo* GetPluginInfo() +{ + return &info; +} + +static DataDef journalMessageData[] = + { + { "Subject", DATA_UTF, 1, 0 }, + { "Private", DATA_ULONG, 1, 0 }, + { "Time", DATA_ULONG, 1, 0 }, + { "ItemID", DATA_ULONG, 1, 0 }, + { "", DATA_ULONG, 1, 0 }, // oldID + { "Mood", DATA_ULONG, 1, 0 }, + { "Comments", DATA_ULONG, 1, 0 }, + { NULL, DATA_UNKNOWN, 0, 0 } + }; + +JournalMessage::JournalMessage(Buffer *cfg) + : Message(MessageJournal, cfg) +{ + load_data(journalMessageData, &data, cfg); +} + +JournalMessage::~JournalMessage() +{ + free_data(journalMessageData, &data); +} + +QByteArray JournalMessage::save() +{ + QByteArray cfg = Message::save(); + QByteArray my_cfg = save_data(journalMessageData, &data); + if (!my_cfg.isEmpty()){ + if (!cfg.isEmpty()) + cfg += "\n"; + cfg += my_cfg; + } + return cfg; +} + +QString JournalMessage::presentation() +{ + QString subj = getSubject(); + QString res; + if (!subj.isEmpty()) + res = i18n("

Subject: %1

") .arg(subj); + res += Message::presentation(); + return res; +} + +#if 0 +i18n("LiveJournal post", "%n LiveJournal posts", 1); +i18n("Friends updated", "Friends updated %n", 1); +#endif + +static Message *createJournalMessage(Buffer *cfg) +{ + return new JournalMessage(cfg); +} + +static QObject* generateJournalMessage(MsgEdit *w, Message *msg) +{ + return new MsgJournal(w, msg); +} + +static CommandDef journalMessageCommands[] = + { + CommandDef ( + CmdDeleteJournalMessage, + I18N_NOOP("&Remove from journal"), + "remove", + QString::null, + QString::null, + ToolBarMsgEdit, + 0x1080, + MenuMessage, + 0, + 0, + COMMAND_DEFAULT, + NULL, + QString::null + ), + CommandDef () + }; + +static MessageDef defJournalMessage = + { + NULL, + journalMessageCommands, + MESSAGE_SENDONLY, + "LiveJournal post", + "%n LiveJournal posts", + createJournalMessage, + generateJournalMessage, + NULL + }; + +static MessageDef defWWWJournalMessage = + { + NULL, + NULL, + MESSAGE_SENDONLY | MESSAGE_SILENT, + NULL, + NULL, + createJournalMessage, + NULL, + NULL + }; + +static Message *createUpdatedMessage(Buffer *cfg) +{ + return new Message(MessageUpdated, cfg); +} + +static MessageDef defUpdatedMessage = + { + NULL, + NULL, + MESSAGE_SYSTEM, + "Friends updated", + "Friends updated %n", + createUpdatedMessage, + NULL, + NULL + }; + +unsigned LiveJournalPlugin::MenuCount = 0; + +LiveJournalPlugin::LiveJournalPlugin(unsigned base) + : Plugin(base) +{ + m_protocol = new LiveJournalProtocol(this); + + EventMenu(MenuWeb, EventMenu::eAdd).process(); + + Command cmd; + cmd->id = CmdMenuWeb; + cmd->text = "_"; + cmd->menu_id = MenuWeb; + cmd->menu_grp = 0x1000; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); + + cmd->id = MessageJournal; + cmd->text = I18N_NOOP("LiveJournal &post"); + cmd->icon = "LiveJournal"; + cmd->accel = "Ctrl+P"; + cmd->menu_grp = 0x3080; + cmd->flags = COMMAND_DEFAULT; + cmd->param = &defJournalMessage; + EventCreateMessageType(cmd).process(); + + cmd->id = CmdMenuWeb; + cmd->text = I18N_NOOP("LiveJournal &WWW"); + cmd->icon = QString::null; + cmd->accel = QString::null; + cmd->menu_grp = 0x3090; + cmd->popup_id = MenuWeb; + cmd->flags = COMMAND_DEFAULT; + cmd->param = &defWWWJournalMessage; + EventCreateMessageType(cmd).process(); + + cmd->id = MessageUpdated; + cmd->text = I18N_NOOP("Friends updated"); + cmd->icon = "LiveJournal_upd"; + cmd->accel = QString::null; + cmd->menu_grp = 0; + cmd->popup_id = 0; + cmd->flags = COMMAND_DEFAULT; + cmd->param = &defUpdatedMessage; + EventCreateMessageType(cmd).process(); +} + +LiveJournalPlugin::~LiveJournalPlugin() +{ + EventMenu(MenuWeb, EventMenu::eRemove).process(); + + EventRemoveMessageType(MessageJournal).process(); + EventRemoveMessageType(CmdMenuWeb).process(); + EventRemoveMessageType(MessageUpdated).process(); + + delete m_protocol; +} + +LiveJournalProtocol::LiveJournalProtocol(Plugin *plugin) + : Protocol(plugin) +{ +} + +LiveJournalProtocol::~LiveJournalProtocol() +{ +} + +ClientPtr LiveJournalProtocol::createClient(Buffer *cfg) +{ + ClientPtr lj = ClientPtr(new LiveJournalClient(this, cfg)); + getClientManager()->addClient(lj); + return lj; +} + +static CommandDef livejournal_descr = + CommandDef ( + 0, + I18N_NOOP("LiveJournal"), + "LiveJournal", + QString::null, + "http://www.livejournal.com/lostinfo.bml", + 0, + 0, + 0, + 0, + 0, + PROTOCOL_NOSMS | PROTOCOL_NOPROXY, + NULL, + QString::null + ); + +const CommandDef *LiveJournalProtocol::description() +{ + return &livejournal_descr; +} + +static CommandDef livejournal_status_list[] = + { + CommandDef ( + STATUS_ONLINE, + I18N_NOOP("Online"), + "LiveJournal_online", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + STATUS_OFFLINE, + I18N_NOOP("Offline"), + "LiveJournal_offline", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef () + }; + +const CommandDef *LiveJournalProtocol::statusList() +{ + return livejournal_status_list; +} + +static DataDef liveJournalUserData[] = + { + { "", DATA_ULONG, 1, DATA(5) }, // Sign + { "LastSend", DATA_ULONG, 1, 0 }, + { "User", DATA_UTF, 1, 0 }, + { "Shared", DATA_BOOL, 1, 0 }, + { "", DATA_BOOL, 1, 0 }, // bChecked + { NULL, DATA_UNKNOWN, 0, 0 } + }; + +/* + char *Server; + char *URL; + unsigned Port; + unsigned Interval; +*/ + +static DataDef liveJournalClientData[] = + { + { "Server", DATA_STRING, 1, "www.livejournal.com" }, + { "URL", DATA_STRING, 1, "/interface/flat" }, + { "Port", DATA_ULONG, 1, DATA(80) }, + { "Interval", DATA_ULONG, 1, DATA(5) }, + { "Mood", DATA_STRLIST, 1, 0 }, + { "Moods", DATA_ULONG, 1, 0 }, + { "Menu", DATA_STRLIST, 1, 0 }, + { "MenuURL", DATA_STRLIST, 1, 0 }, + { "FastServer", DATA_BOOL, 1, 0 }, + { "UseFormatting", DATA_BOOL, 1, 0 }, + { "UseSignature", DATA_BOOL, 1, DATA(1) }, + { "Signature", DATA_UTF, 1, 0 }, + { "", DATA_STRING, 1, 0 }, // LastUpdate + { "", DATA_STRUCT, sizeof(LiveJournalUserData) / sizeof(Data), DATA(liveJournalUserData) }, + { NULL, DATA_UNKNOWN, 0, 0 } + }; + +const DataDef *LiveJournalProtocol::userDataDef() +{ + return liveJournalUserData; +} + +LiveJournalClient::LiveJournalClient(Protocol *proto, Buffer *cfg) + : TCPClient(proto, cfg) +{ + load_data(liveJournalClientData, &data, cfg); + m_request = NULL; + m_timer = new QTimer(this); +} + +LiveJournalClient::~LiveJournalClient() +{ + if (m_request) + delete m_request; + free_data(liveJournalClientData, &data); +} + +QByteArray LiveJournalClient::getConfig() +{ + QByteArray cfg = TCPClient::getConfig(); + QByteArray my_cfg = save_data(liveJournalClientData, &data); + if (!my_cfg.isEmpty()){ + if (!cfg.isEmpty()) + cfg += "\n"; + cfg += my_cfg; + } + return cfg; +} + +class MessageRequest : public LiveJournalRequest +{ +public: + MessageRequest(LiveJournalClient *client, JournalMessage *msg, const QString &journal); + ~MessageRequest(); +protected: + void result(const QString &key, const QString &value); + JournalMessage *m_msg; + QString m_err; + unsigned m_id; + bool m_bResult; + bool m_bEdit; +}; + +class BRParser : public HTMLParser +{ +public: + BRParser(unsigned color); + QString m_str; + void parse(const QString&); +protected: + virtual void text(const QString &text); + virtual void tag_start(const QString &tag, const list &options); + virtual void tag_end(const QString &tag); + virtual void add_color(); + bool m_bSkip; + unsigned m_color; +}; + +BRParser::BRParser(unsigned color) +{ + m_color = color; + m_bSkip = false; + add_color(); +} + +void BRParser::parse(const QString &str) +{ + HTMLParser::parse(str); + m_str += "
"; +} + +void BRParser::text(const QString &text) +{ + if (m_bSkip) + return; + QString s = text; + s = s.remove('\r'); + s = s.remove('\n'); + m_str += s; +} + +void BRParser::tag_start(const QString &tag, const list &attrs) +{ + if (m_bSkip) + return; + if (tag == "body"){ + m_str = ""; + add_color(); + return; + } + if (tag == "p"){ + return; + } + if (tag == "br"){ + m_str += "
\n"; + add_color(); + return; + } + m_str += "<"; + m_str += tag; + for (list::const_iterator it = attrs.begin(); it != attrs.end(); ++it){ + QString name = *it; + ++it; + QString value = *it; + m_str += " "; + m_str += name; + if (!value.isEmpty()){ + m_str += "=\'"; + m_str += quoteString(value); + m_str += "\'"; + } + } + m_str += ">"; +} + +void BRParser::tag_end(const QString &tag) +{ + if (m_bSkip) + return; + if (tag == "body"){ + m_bSkip = true; + return; + } + if (tag == "p"){ + m_str += "
\n"; + add_color(); + return; + } + m_str += ""; +} + +void BRParser::add_color() +{ + QString s; + s.sprintf("", m_color & 0xFFFFFF); + m_str += s; +} + +MessageRequest::MessageRequest(LiveJournalClient *client, JournalMessage *msg, const QString &journal) + : LiveJournalRequest(client, msg->getID() ? "editevent" : "postevent") +{ + m_msg = msg; + m_bEdit = (msg->getID() != 0); + m_bResult = false; + QString text; + if (msg->getRichText().isEmpty()){ + text = QString::null; + }else{ + // if (msg->getFlags() & MESSAGE_RICHTEXT){ + if (client->getUseFormatting()){ + BRParser parser(msg->getBackground()); + parser.parse(msg->getRichText()); + text = parser.m_str; + }else{ + text = msg->getPlainText(); + } + addParam("subject", msg->getSubject()); + } + if (!m_bEdit && client->getUseSignature()) + text += "\n" + client->getSignatureText(); + addParam("event", text); + addParam("lineendings", "unix"); + if (msg->getID()) + addParam("itemid", QString::number(msg->getID())); + if (msg->getTime() == 0) + msg->setTime(QDateTime::currentDateTime().toTime_t()); + QDateTime now = QDateTime::fromTime_t( msg->getTime() ); + now = now.toLocalTime(); + addParam("year", QString::number(now.date().year() + 1900)); + addParam("mon", QString::number(now.date().month() + 1)); + addParam("day", QString::number(now.date().day())); + addParam("hour", QString::number(now.time().hour())); + addParam("min", QString::number(now.time().minute())); + if (msg->getPrivate()){ + switch (msg->getPrivate()){ + case 0: + addParam("security", "public"); + break; + case 1: + addParam("security", "usemask"); + addParam("allowmask", "0"); + break; + case 2: + addParam("security", "private"); + break; + } + } + if (msg->getMood()) + addParam("prop_current_moodid", QString::number(msg->getMood())); + if (!journal.isEmpty()) + addParam("usejournal", journal); + if (msg->getComments() == COMMENT_NO_MAIL){ + addParam("prop%5Fopt%5Fnoemail", "1"); + }else if (msg->getComments() == COMMENT_DISABLE){ + addParam("prop%5Fopt%5Fnocomments", "1"); + } +} + +MessageRequest::~MessageRequest() +{ + if (m_bResult){ + if ((m_msg->getFlags() & MESSAGE_NOHISTORY) == 0){ + if (m_bEdit){ + m_msg->setId(m_msg->getOldID()); + if (m_msg->getRichText().isEmpty()){ + EventDeleteMessage(m_msg).process(); + }else{ + EventRewriteMessage(m_msg).process(); + } + }else{ + m_msg->setID(m_id); + EventSent(m_msg).process(); + } + } + }else{ + if (m_err.isEmpty()) + m_err = I18N_NOOP("Posting failed"); + m_msg->setError(m_err); + } + EventMessageSent(m_msg).process(); + delete m_msg; +} + +void MessageRequest::result(const QString &key, const QString &value) +{ + if (key == "errmsg") + m_err = value; + if (key == "success" && value == "OK") + m_bResult = true; + if (key == "itemid") + m_id = value.toUInt(); +} + +bool LiveJournalClient::send(Message *msg, void *_data) +{ + if (!canSend(msg->type(), _data)) + return false; + LiveJournalUserData *data = toLiveJournalUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + QString journal; + if (data->User.str() != this->data.owner.User.str()) + journal = data->User.str(); + m_requests.push_back(new MessageRequest(this, static_cast(msg), journal)); + msg->setClient(dataName(_data)); + send(); + return true; +} + +bool LiveJournalClient::canSend(unsigned type, void *_data) +{ + if ((_data == NULL) || (((clientData*)_data)->Sign.toULong() != LIVEJOURNAL_SIGN)) + return false; + if (type == MessageJournal){ + if (getState() != Connected) + return false; + return true; + } + if (type == CmdMenuWeb){ + LiveJournalUserData *data = toLiveJournalUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + if (data->User.str() != this->data.owner.User.str()) + return false; + return true; + } + return false; +} + +void LiveJournalClient::setupContact(Contact*, void*) +{ +} + +bool LiveJournalClient::createData(clientData*&, Contact*) +{ + return false; +} + +bool LiveJournalClient::isMyData(clientData *&data, Contact*&) +{ + if (data->Sign.toULong() != LIVEJOURNAL_SIGN) + return false; + return false; +} + +QString LiveJournalClient::dataName(void *data) +{ + QString res = name(); + res += "."; + res += toLiveJournalUserData((SIM::clientData*)data)->User.str(); // FIXME unsafe type conversion + return res; +} + +QString LiveJournalClient::name() +{ + return "LiveJournal." + data.owner.User.str(); +} + +QWidget *LiveJournalClient::setupWnd() +{ + return new LiveJournalCfg(NULL, this, true); +} + +void LiveJournalClient::socketConnect() +{ + connect_ready(); + setStatus(STATUS_ONLINE); +} + +const unsigned MAIN_INFO = 1; + +static CommandDef cfgLiveJournalWnd[] = + { + CommandDef ( + MAIN_INFO, + " ", + "LiveJournal", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef () + }; + +CommandDef *LiveJournalClient::configWindows() +{ + QString title =name(); + int n = title.indexOf('.'); + if (n > 0) + title = title.left(n) + ' ' + title.mid(n + 1); + cfgLiveJournalWnd[0].text_wrk = title; + return cfgLiveJournalWnd; +} + +QWidget *LiveJournalClient::configWindow(QWidget *parent, unsigned id) +{ + if (id == MAIN_INFO) + return new LiveJournalCfg(parent, this, false); + return NULL; +} + +bool LiveJournalClient::add(const QString &name) +{ + Contact *contact; + LiveJournalUserData *data = findContact(name, contact, false); + if (data) + return false; + findContact(name, contact); + return true; +} + +LiveJournalUserData *LiveJournalClient::findContact(const QString &user, Contact *&contact, bool bCreate, bool bJoin) +{ + ContactList::ContactIterator it; + while ((contact = ++it) != NULL){ + LiveJournalUserData *data; + ClientDataIterator itc(contact->clientData, this); + while ((data = toLiveJournalUserData(++itc)) != NULL){ + if (data->User.str() == user) + return data; + } + } + if (!bCreate) + return NULL; + if (bJoin){ + it.reset(); + while ((contact = ++it) != NULL){ + if (contact->getName().toLower() == user.toLower()) + break;; + } + } + if (contact == NULL){ + contact = getContacts()->contact(0, true); + contact->setName(user); + } + LiveJournalUserData *data = toLiveJournalUserData((SIM::clientData*)contact->clientData.createData(this)); // FIXME unsafe type conversion + data->User.str() = user; + EventContact e(contact, EventContact::eChanged); + e.process(); + return data; +} + +void LiveJournalClient::auth_ok() +{ + m_status = STATUS_ONLINE; + setState(Connected); + setPreviousPassword(QString::null); + statusChanged(); + list forDelete; + Contact *contact; + ContactList::ContactIterator it; + while ((contact = ++it) != NULL){ + LiveJournalUserData *data; + ClientDataIterator itc(contact->clientData, this); + while ((data = toLiveJournalUserData(++itc)) != NULL){ + if (!data->Shared.toBool()) + continue; + if (data->bChecked.toBool()) + continue; + contact->clientData.freeData(data); + if (contact->clientData.size() == 0) + forDelete.push_back(contact); + break; + } + } + for (list::iterator itc = forDelete.begin(); itc != forDelete.end(); ++itc) + delete (*itc); + QTimer::singleShot(0, this, SLOT(timeout())); +} + +void LiveJournalClient::statusChanged() +{ + Contact *contact = NULL; + ContactList::ContactIterator it; + while ((contact = ++it) != NULL){ + ClientDataIterator itc(contact->clientData, this); + if ((++itc) != NULL){ + EventContact e(contact, EventContact::eChanged); + e.process(); + } + } + findContact(data.owner.User.str(), contact); +} + +QString LiveJournalClient::getSignatureText() +{ + QString res = getSignature(); + if (res.isEmpty()) + res = i18n(""); + return res; +} + +static void addIcon(QSet *s, const QString &icon, const QString &statusIcon) +{ + if (!s || statusIcon == icon) + return; + s->insert(icon); +} + +void LiveJournalClient::contactInfo(void*, unsigned long &curStatus, unsigned&, QString &statusIcon, QSet *icons) +{ + unsigned long status = STATUS_OFFLINE; + const char *dicon = "LiveJournal_offline"; + if ((getState() == Connected) && (m_status != STATUS_OFFLINE)){ + status = STATUS_ONLINE; + dicon = "LiveJournal_online"; + } + if (status > curStatus){ + curStatus = status; + if (!statusIcon.isEmpty() && icons){ + icons->insert(statusIcon); + } + statusIcon = dicon; + }else{ + if (!statusIcon.isEmpty()){ + addIcon(icons, dicon, statusIcon); + }else{ + statusIcon = dicon; + } + } +} + +struct Mood +{ + unsigned id; + QString name; +}; + +class LoginRequest : public LiveJournalRequest +{ +public: + LoginRequest(LiveJournalClient *client); + ~LoginRequest(); +protected: + void result(const QString &key, const QString &value); + bool m_bOK; + bool m_bResult; + vector m_moods; + QString m_err; +}; + +LoginRequest::LoginRequest(LiveJournalClient *client) + : LiveJournalRequest(client, "login") +{ + m_bOK = false; + m_bResult = false; +} + +LoginRequest::~LoginRequest() +{ + if (m_bOK){ + for (unsigned i = 0; i < m_moods.size(); i++){ + if (m_moods[i].name.isEmpty()) + continue; + if (m_client->getMoods() < m_moods[i].id) + m_client->setMoods(m_moods[i].id); + m_client->setMood(i, m_moods[i].name); + } + m_client->auth_ok(); + }else{ + if (!m_bResult) + return; + if (m_err.isEmpty()) + m_err = I18N_NOOP("Login failed"); + m_client->auth_fail(m_err); + } + EventClientChanged(m_client).process(); +} + +void LoginRequest::result(const QString &key, const QString &value) +{ + m_bResult = true; + if (key == "success" && value == "OK"){ + m_bOK = true; + return; + } + if (key == "errmsg"){ + m_err = value; + return; + } + QString k = key; + QString prefix = getToken(k, '_'); + if (prefix == "mood"){ + prefix = getToken(k, '_'); + unsigned id = prefix.toUInt(); + if (id == 0) + return; + while (m_moods.size() <= id){ + Mood m; + m_moods.push_back(m); + } + if (k == "id") + m_moods[id].id = value.toUInt(); + if (k == "name") + m_moods[id].name = value; + } + if (prefix == "menu"){ + prefix = getToken(k, '_'); + unsigned menu_id = prefix.toUInt(); + prefix = getToken(k, '_'); + unsigned item_id = prefix.toUInt(); + if (item_id == 0) + return; + unsigned id = menu_id * 0x100 + item_id; + if (k == "text") + m_client->setMenu(id, value); + if (k == "url") + m_client->setMenuUrl(id, value); + if (k == "sub"){ + QString v = "@"; + v += value; + m_client->setMenuUrl(id, v); + } + } + if (prefix == "access"){ + if (k.toULong() == 0) + return; + Contact *contact; + LiveJournalUserData *data = m_client->findContact(value, contact); + if (data){ + data->bChecked.asBool() = true; + data->Shared.asBool() = true; + } + } +} + +void LiveJournalClient::setStatus(unsigned status) +{ + if (status == STATUS_OFFLINE) + return; + Contact *contact; + ContactList::ContactIterator it; + while ((contact = ++it) != NULL){ + LiveJournalUserData *data; + ClientDataIterator itc(contact->clientData, this); + while ((data = toLiveJournalUserData(++itc)) != NULL){ + data->bChecked.asBool() = false; + if (data->User.str() == this->data.owner.User.str()) + data->bChecked.asBool() = true; + } + } + LiveJournalRequest *req = new LoginRequest(this); + QString version; +#ifdef WIN32 + version = "Win32"; +#else +#ifdef Q_OS_MAC + version = "MacOS"; +#else + version = "Qt"; +#endif +#endif + version += "-" PACKAGE "/" VERSION; + req->addParam("clientversion", version); + req->addParam("getmoods", QString::number(getMoods())); + req->addParam("getmenus", "1"); + m_requests.push_back(req); + send(); +} + +void LiveJournalClient::disconnected() +{ + m_timer->stop(); + statusChanged(); +} + +void LiveJournalClient::packet_ready() +{ +} + +void LiveJournalClient::auth_fail(const QString &err) +{ + m_reconnect = NO_RECONNECT; + error_state(err, AuthError); +} + +QWidget *LiveJournalClient::searchWindow(QWidget *parent) +{ + return new JournalSearch(this, parent); +} + +bool LiveJournalClient::done(unsigned code, Buffer &data, const QString &) +{ + if (code == 200){ + m_request->result(&data); + }else{ + QString err = "Fetch error "; + err += QString::number(code); + error_state(err, 0); + statusChanged(); + } + delete m_request; + m_request = NULL; + send(); + return false; +} + +bool LiveJournalClient::processEvent(Event *e) +{ + TCPClient::processEvent(e); + if (e->type() == eEventOpenMessage){ + EventMessage *em = static_cast(e); + Message *msg = em->msg(); + if (msg->type() != MessageUpdated) + return false; + if (dataName(&data.owner) != msg->client()) + return false; + EventMessageDeleted(msg).process(); + QString url = "http://"; + url += getServer(); + if (getPort() != 80){ + url += ":"; + url += QString::number(getPort()); + } + url += '/'; + EventGoURL(url).process(); + if (getState() == Connected) { + m_timer->setSingleShot(true); + m_timer->start(getInterval() * 60 * 1000); + } + return true; + } + if (e->type() == eEventCommandExec){ + EventCommandExec *ece = static_cast(e); + CommandDef *cmd = ece->cmd(); + if (cmd->id == CmdDeleteJournalMessage){ + Message *msg = (Message*)(cmd->param); + Contact *contact = getContacts()->contact(msg->contact()); + if (contact == NULL) + return false; + LiveJournalUserData *data; + ClientDataIterator it(contact->clientData, this); + while ((data = toLiveJournalUserData(++it)) != NULL){ + if (dataName(data) == msg->client()){ + Buffer cfg; + cfg = "[Title]\n" + msg->save(); + cfg.setWritePos(0); + cfg.getSection(); + JournalMessage *m = new JournalMessage(&cfg); + m->setContact(msg->contact()); + m->setOldID(msg->id()); + m->setText(""); + if (!send(m, data)) + delete m; + return true; + } + } + return false; + } + unsigned menu_id = cmd->menu_id - MenuWeb; + if (menu_id > LiveJournalPlugin::MenuCount) + return false; + unsigned item_id = cmd->id - CmdMenuWeb; + if ((item_id == 0) || (item_id >= 0x100)) + return false; + QString url = getMenuUrl(menu_id * 0x100 + item_id); + if (url.isEmpty()) + return false; + EventGoURL eUrl(url); + eUrl.process(); + return true; + } else + if (e->type() == eEventCheckCommandState){ + EventCheckCommandState *ecs = static_cast(e); + CommandDef *cmd = ecs->cmd(); + if (cmd->id == CmdMenuWeb){ + unsigned menu_id = cmd->menu_id - MenuWeb; + if (menu_id > LiveJournalPlugin::MenuCount) + return false; + unsigned nItems = 0; + unsigned list_id = menu_id * 0x100 + 1; + for (;;){ + if (getMenu(list_id).isEmpty()) + break; + nItems++; + list_id++; + } + if (nItems == 0) + return false; + CommandDef *cmds = new CommandDef[nItems + 1]; + list_id = menu_id * 0x100 + 1; + for (unsigned i = 0;; i++){ + QString text = getMenu(list_id); + if (text.isEmpty()) + break; + cmds[i].text = "_"; + if (text != "-"){ + cmds[i].id = CmdMenuWeb + i + 1; + cmds[i].text = "_"; + cmds[i].text_wrk = i18n(text); + QString url = getMenuUrl(list_id); + if (url.startsWith("@")){ + url = url.mid(1); + unsigned nSub = url.toUInt(); + while (nSub > LiveJournalPlugin::MenuCount){ + unsigned long menu_id = MenuWeb + (++LiveJournalPlugin::MenuCount); + EventMenu(menu_id, EventMenu::eAdd).process(); + CommandDef c; + c.id = CmdMenuWeb; + c.text = "_"; + c.menu_id = menu_id; + c.menu_grp = 0x1000; + c.flags = COMMAND_CHECK_STATE; + EventCommandCreate(&c).process(); + } + cmds[i].popup_id = MenuWeb + nSub; + } + }else{ + cmds[i].id = 0; + } + list_id++; + } + cmd->param = cmds; + cmd->flags |= COMMAND_RECURSIVE; + return true; + } + } + return false; +} + +void LiveJournalClient::send() +{ + if ((m_requests.size() == 0) || m_request) + return; + m_request = m_requests.front(); + m_requests.erase(m_requests.begin()); + QString url; + url = "http://"; + url += getServer(); + if (getPort() != 80){ + url += ":"; + url += QString::number(getPort()); + } + url += getURL(); + QString headers = "Content-Type: application/x-www-form-urlencoded"; + if (getFastServer()) + headers += "\nCookie: ljfastserver=1"; + fetch(url, headers, m_request->m_buffer); + m_request->m_buffer = NULL; +} + +bool LiveJournalClient::error_state(const QString &err, unsigned code) +{ + return TCPClient::error_state(err, code); +} + +class CheckFriendsRequest : public LiveJournalRequest +{ +public: + CheckFriendsRequest(LiveJournalClient *client); + ~CheckFriendsRequest(); +protected: + void result(const QString &key, const QString &value); + bool m_bOK; + bool m_bChanged; + unsigned m_interval; + QString m_err; +}; + +CheckFriendsRequest::CheckFriendsRequest(LiveJournalClient *client) + : LiveJournalRequest(client, "checkfriends") +{ + m_bOK = false; + m_bChanged = false; + m_interval = 0; + addParam("lastupdate", client->getLastUpdate()); +} + +void LiveJournalClient::messageUpdated() +{ + Contact *contact; + LiveJournalUserData *data = findContact(this->data.owner.User.str(), contact); + if (data == NULL) + return; + Message *msg = new Message(MessageUpdated); + msg->setContact(contact->id()); + msg->setClient(dataName(data)); + msg->setFlags(MESSAGE_TEMP | MESSAGE_NOVIEW); + EventMessageReceived e(msg); + if (!e.process()) + delete msg; +} + +CheckFriendsRequest::~CheckFriendsRequest() +{ + if (m_bChanged){ + m_client->messageUpdated(); + return; + } + if (m_bOK){ + m_client->m_timer->setSingleShot( true ); + m_client->m_timer->start( m_interval ); + return; + } + m_client->error_state(m_err, 0); +} + +void CheckFriendsRequest::result(const QString &key, const QString &value) +{ + if (key == "success" && value == "OK"){ + m_bOK = true; + return; + } + if (key == "lastupdate"){ + m_client->setLastUpdate(value); + return; + } + if (key == "new"){ + if (value.toULong()) + m_bChanged = true; + return; + } + if (key == "interval"){ + m_interval = value.toUInt(); + return; + } + if (key == "errmsg"){ + m_err = value; + return; + } +} + +void LiveJournalClient::timeout() +{ + if (getState() != Connected) + return; + m_timer->stop(); + m_requests.push_back(new CheckFriendsRequest(this)); + send(); +} + + +LiveJournalUserData* LiveJournalClient::toLiveJournalUserData(SIM::clientData * data) +{ + // This function is used to more safely preform type conversion from SIM::clientData* into LiveJournalUserData* + // It will at least warn if the content of the structure is not LiveJournalUserData* + // Brave wariors may uncomment abort() function call to know for sure about wrong conversion ;-) + if (! data) return NULL; + if (data->Sign.asULong() != LIVEJOURNAL_SIGN) + { + QString Signs[] = { + "Unknown(0)" , // 0x0000 + "ICQ_SIGN", // 0x0001 + "JABBER_SIGN", // 0x0002 + "MSN_SIGN", // 0x0003 + "Unknown(4)" // 0x0004 + "LIVEJOURNAL_SIGN",// 0x0005 + "SMS_SIGN", // 0x0006 + "Unknown(7)", // 0x0007 + "Unknown(8)", // 0x0008 + "YAHOO_SIGN" // 0x0009 + }; + QString Sign; + if (data->Sign.toULong()<=9) // is always >=0 as it is unsigned int + Sign = Signs[data->Sign.toULong()]; + else + Sign = QString("Unknown(%1)").arg(Sign.toULong()); + + log(L_ERROR, + "ATTENTION!! Unsafly converting %s user data into LIVEJOURNAL_SIGN", + qPrintable(Sign)); +// abort(); + } + return (LiveJournalUserData*) data; +} + +LiveJournalRequest::LiveJournalRequest(LiveJournalClient *client, const char *mode) +{ + m_client = client; + m_buffer = new Buffer; + addParam("mode", mode); + addParam("ver", "1"); + if (!client->data.owner.User.str().isEmpty()) + addParam("user", client->data.owner.User.str()); + QByteArray pass = QCryptographicHash::hash(client->getPassword().toUtf8(), QCryptographicHash::Md5); + QString hpass; + for (int i = 0; i < pass.size(); i++){ + char b[5]; + sprintf(b, "%02x", pass[(int)i] & 0xFF); + hpass += b; + } + addParam("hpassword", hpass); +} + +LiveJournalRequest::~LiveJournalRequest() +{ + if (m_buffer) + delete m_buffer; +} + +void LiveJournalRequest::addParam(const QString &key, const QString &value) +{ + if (m_buffer->size()) + m_buffer->pack("&", 1); + m_buffer->pack(key.toUtf8(), key.toUtf8().length()); + m_buffer->pack("=", 1); + QByteArray cstr = value.toUtf8(); + for (int i = 0; i < cstr.length(); i++){ + char c = cstr[(int)i]; + if (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) || ((c >= '0') && (c <= '9')) || + (c == '.') || (c == '-') || (c == '/') || (c == '_')){ + m_buffer->pack(&c, 1); + }else{ + char buf[4]; + sprintf(buf, "%%%02X", c & 0xFF); + m_buffer->pack(buf, 3); + } + } +} + +void LiveJournalRequest::result(Buffer *b) +{ + for (;;){ + QByteArray key; + QByteArray value; + if (!getLine(b, key) || !getLine(b, value)) + break; + log(L_DEBUG, "Result: %s=%s", key.data(), value.data()); + result(QString::fromUtf8(key), QString::fromUtf8(value)); + } +} + +bool LiveJournalRequest::getLine(Buffer *b, QByteArray &line) +{ + if (b == NULL) + return false; + if (!b->scan("\n", line)) + return false; + if (line.length() && (line[(int)line.length() - 1] == '\r')) + line = line.left(line.length() - 1); + return true; +} + +#if 0 +I18N_NOOP("Invalid username") + +I18N_NOOP("aggravated") +I18N_NOOP("angry") +I18N_NOOP("annoyed") +I18N_NOOP("anxious") +I18N_NOOP("bored") +I18N_NOOP("confused") +I18N_NOOP("crappy") +I18N_NOOP("cranky") +I18N_NOOP("depressed") +I18N_NOOP("discontent") +I18N_NOOP("energetic") +I18N_NOOP("enraged") +I18N_NOOP("enthralled") +I18N_NOOP("exhausted") +I18N_NOOP("happy") +I18N_NOOP("high") +I18N_NOOP("horny") +I18N_NOOP("hungry") +I18N_NOOP("infuriated") +I18N_NOOP("irate") +I18N_NOOP("jubilant") +I18N_NOOP("lonely") +I18N_NOOP("moody") +I18N_NOOP("pissed off") +I18N_NOOP("sad") +I18N_NOOP("satisfied") +I18N_NOOP("sore") +I18N_NOOP("stressed") +I18N_NOOP("thirsty") +I18N_NOOP("thoughtful") +I18N_NOOP("tired") +I18N_NOOP("touched") +I18N_NOOP("lazy") +I18N_NOOP("drunk") +I18N_NOOP("ditzy") +I18N_NOOP("mischievous") +I18N_NOOP("morose") +I18N_NOOP("gloomy") +I18N_NOOP("melancholy") +I18N_NOOP("drained") +I18N_NOOP("excited") +I18N_NOOP("relieved") +I18N_NOOP("hopeful") +I18N_NOOP("amused") +I18N_NOOP("determined") +I18N_NOOP("scared") +I18N_NOOP("frustrated") +I18N_NOOP("indescribable") +I18N_NOOP("sleepy") +I18N_NOOP("groggy") +I18N_NOOP("hyper") +I18N_NOOP("relaxed") +I18N_NOOP("restless") +I18N_NOOP("disappointed") +I18N_NOOP("curious") +I18N_NOOP("mellow") +I18N_NOOP("peaceful") +I18N_NOOP("bouncy") +I18N_NOOP("nostalgic") +I18N_NOOP("okay") +I18N_NOOP("rejuvenated") +I18N_NOOP("complacent") +I18N_NOOP("content") +I18N_NOOP("indifferent") +I18N_NOOP("silly") +I18N_NOOP("flirty") +I18N_NOOP("calm") +I18N_NOOP("refreshed") +I18N_NOOP("optimistic") +I18N_NOOP("pessimistic") +I18N_NOOP("giggly") +I18N_NOOP("pensive") +I18N_NOOP("uncomfortable") +I18N_NOOP("lethargic") +I18N_NOOP("listless") +I18N_NOOP("recumbent") +I18N_NOOP("exanimate") +I18N_NOOP("embarrassed") +I18N_NOOP("envious") +I18N_NOOP("sympathetic") +I18N_NOOP("sick") +I18N_NOOP("hot") +I18N_NOOP("cold") +I18N_NOOP("worried") +I18N_NOOP("loved") +I18N_NOOP("awake") +I18N_NOOP("working") +I18N_NOOP("productive") +I18N_NOOP("accomplished") +I18N_NOOP("busy") +I18N_NOOP("full") +I18N_NOOP("grumpy") +I18N_NOOP("weird") +I18N_NOOP("nauseated") +I18N_NOOP("ecstatic") +I18N_NOOP("chipper") +I18N_NOOP("rushed") +I18N_NOOP("contemplative") +I18N_NOOP("nerdy") +I18N_NOOP("geeky") +I18N_NOOP("cynical") +I18N_NOOP("quixotic") +I18N_NOOP("crazy") +I18N_NOOP("creative") +I18N_NOOP("artistic") +I18N_NOOP("pleased") +I18N_NOOP("bitchy") +I18N_NOOP("guilty") +I18N_NOOP("irritated") +I18N_NOOP("blank") +I18N_NOOP("apathetic") +I18N_NOOP("dorky") +I18N_NOOP("impressed") +I18N_NOOP("naughty") +I18N_NOOP("predatory") +I18N_NOOP("dirty") +I18N_NOOP("giddy") +I18N_NOOP("surprised") +I18N_NOOP("shocked") +I18N_NOOP("rejected") +I18N_NOOP("numb") +I18N_NOOP("cheerful") +I18N_NOOP("good") +I18N_NOOP("distressed") +I18N_NOOP("intimidated") +I18N_NOOP("crushed") +I18N_NOOP("devious") +I18N_NOOP("thankful") +I18N_NOOP("grateful") +I18N_NOOP("jealous") +I18N_NOOP("nervous") + +I18N_NOOP("Recent Entries") +I18N_NOOP("Calendar View") +I18N_NOOP("Friends View") +I18N_NOOP("Your Profile") +I18N_NOOP("Your To-Do List") +I18N_NOOP("Change Settings") +I18N_NOOP("Support") +I18N_NOOP("Personal Info") +I18N_NOOP("Customize Journal") +I18N_NOOP("Journal Settings") +I18N_NOOP("Upgrade your account") + +#endif + + + diff --git a/plugins/livejournal/livejournal.h b/plugins/livejournal/livejournal.h new file mode 100644 index 0000000..04662e7 --- /dev/null +++ b/plugins/livejournal/livejournal.h @@ -0,0 +1,196 @@ +/*************************************************************************** + livejournal.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _LIVEJOURNAL_H +#define _LIVEJOURNAL_H + +#include "buffer.h" +#include "socket/socket.h" +#include "socket/tcpclient.h" +#include "fetch.h" +#include "contacts/client.h" + +#include + +const unsigned long JournalCmdBase = 0x00070000; +const unsigned long MessageJournal = JournalCmdBase; +const unsigned long MessageUpdated = JournalCmdBase + 1; +const unsigned long CmdDeleteJournalMessage = JournalCmdBase + 2; +const unsigned long CmdMenuWeb = JournalCmdBase + 3; +const unsigned long MenuWeb = JournalCmdBase + 0x10; + +const unsigned LIVEJOURNAL_SIGN = 5; + +const unsigned COMMENT_ENABLE = 0; +const unsigned COMMENT_NO_MAIL = 1; +const unsigned COMMENT_DISABLE = 2; + +struct LiveJournalUserData : public SIM::clientData +{ + SIM::Data User; + SIM::Data Shared; + SIM::Data bChecked; +}; + +struct JournalMessageData +{ + SIM::Data Subject; + SIM::Data Private; + SIM::Data Time; + SIM::Data ID; + SIM::Data OldID; + SIM::Data Mood; + SIM::Data Comments; +}; + +class JournalMessage : public SIM::Message +{ +public: + JournalMessage(Buffer *cfg = NULL); + ~JournalMessage(); + virtual QByteArray save(); + PROP_UTF8(Subject); + PROP_ULONG(Private); + PROP_ULONG(Time); + PROP_ULONG(ID); + PROP_ULONG(OldID); + PROP_ULONG(Mood); + PROP_ULONG(Comments); +protected: + QString presentation(); + JournalMessageData data; +}; + +class LiveJournalPlugin : public SIM::Plugin +{ +public: + LiveJournalPlugin(unsigned); + virtual ~LiveJournalPlugin(); + static unsigned MenuCount; +protected: + SIM::Protocol *m_protocol; +}; + +class LiveJournalProtocol : public SIM::Protocol +{ +public: + LiveJournalProtocol(SIM::Plugin *plugin); + ~LiveJournalProtocol(); + SIM::ClientPtr createClient(Buffer *cfg); + const SIM::CommandDef *description(); + const SIM::CommandDef *statusList(); + const SIM::DataDef *userDataDef(); +}; + +struct LiveJournalClientData +{ + SIM::Data Server; + SIM::Data URL; + SIM::Data Port; + SIM::Data Interval; + SIM::Data Mood; + SIM::Data Moods; + SIM::Data Menu; + SIM::Data MenuUrl; + SIM::Data FastServer; + SIM::Data UseFormatting; + SIM::Data UseSignature; + SIM::Data Signature; + SIM::Data LastUpdate; + LiveJournalUserData owner; +}; + +class LiveJournalClient; + +class LiveJournalRequest +{ +public: + LiveJournalRequest(LiveJournalClient *client, const char *mode); + virtual ~LiveJournalRequest(); + void addParam(const QString &key, const QString &value); + void result(Buffer*); + virtual void result(const QString &key, const QString &value) = 0; +protected: + LiveJournalClient *m_client; + Buffer *m_buffer; + bool getLine(Buffer *b, QByteArray &line); + friend class LiveJournalClient; +}; + +class QTimer; + +class LiveJournalClient : public SIM::TCPClient, public FetchClient +{ + Q_OBJECT +public: + LiveJournalClient(SIM::Protocol*, Buffer *cfg); + ~LiveJournalClient(); + PROP_STR(Server); + PROP_STR(URL); + PROP_USHORT(Port); + PROP_ULONG(Interval); + PROP_STRLIST(Mood); + PROP_ULONG(Moods); + PROP_STRLIST(Menu); + PROP_STRLIST(MenuUrl); + PROP_BOOL(FastServer); + PROP_BOOL(UseFormatting); + PROP_BOOL(UseSignature); + PROP_UTF8(Signature); + PROP_STR(LastUpdate); + QString getSignatureText(); + void auth_fail(const QString &err); + void auth_ok(); + LiveJournalUserData *findContact(const QString &user, SIM::Contact *&contact, bool bCreate=true, bool bJoin=true); + QTimer *m_timer; + virtual bool error_state(const QString &err, unsigned code); + bool add(const QString &name); + LiveJournalUserData* toLiveJournalUserData(SIM::clientData * data); // More safely type conversion from generic SIM::clientData into LiveJournalUserData +public slots: + void timeout(); + void send(); + void messageUpdated(); +protected: + virtual bool done(unsigned code, Buffer &data, const QString &headers); + virtual QByteArray getConfig(); + virtual QString name(); + virtual QString dataName(void*); + virtual QWidget *setupWnd(); + virtual bool isMyData(SIM::clientData*&, SIM::Contact*&); + virtual bool createData(SIM::clientData*&, SIM::Contact*); + virtual void setupContact(SIM::Contact*, void *data); + virtual bool send(SIM::Message*, void *data); + virtual bool canSend(unsigned type, void *data); + virtual void setStatus(unsigned status); + virtual void socketConnect(); + virtual void disconnected(); + virtual void packet_ready(); + virtual bool processEvent(SIM::Event *e); + virtual void contactInfo(void*, unsigned long &curStatus, unsigned&, QString &statusIcon, QSet *icons); + QWidget *searchWindow(QWidget *parent); + SIM::CommandDef *configWindows(); + QWidget *configWindow(QWidget *parent, unsigned id); + void statusChanged(); + std::list m_requests; + LiveJournalRequest *m_request; + LiveJournalClientData data; + friend class LiveJournalCfg; + friend class LiveJournalRequest; +}; + +#endif + diff --git a/plugins/livejournal/livejournal.rc b/plugins/livejournal/livejournal.rc new file mode 100644 index 0000000..4126418 --- /dev/null +++ b/plugins/livejournal/livejournal.rc @@ -0,0 +1,97 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,0,0,0 + PRODUCTVERSION 0,0,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Vladimir Shutoff\0" + VALUE "FileDescription", "LiveJournal plugin\0" + VALUE "FileVersion", "0, 9, 6, 0\0" + VALUE "InternalName", "livejournal\0" + VALUE "LegalCopyright", "Copyright © 2002-2003\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "livejournal.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "SIM\0" + VALUE "ProductVersion", "0, 9, 6, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/livejournal/livejournal.vcproj b/plugins/livejournal/livejournal.vcproj new file mode 100644 index 0000000..da71fd8 --- /dev/null +++ b/plugins/livejournal/livejournal.vcproj @@ -0,0 +1,601 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/livejournal/livejournalcfg.cpp b/plugins/livejournal/livejournalcfg.cpp new file mode 100644 index 0000000..80793b6 --- /dev/null +++ b/plugins/livejournal/livejournalcfg.cpp @@ -0,0 +1,99 @@ +/*************************************************************************** + livejournalcfg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include +#include + +#include "simgui/linklabel.h" +#include "misc.h" + +#include "livejournalcfg.h" +#include "livejournal.h" + +using namespace SIM; + +LiveJournalCfg::LiveJournalCfg(QWidget *parent, LiveJournalClient *client, bool bConfig) + : QWidget(parent) +{ + setupUi(this); + m_client = client; + m_bConfig = bConfig; + edtName->setText(client->data.owner.User.str()); + if (bConfig){ + edtPassword->setText(client->getPassword()); + lblLnk->setText(i18n("Register new user")); + lblLnk->setUrl("http://www.livejournal.com/create.bml"); + }else{ + edtName->setReadOnly(true); + edtPassword->hide(); + lblPassword->hide(); + } + edtServer->setText(client->getServer()); + edtPath->setText(client->getURL()); + edtPort->setValue(client->getPort()); + edtInterval->setValue(client->getInterval()); + chkFastServer->setChecked(client->getFastServer()); + chkUseFormatting->setChecked(client->getUseFormatting()); + chkUseSignature->setChecked(client->getUseSignature()); + edtSignature->setPlainText(client->getSignatureText()); + connect(edtName, SIGNAL(textChanged(const QString&)), this, SLOT(changed(const QString&))); + connect(edtPassword, SIGNAL(textChanged(const QString&)), this, SLOT(changed(const QString&))); + connect(chkUseSignature, SIGNAL(toggled(bool)), this, SLOT(useSigToggled(bool))); + useSigToggled(chkUseSignature->isChecked()); + changed(""); + QTimer::singleShot(0, this, SLOT(changed())); +} + +void LiveJournalCfg::changed(const QString&) +{ + changed(); +} + +void LiveJournalCfg::changed() +{ + emit okEnabled(!edtName->text().isEmpty() && !edtPassword->text().isEmpty()); +} + +void LiveJournalCfg::apply() +{ + if (m_bConfig){ + m_client->data.owner.User.str() = edtName->text(); + m_client->setPassword(edtPassword->text()); + } + m_client->setServer(edtServer->text()); + m_client->setURL(edtPath->text()); + m_client->setPort(edtPort->text().toUShort()); + m_client->setInterval(edtInterval->text().toULong()); + m_client->setFastServer(chkFastServer->isChecked()); + m_client->setUseFormatting(chkUseFormatting->isChecked()); + m_client->setUseSignature(chkUseSignature->isChecked()); + if (edtSignature->toPlainText() != m_client->getSignatureText()) + m_client->setSignature(edtSignature->toPlainText()); +} + +void LiveJournalCfg::apply(Client*, void*) +{ +} + +void LiveJournalCfg::useSigToggled(bool value) +{ + edtSignature->setEnabled(value); +} + + diff --git a/plugins/livejournal/livejournalcfg.h b/plugins/livejournal/livejournalcfg.h new file mode 100644 index 0000000..c1a0d1c --- /dev/null +++ b/plugins/livejournal/livejournalcfg.h @@ -0,0 +1,46 @@ +/*************************************************************************** + livejournalcfg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _LIVEJOURNALCFG_H +#define _LIVEJOURNALCFG_H + +#include "contacts.h" + +#include "ui_livejournalcfgbase.h" + +class LiveJournalClient; + +class LiveJournalCfg : public QWidget, public Ui::LiveJournalCfgBase +{ + Q_OBJECT +public: + LiveJournalCfg(QWidget*, LiveJournalClient*, bool bConfig); +signals: + void okEnabled(bool); +public slots: + void apply(); + void apply(SIM::Client*, void*); + void changed(const QString&); + void changed(); + void useSigToggled(bool); +protected: + LiveJournalClient *m_client; + bool m_bConfig; +}; + +#endif + diff --git a/plugins/livejournal/livejournalcfgbase.ui b/plugins/livejournal/livejournalcfgbase.ui new file mode 100644 index 0000000..97cca28 --- /dev/null +++ b/plugins/livejournal/livejournalcfgbase.ui @@ -0,0 +1,301 @@ + + + LiveJournalCfgBase + + + + 0 + 0 + 322 + 280 + + + + Form1 + + + + 6 + + + 11 + + + + + + &LiveJournal + + + + 11 + + + 6 + + + + + Username: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Password: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + QLineEdit::Password + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + + + + &Network + + + + 11 + + + 6 + + + + + + + + Server: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + Path: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Port: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + 1 + + + 65535 + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + &Options + + + + 6 + + + 11 + + + + + 6 + + + 0 + + + + + Check interval: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + + 0 + 0 + + + + minutes + + + false + + + + + + + + + Use &fast server - only for paying customers + + + + + + + Use formatted messages + + + + + + + Add signature to all messages + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + + + + + LinkLabel + QWidget +
simgui/linklabel.h
+
+
+ + +
diff --git a/plugins/livejournal/msgjournal.cpp b/plugins/livejournal/msgjournal.cpp new file mode 100644 index 0000000..c1a7b87 --- /dev/null +++ b/plugins/livejournal/msgjournal.cpp @@ -0,0 +1,212 @@ +/*************************************************************************** + msgjournal.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "msgjournal.h" +#include "livejournal.h" +#include "msgedit.h" +#include "userwnd.h" + +#include "simgui/ballonmsg.h" +#include "simgui/toolbtn.h" +#include "contacts/clientdataiterator.h" +#include "contacts/contact.h" + +#include +#include +#include + +using namespace SIM; + +MsgJournal::MsgJournal(MsgEdit *parent, Message *msg) + : QObject(parent) +{ + m_client = msg->client(); + m_edit = parent; + m_wnd = new MsgJournalWnd(m_edit); + connect(m_wnd, SIGNAL(finished()), this, SLOT(frameDestroyed())); + m_edit->m_layout->insertWidget(0, m_wnd); + m_wnd->show(); + JournalMessage *m = static_cast(msg); + m_ID = m->getID(); + m_oldID = m->id(); + m_time = m->getTime(); + m_wnd->edtSubj->setText(m->getSubject()); + m_wnd->cmbSecurity->setCurrentIndex(m->getPrivate()); + Contact *contact = getContacts()->contact(msg->contact()); + if (contact){ + clientData *data; + ClientDataIterator it(contact->clientData); + while ((data = ++it) != NULL){ + if ((m_client.isEmpty() && (data->Sign.toULong() == LIVEJOURNAL_SIGN)) || + (m_client == it.client()->dataName(data))){ + LiveJournalClient *client = static_cast(it.client()); + for (unsigned i = 1; i < client->getMoods(); i++){ + const QString mood = client->getMood(i); + if (mood.isEmpty()) + continue; + QString s = mood; + QString ts = i18n(mood); + if (s != ts){ + s += " ("; + s += ts; + s += ")"; + } + m_wnd->cmbMood->insertItem(INT_MAX,s); + } + m_wnd->cmbMood->setCurrentIndex(static_cast(msg)->getMood()); + m_wnd->cmbMood->setMinimumSize(m_wnd->cmbMood->sizeHint()); + break; + } + } + } + m_wnd->cmbComment->setCurrentIndex(m->getComments()); + QString text = msg->getRichText(); + if (!text.isEmpty()){ + m_edit->m_edit->setText(text); + m_edit->m_edit->moveCursor(QTextCursor::End, QTextCursor::MoveAnchor); + CorePlugin *core = GET_CorePlugin(); + if ((msg->getBackground() != msg->getForeground()) && !core->property("OwnColors").toBool()){ + m_edit->m_edit->setBackground(msg->getBackground()); + m_edit->m_edit->setForeground(msg->getForeground(), true); + } + } + connect(m_edit->m_edit, SIGNAL(emptyChanged(bool)), this, SLOT(emptyChanged(bool))); + emptyChanged(m_edit->m_edit->isEmpty()); + m_edit->m_edit->setParam(m_edit); +} + +MsgJournal::~MsgJournal() +{ + if (m_wnd) + delete m_wnd; +} + +void MsgJournal::init() +{ + m_wnd->edtSubj->setFocus(); +} + +void MsgJournal::emptyChanged(bool bEmpty) +{ + Command cmd; + cmd->id = CmdSend; + cmd->flags = bEmpty ? COMMAND_DISABLED : 0; + cmd->param = m_edit; + EventCommandDisabled(cmd).process(); +} + +bool MsgJournal::processEvent(Event *e) +{ + if (e->type() == eEventCheckCommandState){ + EventCheckCommandState *ecs = static_cast(e); + CommandDef *cmd = ecs->cmd(); + if (cmd->param == m_edit){ + unsigned id = cmd->bar_grp; + if ((id >= MIN_INPUT_BAR_ID) && (id < MAX_INPUT_BAR_ID)){ + cmd->flags |= BTN_HIDE; + if ((cmd->id == CmdDeleteJournalMessage + CmdReceived) && m_ID) + cmd->flags &= ~BTN_HIDE; + return true; + } + switch (cmd->id){ + case CmdSend: + case CmdSendClose: + e->process(this); + cmd->flags &= ~BTN_HIDE; + return true; + case CmdTranslit: + case CmdSmile: + case CmdNextMessage: + case CmdMsgAnswer: + e->process(this); + cmd->flags |= BTN_HIDE; + return true; + } + } + } else + if (e->type() == eEventCommandExec){ + EventCommandExec *ece = static_cast(e); + CommandDef *cmd = ece->cmd(); + if (cmd->param == m_edit){ + if (cmd->id == CmdSend){ + QString msgText = m_edit->m_edit->toHtml(); + if (!msgText.isEmpty()) + send(msgText); + return true; + } + if (cmd->id == CmdDeleteJournalMessage + CmdReceived){ + QWidget *w = m_edit->m_bar; + Command cmd; + cmd->id = CmdDeleteJournalMessage + CmdReceived; + cmd->param = m_edit; + EventCommandWidget eWidget(cmd); + eWidget.process(); + QWidget *btnRemove = eWidget.widget(); + if (btnRemove) + w = btnRemove; + BalloonMsg::ask(NULL, i18n("Remove record from journal?"), w, SLOT(removeRecord(void*)), NULL, NULL, this); + return true; + } + return false; + } + } + return false; +} + +void MsgJournal::removeRecord(void*) +{ + send(QString::null); +} + +void MsgJournal::send(const QString& msgText) +{ + JournalMessage *msg = new JournalMessage; + msg->setText(msgText); + msg->setContact(m_edit->m_userWnd->id()); + msg->setClient(m_client); + msg->setFlags(MESSAGE_RICHTEXT); + msg->setID(m_ID); + msg->setOldID(m_oldID); + msg->setTime(m_time); + msg->setForeground(m_edit->m_edit->foreground().rgb() & 0xFFFFFF); + msg->setBackground(m_edit->m_edit->background().rgb() & 0xFFFFFF); + CorePlugin *core = GET_CorePlugin(); + msg->setFont(core->property("EditFont").toString()); + msg->setSubject(m_wnd->edtSubj->text()); + msg->setPrivate(m_wnd->cmbSecurity->currentIndex()); + msg->setMood(m_wnd->cmbMood->currentIndex()); + msg->setComments(m_wnd->cmbComment->currentIndex()); + + EventRealSendMessage(msg, m_edit).process(); +} + +void MsgJournal::frameDestroyed() +{ + m_wnd = NULL; +} + +MsgJournalWnd::MsgJournalWnd(QWidget *parent) + : QWidget(parent) +{ + setupUi(this); +} + +MsgJournalWnd::~MsgJournalWnd() +{ + finished(); +} + diff --git a/plugins/livejournal/msgjournal.h b/plugins/livejournal/msgjournal.h new file mode 100644 index 0000000..72273f7 --- /dev/null +++ b/plugins/livejournal/msgjournal.h @@ -0,0 +1,60 @@ +/*************************************************************************** + msgjournal.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _MSGJOURNAL_H +#define _MSGJOURNAL_H + +#include "event.h" + +#include "ui_msgjournalbase.h" + +class MsgEdit; + +class MsgJournalWnd : public QWidget, public Ui::MsgJournalBase +{ + Q_OBJECT +public: + MsgJournalWnd(QWidget*); + ~MsgJournalWnd(); +signals: + void finished(); +}; + +class MsgJournal : public QObject, public SIM::EventReceiver +{ + Q_OBJECT +public: + MsgJournal(MsgEdit *parent, SIM::Message *msg); + ~MsgJournal(); +protected slots: + void init(); + void frameDestroyed(); + void emptyChanged(bool bEmpty); + void removeRecord(void*); +protected: + virtual bool processEvent(SIM::Event *e); + void send(const QString&); + QString m_client; + unsigned m_ID; + unsigned m_oldID; + unsigned m_time; + MsgEdit *m_edit; + MsgJournalWnd *m_wnd; +}; + +#endif + diff --git a/plugins/livejournal/msgjournalbase.ui b/plugins/livejournal/msgjournalbase.ui new file mode 100644 index 0000000..f8b2137 --- /dev/null +++ b/plugins/livejournal/msgjournalbase.ui @@ -0,0 +1,142 @@ + + MsgJournalBase + + + + 0 + 0 + 412 + 81 + + + + + 5 + 1 + 0 + 0 + + + + Form1 + + + + 11 + + + 6 + + + + + 0 + + + 6 + + + + + Subject: + + + false + + + + + + + + + + + + 0 + + + 6 + + + + + Security: + + + false + + + + + + + + Public + + + + + Friends-Only + + + + + Private + + + + + + + + Mood: + + + false + + + + + + + + 7 + 0 + 0 + 0 + + + + + + + + + + + + + + Enable comments + + + + + No email comments + + + + + Disable comments + + + + + + + + + + + diff --git a/plugins/logger/CMakeLists.txt b/plugins/logger/CMakeLists.txt new file mode 100644 index 0000000..eeca586 --- /dev/null +++ b/plugins/logger/CMakeLists.txt @@ -0,0 +1,21 @@ +################## +# logger library # +################## +SET(logger_SRCS + logconfig.cpp + logger.cpp +) + +SET(logger_HDRS + logconfig.h + logger.h +) + +SET(logger_UICS + logconfigbase.ui +) + +REMOVE_DEFINITIONS(-DQT3_SUPPORT) +REMOVE_DEFINITIONS(-DQT_3SUPPORT_LIB) +REMOVE_DEFINITIONS(-DQT3_SUPPORT_WARNINGS) +SIM_ADD_PLUGIN(logger) diff --git a/plugins/logger/logconfig.cpp b/plugins/logger/logconfig.cpp new file mode 100644 index 0000000..3f812a8 --- /dev/null +++ b/plugins/logger/logconfig.cpp @@ -0,0 +1,119 @@ +/*************************************************************************** + logconfig.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include "simgui/editfile.h" +#include "simgui/listview.h" +#include "log.h" +#include "misc.h" + +#include "logconfig.h" +#include "logger.h" + +using namespace SIM; + +const unsigned COL_NAME = 0; +const unsigned COL_CHECK = 1; +const unsigned COL_CHECKED = 2; +const unsigned COL_LEVEL = 3; +const unsigned COL_PACKET = 4; + +LogConfig::LogConfig(QWidget *parent, LoggerPlugin *plugin) + : QWidget(parent) + , m_plugin(plugin) +{ + setupUi(this); + + edtFile->setText(m_plugin->value("File").toString()); + edtFile->setCreate(true); + fill(); +} + +void LogConfig::apply() +{ + unsigned log_level = 0; + /* test if file exist */ + if(!edtFile->text().isEmpty()) { + QFile file(edtFile->text()); + if (!file.open(QIODevice::Append | QIODevice::ReadWrite)) { + log(L_DEBUG,"Logfile %s isn't a valid file - discarded!", qPrintable(edtFile->text())); + edtFile->setText(QString()); + } else { + file.close(); + } + m_plugin->setValue("File", edtFile->text()); + } + + /* check selected protocols */ + for (int row = 0; row < lstLevel->count(); ++row) { + QListWidgetItem *item = lstLevel->item(row); + unsigned level = item->data(Qt::UserRole).toUInt(); + unsigned packet = item->data(Qt::UserRole).toUInt(); + if (item->checkState() == Qt::Checked){ + if (level){ + log_level |= level; + }else{ + m_plugin->setLogType(packet, true); + } + }else{ + if (level == 0) + m_plugin->setLogType(packet, false); + } + } + m_plugin->setValue("LogLevel", log_level); + m_plugin->openFile(); +} + +static QListWidgetItem *createItem(const QString &text, bool bChecked, unsigned id, bool bPacket = false) +{ + QListWidgetItem *item = new QListWidgetItem(text); + item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsUserCheckable|Qt::ItemIsEnabled); + item->setCheckState(bChecked ? Qt::Checked : Qt::Unchecked); + item->setData(bPacket ? Qt::UserRole + 1 : Qt::UserRole, id); + return item; +} + +void LogConfig::fill() +{ + lstLevel->clear(); + + lstLevel->addItem(createItem(i18n("Error"), (m_plugin->value("LogLevel").toUInt() & L_ERROR ) != 0, L_ERROR)); + lstLevel->addItem(createItem(i18n("Warning"), (m_plugin->value("LogLevel").toUInt() & L_WARN ) != 0, L_WARN)); + lstLevel->addItem(createItem(i18n("Debug"), (m_plugin->value("LogLevel").toUInt() & L_DEBUG ) != 0, L_DEBUG)); + lstLevel->addItem(createItem(i18n("Packets"), (m_plugin->value("LogLevel").toUInt() & L_PACKETS) != 0, L_PACKETS)); + //lstLevel->addItem(createItem(i18n("Events"), (m_plugin->getLogLevel() & L_EVENTS ) != 0, L_EVENTS); + + PacketType *type; + ContactList::PacketIterator it; + while ((type = ++it) != NULL){ + lstLevel->addItem(createItem(type->name(), m_plugin->isLogType(type->id()), type->id(), true)); + } +} + +bool LogConfig::processEvent(Event *e) +{ + if ((e->type() == eEventPluginChanged) || (e->type() == eEventLanguageChanged)) + fill(); + return false; +} diff --git a/plugins/logger/logconfig.h b/plugins/logger/logconfig.h new file mode 100644 index 0000000..ab393c5 --- /dev/null +++ b/plugins/logger/logconfig.h @@ -0,0 +1,41 @@ +/*************************************************************************** + logconfig.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _LOGCONFIG_H +#define _LOGCONFIG_H + +#include "event.h" + +#include "ui_logconfigbase.h" + +class LoggerPlugin; + +class LogConfig : public QWidget, public Ui::LogConfigBase, public SIM::EventReceiver +{ + Q_OBJECT +public: + LogConfig(QWidget *parent, LoggerPlugin *plugin); +public slots: + void apply(); +protected: + virtual bool processEvent(SIM::Event *e); + void fill(); + LoggerPlugin *m_plugin; +}; + +#endif + diff --git a/plugins/logger/logconfigbase.ui b/plugins/logger/logconfigbase.ui new file mode 100644 index 0000000..7cfb83d --- /dev/null +++ b/plugins/logger/logconfigbase.ui @@ -0,0 +1,71 @@ + + + LogConfigBase + + + + 0 + 0 + 360 + 308 + + + + Form1 + + + + + + 6 + + + 0 + + + + + File: + + + false + + + + + + + + 0 + 0 + + + + + + + + + + Log level: + + + false + + + + + + + + + + + EditFile + QWidget +
simgui/editfile.h
+
+
+ + +
diff --git a/plugins/logger/logger.cpp b/plugins/logger/logger.cpp new file mode 100644 index 0000000..8eb31c0 --- /dev/null +++ b/plugins/logger/logger.cpp @@ -0,0 +1,249 @@ +/*************************************************************************** + logger.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#ifdef Q_OS_WIN +# include +#endif + +#include "log.h" +#include "misc.h" +#include "profile.h" +#include "profilemanager.h" + +#include "logger.h" +#include "logconfig.h" + +using namespace std; +using namespace SIM; + +Plugin *createLoggerPlugin(unsigned base, bool, Buffer *add_info) +{ + LoggerPlugin *plugin = new LoggerPlugin(base, add_info); + return plugin; +} + +static PluginInfo info = + { + I18N_NOOP("Logger"), + I18N_NOOP("Plugin provides log output\n" + "You can set debug level from command line with -d\n" + "To log errors, set loglevel to 1, for warnings to 2 and for debug-messages to 4\n" + "If you want to log more than one you may add the levels"), + VERSION, + createLoggerPlugin, +#if defined(Q_OS_WIN) || defined(__OS2__) + PLUGIN_NOLOAD_DEFAULT +#else + PLUGIN_DEFAULT +#endif + }; + +EXPORT_PROC PluginInfo* GetPluginInfo() +{ + return &info; +} + +LoggerPlugin::LoggerPlugin(unsigned base, Buffer *add_info) + : QObject() + , Plugin(base) + , m_file(NULL) + , m_bFilter(false) +{ + + m_propertyHub = PropertyHub::create("logger"); + EventArg e("-d:", I18N_NOOP("Set debug level")); + if (e.process()) + setValue("LogLevel", e.value().toUInt()); + const QStringList packets = value("LogPackets").toString().split(','); + Q_FOREACH (const QString &v, packets) { + setLogType(v.toULong(), true); + } + + openFile(); +} + +LoggerPlugin::~LoggerPlugin() +{ + delete m_file; +} + +QByteArray LoggerPlugin::getConfig() +{ + /* + QByteArray packets; + QSetIterator setIt(m_packets); + while(setIt.hasNext()) { + if (packets.length()) + packets += ','; + packets += QByteArray::number(setIt.next()); + } + setValue("LogPackets", packets); + */ + return QByteArray(); +} + +void LoggerPlugin::openFile() +{ +/* + if (m_bFilter){ + if ((getLogLevel() & L_EVENTS) == 0){ + qApp->removeEventFilter(this); + m_bFilter = false; + } + }else{ + if (getLogLevel() & L_EVENTS){ + qApp->installEventFilter(this); + m_bFilter = true; + } + } +*/ + delete m_file; + m_file = NULL; + QString fname = value("File").toString(); + if (fname.isEmpty()) + return; + // This is because sim crashes when a logfile is larger than 100MB ... + QFileInfo fileInfo(fname); + if (fileInfo.size() > 1024 * 1024 * 50) { // 50MB ... + QString desiredFileName = fileInfo.fileName() + ".old"; +#if defined(Q_OS_WIN) || defined(__OS2__) + fileInfo.dir().remove(desiredFileName); +#endif + if (!fileInfo.dir().rename(fileInfo.fileName(), desiredFileName)) { + // won't work --> simply delete... + fileInfo.dir().remove(fileInfo.fileName()); + } + } + // now open file + m_file = new QFile(fname); + if (!m_file->open(QIODevice::Append | QIODevice::ReadWrite)){ + delete m_file; + m_file = NULL; + log(L_WARN, "Can't open %s", qPrintable(fname)); + } +} + +bool LoggerPlugin::isLogType(unsigned id) +{ + return m_packets.contains(id); +} + +void LoggerPlugin::setLogType(unsigned id, bool bLog) +{ + if(bLog) + m_packets.insert(id); + else + m_packets.remove(id); +} +/* +bool LoggerPlugin::eventFilter(QObject *o, QEvent *e) +{ + if (strcmp(o->className(), "QTimer")) + log(L_DEBUG, "Event: %u %s %s", e->type(), o->className(), o->name()); + return QObject::eventFilter(o, e); +} +*/ +QWidget *LoggerPlugin::createConfigWindow(QWidget *parent) +{ + return new LogConfig(parent, this); +} + +bool LoggerPlugin::processEvent(Event *e) +{ + if(e->type() == eEventLog) + { + EventLog *l = static_cast(e); + if (((l->packetID() == 0) && (l->logLevel() & value("LogLevel").toUInt())) || + (l->packetID() && ((value("LogLevel").toUInt() & L_PACKETS) || isLogType(l->packetID())))) + { + QString s; + s = EventLog::make_packet_string(*l); + if (m_file) { +#if defined(Q_OS_WIN) || defined(__OS2__) + s += "\r\n"; +#else + s += "\n"; +#endif + m_file->write(s.toLocal8Bit()); + } +#ifdef Q_OS_WIN + const QStringList slist = s.split('\n'); + for(int i = 0 ; i < slist.count() ; i++) + { + QString out = slist[i]; + if (out.length() > 256){ + while (!out.isEmpty()){ + QString l; + if (out.length() < 256){ + l = out; + out.clear(); + }else{ + l = out.left(256); + out = out.mid(256); + } + OutputDebugStringW((LPCWSTR)l.utf16()); + } + } + else + { + OutputDebugStringW((LPCWSTR)out.utf16()); + } + OutputDebugStringW(L"\n"); + } +#else + fprintf(stderr, "%s\n", qPrintable(s)); +#endif + } + } + else if(e->type() == eEventPluginLoadConfig) + { + PropertyHubPtr hub = ProfileManager::instance()->getPropertyHub("logger"); + if(!hub.isNull()) + setPropertyHub(hub); + } + return false; +} + +void LoggerPlugin::setPropertyHub(SIM::PropertyHubPtr hub) +{ + m_propertyHub = hub; +} + +SIM::PropertyHubPtr LoggerPlugin::propertyHub() +{ + return m_propertyHub; +} + +QVariant LoggerPlugin::value(const QString& key) +{ + return m_propertyHub->value(key); +} + +void LoggerPlugin::setValue(const QString& key, const QVariant& v) +{ + m_propertyHub->setValue(key, v); +} + +// vim: set expandtab: + diff --git a/plugins/logger/logger.h b/plugins/logger/logger.h new file mode 100644 index 0000000..4ee8de2 --- /dev/null +++ b/plugins/logger/logger.h @@ -0,0 +1,63 @@ +/*************************************************************************** + logger.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _LOGGER_H +#define _LOGGER_H + +#include +#include + +#include "cfg.h" +#include "event.h" +#include "plugins.h" +#include "propertyhub.h" + +class QFile; +const unsigned short L_PACKETS = 0x08; +// const unsigned short L_EVENTS = 0x10; + +class QFile; + +class LoggerPlugin : public QObject, public SIM::Plugin, public SIM::EventReceiver +{ + Q_OBJECT +public: + LoggerPlugin(unsigned, Buffer*); + virtual ~LoggerPlugin(); + bool isLogType(unsigned id); + void setLogType(unsigned id, bool bLog); + + void setPropertyHub(SIM::PropertyHubPtr hub); + SIM::PropertyHubPtr propertyHub(); + QVariant value(const QString& key); + void setValue(const QString& key, const QVariant& v); +protected: +// bool eventFilter(QObject *o, QEvent *e); + QSet m_packets; + virtual QWidget *createConfigWindow(QWidget *parent); + virtual QByteArray getConfig(); + virtual bool processEvent(SIM::Event *e); + void openFile(); + QFile *m_file; + bool m_bFilter; + friend class LogConfig; + + SIM::PropertyHubPtr m_propertyHub; +}; + +#endif + diff --git a/plugins/logger/logger.rc b/plugins/logger/logger.rc new file mode 100644 index 0000000..c439f61 --- /dev/null +++ b/plugins/logger/logger.rc @@ -0,0 +1,97 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,9,6,0 + PRODUCTVERSION 0,9,6,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Vladimir Shutoff\0" + VALUE "FileDescription", "Logger plugin\0" + VALUE "FileVersion", "0, 9, 6, 0\0" + VALUE "InternalName", "logger\0" + VALUE "LegalCopyright", "Copyright © 2002-2003\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "logger.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "SIM\0" + VALUE "ProductVersion", "0, 9, 6, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/logger/logger.vcproj b/plugins/logger/logger.vcproj new file mode 100644 index 0000000..cab7fe8 --- /dev/null +++ b/plugins/logger/logger.vcproj @@ -0,0 +1,411 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/msn/CMakeLists.txt b/plugins/msn/CMakeLists.txt new file mode 100644 index 0000000..0febfe6 --- /dev/null +++ b/plugins/msn/CMakeLists.txt @@ -0,0 +1,33 @@ +############### +# msn library # +############### +IF(BUILD_DROPPED) +SET(msn_SRCS + msn.cpp + msnclient.cpp + msnconfig.cpp + msnfiletransfer.cpp + msnhttp.cpp + msninfo.cpp + msnpacket.cpp + msnsearch.cpp +) + +SET(msn_HDRS + msn.h + msnclient.h + msnconfig.h + msnhttp.h + msninfo.h + msnpacket.h + msnsearch.h +) + +SET(msn_UICS + msnconfigbase.ui + msninfobase.ui + msnsearchbase.ui +) + +SIM_ADD_PLUGIN(msn) +ENDIF(BUILD_DROPPED) diff --git a/plugins/msn/configure.in.in b/plugins/msn/configure.in.in new file mode 100644 index 0000000..63e9a8d --- /dev/null +++ b/plugins/msn/configure.in.in @@ -0,0 +1,5 @@ +if test "$have_ssl" != yes; then + AC_MSG_WARN([OpenSSL library disabled. MSN plugin is disabled]) +fi + +AM_CONDITIONAL(ENABLE_MSN, test "$have_ssl" = "yes") diff --git a/plugins/msn/msn.cpp b/plugins/msn/msn.cpp new file mode 100644 index 0000000..3ab436a --- /dev/null +++ b/plugins/msn/msn.cpp @@ -0,0 +1,232 @@ +/*************************************************************************** + msn.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +#include "clientmanager.h" +#include "misc.h" + +#include "msn.h" +#include "msnclient.h" + + +using namespace SIM; + +Plugin *createMSNPlugin(unsigned base, bool, Buffer*) +{ + Plugin *plugin = new MSNPlugin(base); + return plugin; +} + +static PluginInfo info = + { + NULL, + NULL, + VERSION, + createMSNPlugin, + PLUGIN_PROTOCOL + }; + +EXPORT_PROC PluginInfo* GetPluginInfo() +{ + return &info; +} + +MSNProtocol::MSNProtocol(Plugin *plugin) + : Protocol(plugin) +{ +} + +MSNProtocol::~MSNProtocol() +{ +} + +ClientPtr MSNProtocol::createClient(Buffer *cfg) +{ + ClientPtr msn = ClientPtr(new MSNClient(this, cfg)); + getClientManager()->addClient(msn); + return msn; +} + +static CommandDef msn_descr = + CommandDef ( + 0, + I18N_NOOP("MSN"), + "MSN_online", + "MSN_invisible", + I18N_NOOP("https://accountservices.passport.net/uiresetpw.srf?lc=1033"), + 0, + 0, + 0, + 0, + 0, + PROTOCOL_INVISIBLE, + NULL, + QString::null + ); + +const CommandDef *MSNProtocol::description() +{ + return &msn_descr; +} + +static CommandDef msn_status_list[] = + { + CommandDef ( + STATUS_ONLINE, + I18N_NOOP("Online"), + "MSN_online", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + STATUS_AWAY, + I18N_NOOP("Away"), + "MSN_away", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + STATUS_NA, + I18N_NOOP("N/A"), + "MSN_na", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + STATUS_DND, + I18N_NOOP("Busy"), + "MSN_dnd", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + STATUS_BRB, + I18N_NOOP("Be right back"), + "MSN_onback", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + STATUS_PHONE, + I18N_NOOP("On the phone"), + "MSN_onphone", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + STATUS_LUNCH, + I18N_NOOP("On the lunch"), + "MSN_lunch", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + STATUS_OFFLINE, + I18N_NOOP("Offline"), + "MSN_offline", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef () + }; + +const CommandDef *MSNProtocol::statusList() +{ + return msn_status_list; +} + +MSNPlugin::MSNPlugin(unsigned base) + : Plugin(base) +{ + MSNPacket = registerType(); + EventAddOk = registerType(); + EventAddFail = registerType(); + MSNInitMail = registerType(); + MSNNewMail = registerType(); + + getContacts()->addPacketType(MSNPacket, msn_descr.text, true); + + m_protocol = new MSNProtocol(this); +} + +MSNPlugin::~MSNPlugin() +{ + getContacts()->removePacketType(MSNPacket); + delete m_protocol; +} diff --git a/plugins/msn/msn.h b/plugins/msn/msn.h new file mode 100644 index 0000000..c90e93a --- /dev/null +++ b/plugins/msn/msn.h @@ -0,0 +1,50 @@ +/*************************************************************************** + msn.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _MSN_H +#define _MSN_H + +#include "contacts.h" +#include "contacts/client.h" + +class MSNProtocol : public SIM::Protocol +{ +public: + MSNProtocol(SIM::Plugin *plugin); + ~MSNProtocol(); + SIM::ClientPtr createClient(Buffer *cfg); + const SIM::CommandDef *description(); + const SIM::CommandDef *statusList(); + virtual const SIM::DataDef *userDataDef(); +}; + +class MSNPlugin : public SIM::Plugin +{ +public: + MSNPlugin(unsigned base); + virtual ~MSNPlugin(); + unsigned EventAddOk; + unsigned EventAddFail; + unsigned MSNPacket; + unsigned MSNInitMail; + unsigned MSNNewMail; +protected: + SIM::Protocol *m_protocol; +}; + +#endif + diff --git a/plugins/msn/msn.rc b/plugins/msn/msn.rc new file mode 100644 index 0000000..076c464 --- /dev/null +++ b/plugins/msn/msn.rc @@ -0,0 +1,97 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,9,6,0 + PRODUCTVERSION 0,9,6,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Vladimir Shutoff\0" + VALUE "FileDescription", "MSN plugin\0" + VALUE "FileVersion", "0, 9, 6, 0\0" + VALUE "InternalName", "msn\0" + VALUE "LegalCopyright", "Copyright © 2002-2003\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "msn.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "SIM\0" + VALUE "ProductVersion", "0, 9, 6, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/msn/msn.vcproj b/plugins/msn/msn.vcproj new file mode 100644 index 0000000..0080260 --- /dev/null +++ b/plugins/msn/msn.vcproj @@ -0,0 +1,748 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/msn/msn_pch.h b/plugins/msn/msn_pch.h new file mode 100644 index 0000000..872709a --- /dev/null +++ b/plugins/msn/msn_pch.h @@ -0,0 +1,47 @@ +#pragma once + +#include + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef NO_QT_MOC_HEADER +#include +//#include +//#include +#endif + +#include "msn.h" +#include "msnclient.h" +#include "msnconfig.h" +#include "ui_msnconfigbase.h" +#include "msnhttp.h" +#include "msninfo.h" +#include "ui_msninfobase.h" +#include "msnpacket.h" +#include "msnsearch.h" +#include "ui_msnsearchbase.h" diff --git a/plugins/msn/msnclient.cpp b/plugins/msn/msnclient.cpp new file mode 100644 index 0000000..e9a8c11 --- /dev/null +++ b/plugins/msn/msnclient.cpp @@ -0,0 +1,2757 @@ +/*************************************************************************** + msn.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include + +#include "log.h" +#include "core.h" +#include "core_events.h" +#include "contacts/clientdataiterator.h" +#include "contacts/contact.h" +#include "contacts/group.h" + +#include "msnclient.h" +#include "msnconfig.h" +#include "msnpacket.h" +#include "msn.h" +#include "msninfo.h" +#include "msnsearch.h" + +#include "socket/clientsocket.h" + +#ifndef INADDR_NONE +#define INADDR_NONE 0xFFFFFFFF +#endif + +using namespace std; +using namespace SIM; + +const unsigned long PING_TIMEOUT = 60; + +const unsigned long TYPING_TIME = 10; + +static DataDef msnUserData[] = + { + { "", DATA_ULONG, 1, DATA(3) }, // Sign + { "LastSend", DATA_ULONG, 1, 0 }, + { "EMail", DATA_UTF, 1, 0 }, + { "Screen", DATA_UTF, 1, 0 }, + { "", DATA_ULONG, 1, DATA(1) }, // Status + { "StatusTime", DATA_ULONG, 1, 0 }, + { "OnlineTime", DATA_ULONG, 1, 0 }, + { "PhoneHome", DATA_UTF, 1, 0 }, + { "PhoneWork", DATA_UTF, 1, 0 }, + { "PhoneMobile", DATA_UTF, 1, 0 }, + { "Mobile", DATA_BOOL, 1, 0 }, + { "Group", DATA_ULONG, 1, 0 }, + { "Flags", DATA_ULONG, 1, 0 }, + { "", DATA_ULONG, 1, 0 }, // sFlags + { "", DATA_ULONG, 1, 0 }, + { "IP", DATA_IP, 1, 0 }, + { "RealIP", DATA_IP, 1, 0 }, + { "Port", DATA_ULONG, 1, 0 }, + { "", DATA_OBJECT, 1, 0 }, // sb + { NULL, DATA_UNKNOWN, 0, 0 } + }; + +static DataDef msnClientData[] = + { + { "Server", DATA_STRING, 1, "messenger.hotmail.com" }, + { "Port", DATA_ULONG, 1, DATA(1863) }, + { "ListVer", DATA_ULONG, 1, 0 }, + { "ListRequests", DATA_UTF, 1, 0 }, + { "Version", DATA_STRING, 1, "5.0.0540" }, + { "MinPort", DATA_ULONG, 1, DATA(1024) }, + { "MaxPort", DATA_ULONG, 1, DATA(0xFFFF) }, + { "UseHTTP", DATA_BOOL, 1, 0 }, + { "AutoHTTP", DATA_BOOL, 1, DATA(1) }, + { "Deleted", DATA_STRLIST, 1, 0 }, + { "NDeleted", DATA_ULONG, 1, 0 }, + { "AutoAuth", DATA_BOOL, 1, DATA(1) }, + { "", DATA_STRUCT, sizeof(MSNUserData) / sizeof(Data), DATA(msnUserData) }, + { NULL, DATA_UNKNOWN, 0, 0 } + }; + +MSNClient::MSNClient(Protocol *protocol, Buffer *cfg) + : TCPClient (protocol, cfg) + , m_bJoin (false) + , m_packetId (1) + , m_msg (NULL) + , m_bFirstTry (false) +{ + load_data(msnClientData, &data, cfg); + + m_bFirst = (cfg == NULL); + QString s = getListRequests(); + while (!s.isEmpty()){ + QString item = getToken(s, ';'); + MSNListRequest lr; + lr.Type = getToken(item, ',').toUInt(); + lr.Name = item; + } + setListRequests(QString::null); + +} + +MSNClient::~MSNClient() +{ + TCPClient::setStatus(STATUS_OFFLINE, false); + free_data(msnClientData, &data); + freeData(); +} + +QString MSNClient::name() +{ + return "MSN." + getLogin(); +} + +QWidget *MSNClient::setupWnd() +{ + return new MSNConfig(NULL, this, false); +} + +QByteArray MSNClient::getConfig() +{ + QString listRequests; + for (list::iterator it = m_requests.begin(); it != m_requests.end(); ++it){ + if (!listRequests.isEmpty()) + listRequests += ";"; + listRequests += QString::number(it->Type) + "," + it->Name; + } + setListRequests(listRequests); + QByteArray res = Client::getConfig(); + if (res.length()) + res += "\n"; + res += save_data(msnClientData, &data); + setListRequests(QString::null); + return res; +} + +const DataDef *MSNProtocol::userDataDef() +{ + return msnUserData; +} + +void MSNClient::connect_ready() +{ + m_bFirstTry = false; + socket()->readBuffer().init(0); + socket()->readBuffer().packetStart(); + socket()->setRaw(true); + log(L_DEBUG, "Connect ready"); + TCPClient::connect_ready(); + MSNPacket *packet = new VerPacket(this); + packet->send(); +} + +void MSNClient::setStatus(unsigned status) +{ + if (status == m_status) + return; + QDateTime now(QDateTime::currentDateTime()); + if (m_status == STATUS_OFFLINE) + data.owner.OnlineTime.asULong() = now.toTime_t(); + data.owner.StatusTime.asULong() = now.toTime_t(); + m_status = status; + data.owner.Status.asULong() = m_status; + EventClientChanged(this).process(); + if (status == STATUS_OFFLINE) + { + if (m_status != STATUS_OFFLINE) + { + m_status = status; + data.owner.Status.asULong() = status; + data.owner.StatusTime.asULong() = now.toTime_t(); + MSNPacket *packet = new OutPacket(this); + packet->send(); + } + return; + } + if (Client::m_state != Connected) + { + m_logonStatus = status; + return; + } + m_status = status; + MSNPacket *packet = new ChgPacket(this); + packet->send(); +} + +void MSNClient::connected() +{ + setState(Client::Connected); + setStatus(m_logonStatus); + processRequests(); +} + +void MSNClient::setInvisible(bool bState) +{ + if (bState == getInvisible()) + return; + TCPClient::setInvisible(bState); + if (getStatus() == STATUS_OFFLINE) + return; + MSNPacket *packet = new ChgPacket(this); + packet->send(); +} + +void MSNClient::disconnected() +{ + stop(); + Contact *contact; + ContactList::ContactIterator it; + while ((contact = ++it) != NULL) + { + bool bChanged = false; + MSNUserData *data; + ClientDataIterator it(contact->clientData, this); + while ((data = toMSNUserData(++it)) != NULL){ + if (data->Status.toULong() != STATUS_OFFLINE){ + data->Status.asULong() = STATUS_OFFLINE; + QDateTime now(QDateTime::currentDateTime()); + data->StatusTime.asULong() = now.toTime_t(); + SBSocket *sock = dynamic_cast(data->sb.object()); + if (sock) + { + delete sock; + data->sb.clear(); + } + bChanged = true; + } + if (bChanged) + { + StatusMessage *m = new StatusMessage(); + m->setContact(contact->id()); + m->setClient(dataName(data)); + m->setFlags(MESSAGE_RECEIVED); + m->setStatus(STATUS_OFFLINE); + EventMessageReceived e(m); + if(!e.process()) + delete m; + } + } + } + m_packetId = 0; + m_pingTime = 0; + m_state = None; + m_authChallenge = QString::null; + clearPackets(); +} + +void MSNClient::clearPackets() +{ + if (m_msg) + { + delete m_msg; + m_msg = NULL; + } + for (list::iterator it = m_packets.begin(); it != m_packets.end(); ++it) + { + delete *it; + } + m_packets.clear(); +} + +void MSNClient::packet_ready() +{ + if (socket()->readBuffer().writePos() == 0) + return; + MSNPlugin *plugin = static_cast(protocol()->plugin()); + EventLog::log_packet(socket()->readBuffer(), false, plugin->MSNPacket); + if (m_msg) + { + if (!m_msg->packet()) + return; + delete m_msg; + m_msg = NULL; + } + for (;;) + { + QByteArray s; + if (!socket()->readBuffer().scan("\r\n", s)) + break; + getLine(s); + } + if (socket()->readBuffer().readPos() == socket()->readBuffer().writePos()) + socket()->readBuffer().init(0); +} + +struct statusText +{ + unsigned status; + const char *name; +}; + +statusText st[] = + { + { STATUS_ONLINE, "NLN" }, + { STATUS_OFFLINE, "FLN" }, + { STATUS_OFFLINE, "HDN" }, + { STATUS_NA, "IDL" }, + { STATUS_AWAY, "AWY" }, + { STATUS_DND, "BSY" }, + { STATUS_BRB, "BRB" }, + { STATUS_PHONE, "PHN" }, + { STATUS_LUNCH, "LUN" }, + { 0, NULL } + }; + +static unsigned str2status(const QString &str) +{ + for (const statusText *s = st; s->name; s++){ + if (str == s->name) + return s->status; + } + return STATUS_OFFLINE; +} + +void MSNClient::processLSG(unsigned id, const QString &name) +{ + if (id == 0) + return; + Group *grp; + MSNListRequest *lr = findRequest(id, LR_GROUPxREMOVED); + if (lr) + return; + MSNUserData *data = findGroup(id, QString::null, grp); + if (data){ + lr = findRequest(grp->id(), LR_GROUPxCHANGED); + if (lr){ + data->sFlags.asULong() |= MSN_CHECKED; + return; + } + } + data = findGroup(id, name, grp); + data->sFlags.asULong() |= MSN_CHECKED; +} + +void MSNClient::processLST(const QString &mail, const QString &name, unsigned state, unsigned grp) +{ + if ((state & MSN_FORWARD) == 0){ + for (unsigned i = 1; i <= getNDeleted(); i++){ + if (getDeleted(i) == mail) + return; + } + } + + m_curBuddy = mail; + Contact *contact; + MSNListRequest *lr = findRequest(mail, LR_CONTACTxREMOVED); + if (lr) + return; + bool bNew = false; + MSNUserData *data = findContact(mail, contact); + if (data == NULL){ + data = findContact(mail, name, contact); + bNew = true; + }else{ + data->EMail.str() = mail; + data->ScreenName.str() = name; + if (name != contact->getName()) + contact->setName(name); + } + data->sFlags.asULong() |= MSN_CHECKED; + data->Flags.asULong() = state; + if (state & MSN_BLOCKED) + contact->setIgnore(true); + + lr = findRequest(mail, LR_CONTACTxCHANGED); + data->Group.asULong() = grp; + data->PhoneHome.clear(); + data->PhoneWork.clear(); + data->PhoneMobile.clear(); + data->Mobile.asBool() = false; + Group *group = NULL; + if ((grp == 0) || (grp == NO_GROUP)){ + group = getContacts()->group(0); + }else{ + findGroup(grp, QString::null, group); + } + if (lr == NULL){ + bool bChanged = ((data->Flags.toULong() & MSN_FLAGS) != (data->sFlags.toULong() & MSN_FLAGS)); + if (getAutoAuth() && (data->Flags.toULong() & MSN_FORWARD) && ((data->Flags.toULong() & MSN_ACCEPT) == 0) && ((data->Flags.toULong() & MSN_BLOCKED) == 0)) + bChanged = true; + int grp = 0; + if (group) + grp = group->id(); + if (grp != contact->getGroup()) + bChanged = true; + if (bChanged){ + MSNListRequest lr; + lr.Type = LR_CONTACTxCHANGED; + lr.Name = data->EMail.str(); + m_requests.push_back(lr); + } + if (data->Flags.toULong() & MSN_FORWARD) + contact->setGroup(grp); + } +} + +void MSNClient::checkEndSync() +{ + if (m_nBuddies || m_nGroups) + return; + ContactList::GroupIterator itg; + Group *grp; + list grpRemove; + list contactRemove; + while ((grp = ++itg) != NULL){ + ClientDataIterator it(grp->clientData, this); + MSNUserData *data = toMSNUserData(++it); + if (grp->id() && (data == NULL)){ + MSNListRequest lr; + lr.Type = LR_GROUPxCHANGED; + lr.Name = QString::number(grp->id()); + m_requests.push_back(lr); + continue; + } + if (data == NULL) + continue; + if ((data->sFlags.toULong() & MSN_CHECKED) == 0) + grpRemove.push_back(grp); + } + Contact *contact; + ContactList::ContactIterator itc; + while ((contact = ++itc) != NULL){ + MSNUserData *data; + ClientDataIterator it(contact->clientData, this); + list forRemove; + while ((data = toMSNUserData(++it)) != NULL){ + if (data->sFlags.toULong() & MSN_CHECKED){ + if ((data->sFlags.toULong() & MSN_REVERSE) && ((data->Flags.toULong() & MSN_REVERSE) == 0)) + auth_message(contact, MessageRemoved, data); + if (!m_bFirst && ((data->sFlags.toULong() & MSN_REVERSE) == 0) && (data->Flags.toULong() & MSN_REVERSE)){ + if ((data->Flags.toULong() & MSN_ACCEPT) || getAutoAuth()){ + auth_message(contact, MessageAdded, data); + }else{ + auth_message(contact, MessageAuthRequest, data); + } + } + setupContact(contact, data); + EventContact e(contact, EventContact::eChanged); + e.process(); + }else{ + forRemove.push_back(data); + } + } + if (forRemove.empty()) + continue; + for (list::iterator itr = forRemove.begin(); itr != forRemove.end(); ++itr) + contact->clientData.freeData(*itr); + if (contact->clientData.size() == 0) + contactRemove.push_back(contact); + } + for (list::iterator rc = contactRemove.begin(); rc != contactRemove.end(); ++rc) + delete *rc; + for (list::iterator rg = grpRemove.begin(); rg != grpRemove.end(); ++rg) + delete *rg; + if (m_bJoin){ + EventJoinAlert(this).process(); + } + m_bFirst = false; + connected(); +} + +void MSNClient::getLine(const QByteArray &line) +{ + QString l = QString::fromUtf8(line); + l = l.remove('\r'); + log(L_DEBUG, "Get: %s", qPrintable(l)); + QString cmd = getToken(l, ' '); + log(L_DEBUG, QString("Command: %1").arg(cmd)); + if ((cmd == "715") || (cmd == "228")) + return; + if (cmd == "XFR"){ + QString id = getToken(l, ' '); // ID + QString type = getToken(l, ' '); // NS + if (type == "NS"){ + l = getToken(l, ' '); // from + QString host = getToken(l, ':'); + unsigned short port = l.toUShort(); + if (host.isEmpty() || (port == 0)){ + log(L_WARN, "Bad host on XFR"); + socket()->error_state(I18N_NOOP("MSN protocol error")); + return; + } + clearPackets(); + socket()->close(); + socket()->readBuffer().init(0); + socket()->connect(host, port, this); + return; + } + l = id + " " + type + " " + l; + } + if (cmd == "MSG"){ + getToken(l, ' '); + getToken(l, ' '); + unsigned size = getToken(l, ' ').toUInt(); + if (size == 0){ + log(L_WARN, "Bad server message size"); + socket()->error_state(I18N_NOOP("MSN protocol error")); + return; + } + m_msg = new MSNServerMessage(this, size); + packet_ready(); + return; + } + if (cmd == "CHL"){ + getToken(l, ' '); + MSNPacket *packet = new QryPacket(this, getToken(l, ' ')); + packet->send(); + return; + } + if (cmd == "QNG") + return; + if (cmd == "BPR"){ + Contact *contact; + MSNUserData *data = findContact(getToken(l, ' '), contact); + if (data){ + QString info = getToken(l, ' '); + QString type = getToken(l, ' '); + bool bChanged = false; + if (type == "PHH"){ + bChanged = data->PhoneHome.setStr(unquote(info)); + }else if (type == "PHW"){ + bChanged = data->PhoneWork.setStr(unquote(info)); + }else if (type == "PHM"){ + bChanged = data->PhoneMobile.setStr(unquote(info)); + }else if (type == "MOB"){ + data->Mobile.asBool() = ((info[0] == 'Y') != 0); + }else{ + log(L_DEBUG, "Unknown BPR type %s", qPrintable(type)); + } + if (bChanged){ + setupContact(contact, data); + EventContact e(contact, EventContact::eChanged); + e.process(); + } + } + return; + } + if (cmd == "ILN"){ + getToken(l, ' '); + unsigned status = str2status(getToken(l, ' ')); + Contact *contact; + MSNUserData *data = findContact(getToken(l, ' '), contact); + QDateTime now(QDateTime::currentDateTime()); + if (data && (data->Status.toULong() != status)) + { + data->Status.asULong() = status; + if (data->Status.toULong() == STATUS_OFFLINE){ + data->OnlineTime.asULong() = now.toTime_t(); + set_ip(&data->IP, 0); + set_ip(&data->RealIP, 0); + } + data->StatusTime.asULong() = now.toTime_t(); + StatusMessage *m = new StatusMessage(); + m->setContact(contact->id()); + m->setClient(dataName(data)); + m->setFlags(MESSAGE_RECEIVED); + m->setStatus(status); + EventMessageReceived e(m); + if(!e.process()) + delete m; + } + return; + } + if (cmd == "NLN"){ + unsigned status = str2status(getToken(l, ' ')); + Contact *contact; + MSNUserData *data = findContact(getToken(l, ' '), contact); + if (data && (data->Status.toULong() != status)) + { + QDateTime now(QDateTime::currentDateTime()); + if (data->Status.toULong() == STATUS_OFFLINE){ + data->OnlineTime.asULong() = now.toTime_t(); + set_ip(&data->IP, 0); + set_ip(&data->RealIP, 0); + } + data->StatusTime.asULong() = now.toTime_t(); + data->Status.asULong() = status; + StatusMessage *m = new StatusMessage(); + m->setContact(contact->id()); + m->setClient(dataName(data)); + m->setFlags(MESSAGE_RECEIVED); + m->setStatus(status); + EventMessageReceived e(m); + if(!e.process()) + delete m; + if ((status == STATUS_ONLINE) && !contact->getIgnore()){ + EventContact e(contact, EventContact::eOnline); + e.process(); + } + } + return; + } + if (cmd == "FLN"){ + Contact *contact; + MSNUserData *data = findContact(getToken(l, ' '), contact); + if (data && (data->Status.toULong() != STATUS_OFFLINE)){ + QDateTime now(QDateTime::currentDateTime()); + data->StatusTime.asULong() = now.toTime_t(); + data->Status.asULong() = STATUS_OFFLINE; + StatusMessage *m = new StatusMessage(); + m->setContact(contact->id()); + m->setClient(dataName(data)); + m->setFlags(MESSAGE_RECEIVED); + m->setStatus(STATUS_OFFLINE); + EventMessageReceived e(m); + if(!e.process()) + delete m; + } + return; + } + if (cmd == "ADD"){ + getToken(l, ' '); + if (getToken(l, ' ') == "RL"){ + setListVer(getToken(l, ' ').toUInt()); + Contact *contact; + MSNUserData *data = findContact(getToken(l, ' '), getToken(l, ' '), contact); + if (data){ + data->Flags.asULong() |= MSN_REVERSE; + if ((data->Flags.toULong() & MSN_ACCEPT) || getAutoAuth()){ + auth_message(contact, MessageAdded, data); + }else{ + auth_message(contact, MessageAuthRequest, data); + } + } + } + return; + } + if (cmd == "REM"){ + getToken(l, ' '); + if (getToken(l, ' ') == "RL"){ + setListVer(getToken(l, ' ').toUInt()); + Contact *contact; + MSNUserData *data = findContact(getToken(l, ' '), contact); + if (data){ + data->Flags.asULong() &= ~MSN_REVERSE; + auth_message(contact, MessageRemoved, data); + } + } + return; + } + if (cmd == "RNG"){ + QString session = getToken(l, ' '); + QString addr = getToken(l, ' '); + getToken(l, ' '); + QString cookie, email, nick; + cookie = getToken(l, ' '); + email = getToken(l, ' '); + nick = getToken(l, ' '); + Contact *contact; + MSNUserData *data = findContact(email, contact); + if (data == NULL){ + data = findContact(email, nick, contact); + contact->setFlags(CONTACT_TEMP); + EventContact e(contact, EventContact::eChanged); + e.process(); + } + SBSocket *sock = dynamic_cast(data->sb.object()); + if (sock){ + delete sock; + } + sock = new SBSocket(this, contact, data); + sock->connect(addr, session, cookie, false); + data->sb.setObject(sock); + return; + } + if (cmd == "OUT"){ + m_reconnect = NO_RECONNECT; + socket()->error_state(I18N_NOOP("Your account is being used from another location")); + return; + } + if (cmd == "GTC") + return; + if (cmd == "BLP") + return; + if (cmd == "UUX") + { + // personal message + getToken(l, ' '); + getToken(l, ' '); + unsigned size = getToken(l, ' ').toUInt(); + if (size == 0){ + log(L_WARN, "Empty server personal message size"); + //return; + } + else + { + m_msg = new MSNServerMessage(this, size); + // only we post the message in log now..... + // ToDo: restore this + // Error: m_msg is not a string + //log(L_WARN, "Personal message: %s", m_msg); + //packet_ready(); + } + return; + } + if (cmd == "LSG"){ + unsigned id = getToken(l, ' ').toUInt(); + processLSG(id, unquote(getToken(l, ' '))); + m_nGroups--; + checkEndSync(); + return; + } + if (cmd == "LST"){ + QString mail = unquote(getToken(l, ' ')); + QString name = unquote(getToken(l, ' ')); + unsigned state = getToken(l, ' ').toUInt(); + unsigned grp = getToken(l, ' ').toUInt(); + processLST(mail, name, state, grp); + m_nBuddies--; + checkEndSync(); + return; + } + if (cmd == "PRP"){ + QString cmd = getToken(l, ' '); + if (cmd == "PHH") + data.owner.PhoneHome.str() = unquote(getToken(l, ' ')); + if (cmd == "PHW") + data.owner.PhoneWork.str() = unquote(getToken(l, ' ')); + if (cmd == "PHM") + data.owner.PhoneMobile.str() = unquote(getToken(l, ' ')); + if (cmd == "MBE") + data.owner.Mobile.asBool() = (getToken(l, ' ') == "Y"); + return; + } + if (cmd == "BPR"){ + Contact *contact; + MSNUserData *data = findContact(m_curBuddy, contact); + if (data == NULL) + return; + EventContact e(contact, EventContact::eChanged); + e.process(); + QString cmd = getToken(l, ' '); + if (cmd == "PHH") + data->PhoneHome.str() = unquote(getToken(l, ' ')); + if (cmd == "PHW") + data->PhoneWork.str() = unquote(getToken(l, ' ')); + if (cmd == "PHM") + data->PhoneMobile.str() = unquote(getToken(l, ' ')); + if (cmd == "MBE") + data->Mobile.asBool() = (getToken(l, ' ') == "Y"); + return; + } + unsigned code = cmd.toUInt(); + if (code){ + MSNPacket *packet = NULL; + unsigned id = getToken(l, ' ').toUInt(); + list::iterator it; + for (it = m_packets.begin(); it != m_packets.end(); ++it){ + if ((*it)->id() == id){ + packet = *it; + break; + } + } + if (it == m_packets.end()){ + socket()->error_state("Bad packet id"); + return; + } + m_packets.erase(it); + packet->error(code); + delete packet; + return; + } + if (m_packets.empty()){ + log(L_DEBUG, "Packet not found"); + return; + } + MSNPacket *packet = NULL; + unsigned id = getToken(l, ' ').toUInt(); + list::iterator it; + for (it = m_packets.begin(); it != m_packets.end(); ++it){ + if ((*it)->id() == id){ + packet = *it; + break; + } + } + if (it == m_packets.end()){ + socket()->error_state("Bad packet id"); + return; + } + if (cmd != packet->cmd()){ + socket()->error_state("Bad answer cmd"); + return; + } + QStringList args; + while (l.length()) + args.push_back(getToken(l, ' ', false)); + packet->answer(args); + m_packets.erase(it); + delete packet; +} + +void MSNClient::sendLine(const QString &line, bool crlf) +{ + log(L_DEBUG, "Send: %s", qPrintable(line)); + socket()->writeBuffer().packetStart(); + socket()->writeBuffer() << (const char*)line.toUtf8(); + if (crlf) + socket()->writeBuffer() << "\r\n"; + MSNPlugin *plugin = static_cast(protocol()->plugin()); + EventLog::log_packet(socket()->writeBuffer(), true, plugin->MSNPacket); + socket()->write(); +} + +void MSNClient::authFailed() +{ + m_reconnect = NO_RECONNECT; + socket()->error_state(I18N_NOOP("Login failed"), AuthError); +} + +void MSNClient::authOk() +{ + m_state = None; + m_authChallenge = QString::null; + QDateTime now(QDateTime::currentDateTime()); + m_pingTime = now.toTime_t(); + QTimer::singleShot(TYPING_TIME * 1000, this, SLOT(ping())); + setPreviousPassword(QString::null); + MSNPacket *packet = new SynPacket(this); + packet->send(); +} + +void MSNClient::ping() +{ + if (getState() != Connected) + return; + QDateTime now(QDateTime::currentDateTime()); + if (now.toTime_t() >= m_pingTime + PING_TIMEOUT){ + sendLine("PNG"); + m_pingTime = now.toTime_t(); + } + for (list::iterator it = m_SBsockets.begin(); it != m_SBsockets.end(); ++it) + (*it)->timer(now.toTime_t()); + QTimer::singleShot(TYPING_TIME * 1000, this, SLOT(ping())); +} + +QString MSNClient::getLogin() +{ + return data.owner.EMail.str(); +} + +void MSNClient::setLogin(const QString &str) +{ + data.owner.EMail.str() = str; +} + +const unsigned MAIN_INFO = 1; +const unsigned NETWORK = 2; + +static CommandDef msnWnd[] = + { + CommandDef ( + MAIN_INFO, + " ", + "MSN_online", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef (), + }; + +static CommandDef cfgMsnWnd[] = + { + CommandDef ( + MAIN_INFO, + " ", + "MSN_online", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + NETWORK, + I18N_NOOP("Network"), + "network", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef (), + }; + +CommandDef *MSNClient::infoWindows(Contact*, void *_data) +{ + MSNUserData *data = toMSNUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + QString name = i18n(protocol()->description()->text); + name += " "; + name += data->EMail.str(); + msnWnd[0].text_wrk = name; + return msnWnd; +} + +CommandDef *MSNClient::configWindows() +{ + QString name = i18n(protocol()->description()->text); + name += " "; + name += data.owner.EMail.str(); + cfgMsnWnd[0].text_wrk = name; + return cfgMsnWnd; +} + +QWidget *MSNClient::infoWindow(QWidget *parent, Contact*, void *_data, unsigned id) +{ + MSNUserData *data = toMSNUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + switch (id){ + case MAIN_INFO: + return new MSNInfo(parent, data, this); + } + return NULL; +} + +QWidget *MSNClient::configWindow(QWidget *parent, unsigned id) +{ + switch (id){ + case MAIN_INFO: + return new MSNInfo(parent, NULL, this); + case NETWORK: + return new MSNConfig(parent, this, true); + } + return NULL; +} + +bool MSNClient::canSend(unsigned type, void *_data) +{ + if ((_data == NULL) || (((clientData*)_data)->Sign.toULong() != MSN_SIGN)) + return false; + MSNUserData *data = toMSNUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + if (getState() != Connected) + return false; + switch (type){ + case MessageGeneric: + case MessageFile: + case MessageUrl: + if (getInvisible()) + return false; + return true; + case MessageAuthGranted: + case MessageAuthRefused: + return (data->Flags.toULong() & MSN_ACCEPT) == 0; + } + return false; +} + +bool MSNClient::send(Message *msg, void *_data) +{ + if ((_data == NULL) || (getState() != Connected)) + return false; + MSNUserData *data = toMSNUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + MSNPacket *packet; + switch (msg->type()){ + case MessageAuthGranted: + if (data->Flags.toULong() & MSN_ACCEPT) + return false; + packet = new AddPacket(this, "AL", data->EMail.str(), quote(data->ScreenName.str()), 0); + packet->send(); + case MessageAuthRefused: + if (data->Flags.toULong() & MSN_ACCEPT) + return false; + if (msg->getText().isEmpty()){ + if ((msg->getFlags() & MESSAGE_NOHISTORY) == 0){ + msg->setClient(dataName(data)); + EventSent(msg).process(); + } + EventMessageSent(msg).process(); + delete msg; + return true; + } + case MessageGeneric: + case MessageFile: + case MessageUrl: { + SBSocket *sock = dynamic_cast(data->sb.object()); + if (!sock){ + if (getInvisible()) + return false; + Contact *contact; + findContact(data->EMail.str(), contact); + sock = new SBSocket(this, contact, data); + sock->connect(); + data->sb.setObject(sock); + } + return sock->send(msg); + } + case MessageTypingStart: { + SBSocket *sock = dynamic_cast(data->sb.object()); + if (!sock){ + if (getInvisible()) + return false; + Contact *contact; + findContact(data->EMail.str(), contact); + sock = new SBSocket(this, contact, data); + sock->connect(); + data->sb.setObject(sock); + } + sock->setTyping(true); + delete msg; + return true; + } + case MessageTypingStop: { + SBSocket *sock = dynamic_cast(data->sb.object()); + if (!sock) + return false; + sock->setTyping(false); + delete msg; + return true; + } + } + return false; +} + +QString MSNClient::dataName(void *_data) +{ + QString res = name(); + MSNUserData *data = toMSNUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + res += "+"; + res += data->EMail.str(); + return res; +} + +bool MSNClient::isMyData(clientData *&_data, Contact *&contact) +{ + if (_data->Sign.toULong() != MSN_SIGN) + return false; + MSNUserData *data = toMSNUserData(_data); + if (data->EMail.str().toLower() == this->data.owner.EMail.str().toLower()) + return false; + MSNUserData *my_data = findContact(data->EMail.str(), contact); + if (my_data){ + data = my_data; + }else{ + contact = NULL; + } + return true; +} + +bool MSNClient::createData(clientData *&_data, Contact *contact) +{ + MSNUserData *data = toMSNUserData(_data); + MSNUserData *new_data = toMSNUserData((SIM::clientData*)contact->clientData.createData(this)); // FIXME unsafe type conversion + new_data->EMail.str() = data->EMail.str(); + _data = (clientData*)new_data; + return true; +} + +void MSNClient::setupContact(Contact *contact, void *_data) +{ + MSNUserData *data = toMSNUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + QString phones; + if (!data->PhoneHome.str().isEmpty()){ + phones += data->PhoneHome.str(); + phones += ",Home Phone,1"; + } + if (!data->PhoneWork.str().isEmpty()){ + if (!phones.isEmpty()) + phones += ";"; + phones += data->PhoneWork.str(); + phones += ",Work Phone,1"; + } + if (!data->PhoneMobile.str().isEmpty()){ + if (!phones.isEmpty()) + phones += ";"; + phones += data->PhoneMobile.str(); + phones += ",Private Cellular,2"; + } + bool bChanged = contact->setPhones(phones, name()); + bChanged |= contact->setEMails(data->EMail.str(), name()); + if (contact->getName().isEmpty()){ + QString name = data->ScreenName.str(); + if (name.isEmpty()) + name = data->EMail.str(); + int n = name.indexOf('@'); + if (n > 0) + name = name.left(n); + + QString oldName(contact->getName()); + contact->setName(name); + bChanged |= (oldName != name ); + } + if (bChanged) + { + EventContact e(contact, EventContact::eChanged); + e.process(); + } +} + +QString MSNClient::unquote(const QString &s) +{ + QString res; + for (int i = 0; i < (int)(s.length()); i++){ + QChar c = s[i]; + if (c != '%'){ + res += c; + continue; + } + i++; + if (i + 2 > (int)(s.length())) + break; + res += QChar((char)((fromHex(s[i].toAscii()) << 4) + fromHex(s[i+1].toAscii()))); + i++; + } + return res; +} + +// FIXME: what's with non-latin1 characters here? +QString MSNClient::quote(const QString &s) +{ + QString res; + for (int i = 0; i < (int)(s.length()); i++){ + QChar c = s[i]; + if ((c == '%') || (c == ' ') || (c == '+')){ + char b[4]; + sprintf(b, "%%%2X", c.toLatin1()); + res += b; + }else{ + res += c; + } + } + return res; +} + +MSNUserData *MSNClient::findContact(const QString &mail, Contact *&contact) +{ + ContactList::ContactIterator itc; + while ((contact = ++itc) != NULL){ + MSNUserData *res; + ClientDataIterator it(contact->clientData, this); + while ((res = toMSNUserData(++it)) != NULL){ + if (res->EMail.str() == mail) + return res; + } + } + return NULL; +} + +QString MSNClient::contactName(void *clientData) +{ + MSNUserData *data = toMSNUserData((SIM::clientData*)clientData); // FIXME unsafe type conversion + return "MSN: " + data->EMail.str(); +} + +MSNUserData *MSNClient::findContact(const QString &mail, const QString &name, Contact *&contact, bool bJoin) +{ + unsigned i; + for (i = 1; i <= getNDeleted(); i++){ + if (getDeleted(i) == mail) + break; + } + if (i <= getNDeleted()){ + QStringList deleted; + for (i = 1; i <= getNDeleted(); i++){ + if (getDeleted(i) == mail) + continue; + deleted.push_back(getDeleted(i)); + } + setNDeleted(0); + for (QStringList::iterator it = deleted.begin(); it != deleted.end(); ++it){ + setNDeleted(getNDeleted() + 1); + setDeleted(getNDeleted(), (*it)); + } + } + QString name_str = unquote(name); + MSNUserData *data = findContact(mail, contact); + if (data){ + data->ScreenName.str() = name; + setupContact(contact, data); + return data; + } + if (bJoin){ + ContactList::ContactIterator it; + while ((contact = ++it) != NULL){ + if (contact->getName() == name_str){ + data = toMSNUserData((SIM::clientData*)contact->clientData.createData(this)); // FIXME unsafe type conversion + data->EMail.str() = mail; + data->ScreenName.str() = name; + setupContact(contact, data); + EventContact e(contact, EventContact::eChanged); + e.process(); + return data; + } + } + it.reset(); + while ((contact = ++it) != NULL){ + if (contact->getName().toLower() == name_str.toLower()){ + data = toMSNUserData((SIM::clientData*)contact->clientData.createData(this)); // FIXME unsafe type conversion + data->EMail.str() = mail; + data->ScreenName.str() = name; + setupContact(contact, data); + EventContact e(contact, EventContact::eChanged); + e.process(); + m_bJoin = true; + return data; + } + } + int n = name_str.indexOf('@'); + if (n > 0){ + name_str = name_str.left(n); + it.reset(); + while ((contact = ++it) != NULL){ + if (contact->getName().toLower() == name_str.toLower()){ + data = toMSNUserData((SIM::clientData*)contact->clientData.createData(this)); // FIXME unsafe type conversion + data->EMail.str() = mail; + data->ScreenName.str() = name; + setupContact(contact, data); + EventContact e(contact, EventContact::eChanged); + e.process(); + m_bJoin = true; + return data; + } + } + } + } + contact = getContacts()->contact(0, true); + data = toMSNUserData((SIM::clientData*)contact->clientData.createData(this)); // FIXME unsafe type conversion + data->EMail.str() = mail; + data->ScreenName.str() = name; + contact->setName(name_str); + EventContact e(contact, EventContact::eChanged); + e.process(); + return data; +} + +MSNUserData *MSNClient::findGroup(unsigned long id, const QString &name, Group *&grp) +{ + ContactList::GroupIterator itg; + while ((grp = ++itg) != NULL){ + ClientDataIterator it(grp->clientData, this); + MSNUserData *res = toMSNUserData(++it); + if ((res == NULL) || (res->Group.toULong() != id)) + continue; + if (!name.isEmpty() && res->ScreenName.setStr(name)){ + grp->setName(name); + EventGroup e(grp, EventGroup::eChanged); + e.process(); + } + return res; + } + if (name.isEmpty()) + return NULL; + QString grpName = name; + itg.reset(); + while ((grp = ++itg) != NULL){ + if (grp->getName() != grpName) + continue; + MSNUserData *res = toMSNUserData((SIM::clientData*)grp->clientData.createData(this)); // FIXME unsafe type conversion + res->Group.asULong() = id; + res->ScreenName.str() = name; + return res; + } + grp = getContacts()->group(0, true); + MSNUserData *res = toMSNUserData((SIM::clientData*)grp->clientData.createData(this)); // FIXME unsafe type conversion + res->Group.asULong() = id; + res->ScreenName.str() = name; + grp->setName(grpName); + EventGroup e(grp, EventGroup::eChanged); + e.process(); + return res; +} + +void MSNClient::auth_message(Contact *contact, unsigned type, MSNUserData *data) +{ + AuthMessage *msg = new AuthMessage(type); + msg->setClient(dataName(data)); + msg->setContact(contact->id()); + msg->setFlags(MESSAGE_RECEIVED); + EventMessageReceived e(msg); + if(!e.process()) + delete msg; +} + +bool MSNClient::done(unsigned code, Buffer&, const QString &headers) +{ + switch (m_state){ + case LoginHost: + if (code == 200){ + QString h = getHeader("PassportURLs", headers); + if (h.isEmpty()){ + socket()->error_state("No PassportURLs answer"); + break; + } + QString loginHost = getValue("DALogin", h); + if (loginHost.isEmpty()){ + socket()->error_state("No DALogin in PassportURLs answer"); + break; + } + QString loginUrl = "https://" + loginHost; + requestTWN(loginUrl); + }else{ + socket()->error_state("Bad answer code"); + } + break; + case TWN: + if (code == 200){ + QString h = getHeader("Authentication-Info", headers); + if (h.isEmpty()){ + socket()->error_state("No Authentication-Info answer"); + break; + } + QString twn = getValue("from-PP", h); + if (twn.isEmpty()){ + socket()->error_state("No from-PP in Authentication-Info answer"); + break; + } + MSNPacket *packet = new UsrPacket(this, twn); + packet->send(); + }else if (code == 401){ + authFailed(); + }else{ + socket()->error_state("Bad answer code"); + } + break; + default: + log(L_WARN, "Fetch done in bad state"); + } + return false; +} + +bool MSNClient::processEvent(Event *e) +{ + TCPClient::processEvent(e); + switch(e->type()) { + case eEventCommandExec: { + EventCommandExec *ece = static_cast(e); + CommandDef *cmd = ece->cmd(); + if (cmd->id == static_cast(protocol()->plugin())->MSNInitMail){ + EventGoURL(m_init_mail).process(); + return true; + } + if (cmd->id == static_cast(protocol()->plugin())->MSNNewMail){ + EventGoURL(m_new_mail).process(); + return true; + } + break; + } + case eEventAddContact: { + EventAddContact *ec = static_cast(e); + EventAddContact::AddContact *ac = ec->addContact(); + if (!ac->proto.isEmpty() && (protocol()->description()->text == ac->proto)) + { + Contact *contact = NULL; + findContact(ac->addr, ac->nick, contact); + if (contact && contact->getGroup() != ac->group) + { + contact->setGroup(ac->group); + EventContact e(contact, EventContact::eChanged); + e.process(); + } + ec->setContact(contact); + return true; + } + break; + } + case eEventDeleteContact: { + EventDeleteContact *ec = static_cast(e); + QString addr = ec->alias(); + ContactList::ContactIterator it; + Contact *contact; + while ((contact = ++it) != NULL){ + MSNUserData *data; + ClientDataIterator itc(contact->clientData, this); + while ((data = toMSNUserData(++itc)) != NULL){ + if (data->EMail.str() == addr){ + contact->clientData.freeData(data); + ClientDataIterator itc(contact->clientData); + if (++itc == NULL) + delete contact; + return true; + } + } + } + break; + } + case eEventGetContactIP: { + EventGetContactIP *ei = static_cast(e); + Contact *contact = ei->contact(); + MSNUserData *data; + ClientDataIterator it(contact->clientData, this); + while ((data = toMSNUserData(++it)) != NULL){ + if (data->IP.ip()) { + ei->setIP(data->IP.ip()); + return true; + } + } + break; + } + case eEventMessageAccept: { + EventMessageAccept *ema = static_cast(e); + Contact *contact = getContacts()->contact(ema->msg()->contact()); + if (contact == NULL) + return false; + MSNUserData *data; + ClientDataIterator it(contact->clientData, this); + while ((data = toMSNUserData(++it)) != NULL){ + if (dataName(data) == ema->msg()->client()){ + SBSocket *sock = dynamic_cast(data->sb.object()); + if (sock) + sock->acceptMessage(ema->msg(), ema->dir(), ema->mode()); + return true; + } + } + break; + } + case eEventMessageDecline: { + EventMessageDecline *emd = static_cast(e); + Contact *contact = getContacts()->contact(emd->msg()->contact()); + if (contact == NULL) + return false; + MSNUserData *data; + ClientDataIterator it(contact->clientData, this); + while ((data = toMSNUserData(++it)) != NULL){ + if (dataName(data) == emd->msg()->client()){ + SBSocket *sock = dynamic_cast(data->sb.object()); + if (sock) + sock->declineMessage(emd->msg(), emd->reason()); + return true; + } + } + break; + } + case eEventContact: { + EventContact *ec = static_cast(e); + Contact *contact = ec->contact(); + switch(ec->action()) { + case EventContact::eDeleted: { + MSNUserData *data; + ClientDataIterator it(contact->clientData, this); + while ((data = toMSNUserData(++it)) != NULL){ + findRequest(data->EMail.str(), LR_CONTACTxCHANGED, true); + MSNListRequest lr; + if (data->Group.toULong() != NO_GROUP){ + lr.Type = LR_CONTACTxREMOVED; + lr.Name = data->EMail.str(); + lr.Group = data->Group.toULong(); + m_requests.push_back(lr); + } + if (data->Flags.toULong() & MSN_BLOCKED){ + lr.Type = LR_CONTACTxREMOVED_BL; + lr.Name = data->EMail.str(); + m_requests.push_back(lr); + } + } + processRequests(); + break; + } + case EventContact::eChanged: { + MSNUserData *data; + ClientDataIterator it(contact->clientData, this); + while ((data = toMSNUserData(++it)) != NULL){ + bool bChanged = false; + if (contact->getIgnore() != ((data->Flags.toULong() & MSN_BLOCKED) != 0)) + bChanged = true; + if (contact->getGroup() != (int)(data->Group.toULong())) + bChanged = true; + if (contact->getName() != data->ScreenName.str()) + bChanged = true; + if (!bChanged) + continue; + findRequest(data->EMail.str(), LR_CONTACTxCHANGED, true); + MSNListRequest lr; + lr.Type = LR_CONTACTxCHANGED; + lr.Name = data->EMail.str(); + m_requests.push_back(lr); + } + processRequests(); + break; + } + default: + break; + } + break; + } + case eEventGroup: { + EventGroup *ev = static_cast(e); + Group *grp = ev->group(); + switch (ev->action()) { + case EventGroup::eChanged: { + ClientDataIterator it(grp->clientData, this); + MSNUserData *data = toMSNUserData(++it); + if ((data == NULL) || (grp->getName() != data->ScreenName.str())){ + findRequest(grp->id(), LR_GROUPxCHANGED, true); + MSNListRequest lr; + lr.Type = LR_GROUPxCHANGED; + lr.Name = QString::number(grp->id()); + m_requests.push_back(lr); + processRequests(); + } + break; + } + case EventGroup::eDeleted: { + ClientDataIterator it(grp->clientData, this); + MSNUserData *data = toMSNUserData(++it); + if (data){ + findRequest(grp->id(), LR_GROUPxCHANGED, true); + MSNListRequest lr; + lr.Type = LR_GROUPxREMOVED; + lr.Name = QString::number(data->Group.toULong()); + m_requests.push_back(lr); + processRequests(); + } + break; + } + case EventGroup::eAdded: + break; + } + break; + } + case eEventMessageCancel: { + EventMessage *em = static_cast(e); + Message *msg = em->msg(); + for (list::iterator it = m_SBsockets.begin(); it != m_SBsockets.end(); ++it){ + if ((*it)->cancelMessage(msg)) + return msg; + } + break; + } + default: + break; + } + return false; +} + +void MSNClient::requestLoginHost(const QString &url) +{ + if (!isDone()) + return; + m_state = LoginHost; + fetch(url); +} + +void MSNClient::requestTWN(const QString &url) +{ + if (!isDone()) + return; + QString auth = "Authorization: Passport1.4 OrgVerb=GET,OrgURL=http%%3A%%2F%%2Fmessenger%%2Emsn%%2Ecom,sign-in="; + auth += quote(getLogin()); + auth += ",pwd="; + auth += quote(getPassword()); + auth += ","; + auth += m_authChallenge; + m_state = TWN; + fetch(url, auth); +} + +QString MSNClient::getValue(const QString &key, const QString &str) +{ + QString s = str; + while (!s.isEmpty()){ + QString k = getToken(s, '='); + QString v; + if (s.startsWith("\'")){ + getToken(s, '\''); + v = getToken(s, '\''); + getToken(s, ','); + }else{ + v = getToken(s, ','); + } + if (k == key) + return v; + } + return QString::null; +} + +QString MSNClient::getHeader(const QString &name, const QString &headers) +{ + int idx = headers.indexOf(name + ':'); + if(idx != -1) { + int end = headers.indexOf('\n', idx); + QString res; + if(end == -1) + res = headers.mid(idx); + else + res = headers.mid(idx, end - idx + 1); + return res.trimmed(); + } + return QString::null; +} + +MSNListRequest *MSNClient::findRequest(unsigned long id, unsigned type, bool bDelete) +{ + if (m_requests.empty()) + return NULL; + return findRequest(QString::number(id), type, bDelete); +} + +MSNListRequest *MSNClient::findRequest(const QString &name, unsigned type, bool bDelete) +{ + if (m_requests.empty()) + return NULL; + for (list::iterator it = m_requests.begin(); it != m_requests.end(); ++it){ + if ((it->Type == type) && (it->Name == name)){ + if (bDelete){ + m_requests.erase(it); + return NULL; + } + return &(*it); + } + } + return NULL; +} + +void MSNClient::processRequests() +{ + if (m_requests.empty() || (getState() != Connected)) + return; + for (list::iterator it = m_requests.begin(); it != m_requests.end(); ++it){ + Group *grp; + Contact *contact; + MSNPacket *packet = NULL; + MSNUserData *data; + switch (it->Type){ + case LR_CONTACTxCHANGED: + data = findContact(it->Name, contact); + if (data){ + bool bBlock = (data->Flags.toULong() & MSN_BLOCKED) != 0; + if (contact->getIgnore() != bBlock){ + if (contact->getIgnore()){ + if (data->Flags.toULong() & MSN_FORWARD) + packet = new RemPacket(this, "FL", it->Name); + if (data->Flags.toULong() & MSN_ACCEPT){ + if (packet) + packet->send(); + packet = new RemPacket(this, "AL", it->Name); + } + data->Flags.asULong() &= ~(MSN_FORWARD | MSN_ACCEPT); + if (packet) + packet->send(); + packet = new AddPacket(this, "BL", data->EMail.str(), quote(contact->getName())); + data->ScreenName.str() = contact->getName(); + data->Flags.asULong() |= MSN_BLOCKED; + }else{ + packet = new RemPacket(this, "BL", data->EMail.str()); + data->Flags.asULong() &= ~MSN_BLOCKED; + } + } + if (data->Flags.toULong() & MSN_BLOCKED) + break; + unsigned grp_id = 0; + if (contact->getGroup()){ + Group *grp = getContacts()->group(contact->getGroup()); + if(grp) { + ClientDataIterator it(grp->clientData, this); + MSNUserData *res = toMSNUserData(++it); + if (res) + grp_id = res->Group.toULong(); + } + } + if (((data->Flags.toULong() & MSN_FORWARD) == 0) || (data->Group.toULong() == NO_GROUP)){ + if (packet) + packet->send(); + packet = new AddPacket(this, "FL", data->EMail.str(), quote(data->ScreenName.str()), grp_id); + data->Group.asULong() = grp_id; + data->Flags.asULong() |= MSN_FORWARD; + } + if (getAutoAuth() && (data->Flags.toULong() & MSN_FORWARD) && ((data->Flags.toULong() & MSN_ACCEPT) == 0) && ((data->Flags.toULong() & MSN_BLOCKED) == 0)){ + if (packet) + packet->send(); + packet = new AddPacket(this, "AL", data->EMail.str(), quote(data->ScreenName.str()), 0); + data->Group.asULong() = grp_id; + data->Flags.asULong() |= MSN_ACCEPT; + } + if (data->Group.toULong() != grp_id){ + if (packet) + packet->send(); + packet = new AddPacket(this, "FL", data->EMail.str(), quote(data->ScreenName.str()), grp_id); + packet->send(); + packet = NULL; + packet = new RemPacket(this, "FL", data->EMail.str(), data->Group.toULong()); + data->Group.asULong() = grp_id; + } + if (contact->getName() != data->ScreenName.str()){ + if (packet) + packet->send(); + packet = new ReaPacket(this, data->EMail.str(), quote(contact->getName())); + data->ScreenName.str() = contact->getName(); + } + } + break; + case LR_CONTACTxREMOVED: + packet = new RemPacket(this, "AL", it->Name); + packet->send(); + packet = new RemPacket(this, "FL", it->Name); + setNDeleted(getNDeleted() + 1); + setDeleted(getNDeleted(), it->Name); + break; + case LR_CONTACTxREMOVED_BL: + packet = new RemPacket(this, "BL", it->Name); + break; + case LR_GROUPxCHANGED: + grp = getContacts()->group(it->Name.toULong()); + if (grp){ + ClientDataIterator it(grp->clientData, this); + data = toMSNUserData(++it); + if (data){ + packet = new RegPacket(this, data->Group.toULong(), quote(grp->getName())); + }else{ + packet = new AdgPacket(this, grp->id(), quote(grp->getName())); + data = toMSNUserData((SIM::clientData*)grp->clientData.createData(this)); // FIXME unsafe type conversion + } + data->ScreenName.str() = grp->getName(); + } + break; + case LR_GROUPxREMOVED: + packet = new RmgPacket(this, it->Name.toULong()); + break; + } + if (packet) + packet->send(); + } + m_requests.clear(); +} + +bool MSNClient::add(const QString &mail, const QString &name, unsigned grp) +{ + Contact *contact; + MSNUserData *data = findContact(mail, contact); + if (data) + { + if (contact->getGroup() != (int)grp) + { + contact->setGroup(grp); + EventContact e(contact, EventContact::eChanged); + e.process(); + } + return false; + } + data = findContact(mail, name, contact); + if (!data) + return false; + contact->setGroup(grp); + EventContact e(contact, EventContact::eChanged); + e.process(); + return true; +} + +bool MSNClient::compareData(void *d1, void *d2) +{ + return (toMSNUserData((SIM::clientData*)d1)->EMail.str() == (toMSNUserData((SIM::clientData*)d2)->EMail.str())); // FIXME unsafe type conversion +} + +static void addIcon(QSet *s, const QString &icon, const QString &statusIcon) +{ + if (!s || statusIcon == icon) + return; + s->insert(icon); +} + +void MSNClient::contactInfo(void *_data, unsigned long &curStatus, unsigned&, QString &statusIcon, QSet *icons) +{ + MSNUserData *data = toMSNUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + unsigned cmp_status = data->Status.toULong(); + const CommandDef *def; + for (def = protocol()->statusList(); !def->text.isEmpty(); def++){ + if (def->id == cmp_status) + break; + } + if ((cmp_status == STATUS_BRB) || (cmp_status == STATUS_PHONE) || (cmp_status == STATUS_LUNCH)) + cmp_status = STATUS_AWAY; + if (data->Status.toULong() > curStatus){ + curStatus = data->Status.toULong(); + if (!statusIcon.isEmpty() && icons){ + icons->insert(statusIcon); + } + statusIcon = def->icon; + }else{ + if (!statusIcon.isEmpty()){ + addIcon(icons, def->icon, statusIcon); + }else{ + statusIcon = def->icon; + } + } + if (icons && data->typing_time.toULong()) + addIcon(icons, "typing", statusIcon); +} + +QString MSNClient::contactTip(void *_data) +{ + MSNUserData *data = toMSNUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + unsigned long status = STATUS_UNKNOWN; + unsigned style = 0; + QString statusIcon; + contactInfo(data, status, style, statusIcon); + QString res; + res += ""; + QString statusText; + for (const CommandDef *cmd = protocol()->statusList(); !cmd->text.isEmpty(); cmd++){ + if (cmd->icon == statusIcon){ + res += " "; + statusText = i18n(cmd->text); + res += statusText; + break; + } + } + res += "
"; + res += data->EMail.str(); + res += "
"; + if (data->Status.toULong() == STATUS_OFFLINE){ + if (data->StatusTime.toULong()){ + res += "
"; + res += i18n("Last online"); + res += ": "; + res += formatDateTime(data->StatusTime.toULong()); + } + }else{ + if (data->OnlineTime.toULong()){ + res += "
"; + res += i18n("Online"); + res += ": "; + res += formatDateTime(data->OnlineTime.toULong()); + } + if (data->Status.toULong() != STATUS_ONLINE){ + res += "
"; + res += statusText; + res += ": "; + res += formatDateTime(data->StatusTime.toULong()); + } + } + if (data->IP.ip()) + { + res += "
"; + res += formatAddr(data->IP, data->Port.toULong()); + } + if (data->RealIP.ip() && ((data->IP.ip() == NULL) || (get_ip(data->IP) != get_ip(data->RealIP)))) + { + res += "
"; + res += formatAddr(data->RealIP, data->Port.toULong()); + } + return res; +} + +QWidget *MSNClient::searchWindow(QWidget *parent) +{ + if (getState() != Connected) + return NULL; + return new MSNSearch(this, parent); +} + + +MSNUserData* MSNClient::toMSNUserData(SIM::clientData * data) +{ + // This function is used to more safely preform type conversion from SIM::clientData* into MSNUserData* + // It will at least warn if the content of the structure is not MSNUserData + // Brave wariors may uncomment abort() function call to know for sure about wrong conversion ;-) + if (! data) return NULL; + if (data->Sign.asULong() != MSN_SIGN) + { + QString Signs[] = { + "Unknown(0)" , // 0x0000 + "ICQ_SIGN", // 0x0001 + "JABBER_SIGN", // 0x0002 + "MSN_SIGN", // 0x0003 + "Unknown(4)" // 0x0004 + "LIVEJOURNAL_SIGN",// 0x0005 + "SMS_SIGN", // 0x0006 + "Unknown(7)", // 0x0007 + "Unknown(8)", // 0x0008 + "YAHOO_SIGN" // 0x0009 + }; + QString Sign; + if (data->Sign.toULong()<=9) // is always >=0 as it is unsigned int + Sign = Signs[data->Sign.toULong()]; + else + Sign = QString("Unknown(%1)").arg(Sign.toULong()); + + log(L_ERROR, + "ATTENTION!! Unsafly converting %s user data into MSN_SIGN", + qPrintable(Sign)); +// abort(); + } + return (MSNUserData*) data; +} + + +SBSocket::SBSocket(MSNClient *client, Contact *contact, MSNUserData *data) +{ + m_state = Unknown; + m_client = client; + m_contact = contact; + m_data = data; + m_socket = new ClientSocket(this, client->createSBSocket()); + m_packet_id = 0; + m_messageSize = 0; + m_invite_cookie = get_random(); + m_bTyping = false; + m_client->m_SBsockets.push_back(this); +} + +SBSocket::~SBSocket() +{ + if (m_packet) + m_packet->clear(); + if (m_socket) + delete m_socket; + list::iterator it = find(m_client->m_SBsockets.begin(), m_client->m_SBsockets.end(), this); + if (it != m_client->m_SBsockets.end()) + m_client->m_SBsockets.erase(it); + if (m_data){ + m_data->sb.clear(); + if (m_data->typing_time.toULong()){ + m_data->typing_time.asULong() = 0; + EventContact e(m_contact, EventContact::eStatus);; + e.process(); + } + } + list::iterator itm; + for (itm = m_queue.begin(); itm != m_queue.end(); ++itm){ + Message *msg = (*itm); + msg->setError(I18N_NOOP("Contact go offline")); + EventMessageSent(msg).process(); + delete msg; + } + list::iterator itw; + for (itw = m_waitMsg.begin(); itw != m_waitMsg.end(); ++itw){ + Message *msg = itw->msg; + msg->setError(I18N_NOOP("Contact go offline")); + EventMessageSent(msg).process(); + delete msg; + } + for (itw = m_acceptMsg.begin(); itw != m_acceptMsg.end(); ++itw){ + Message *msg = itw->msg; + EventMessageDeleted(msg).process(); + delete msg; + } +} + +void SBSocket::connect() +{ + m_packet = new XfrPacket(m_client, this); + m_packet->send(); +} + +void SBSocket::connect(const QString &addr, const QString &session, const QString &cookie, bool bDirection) +{ + m_packet = NULL; + if (m_state != Unknown){ + log(L_DEBUG, "Connect in bad state"); + return; + } + if (bDirection){ + m_state = ConnectingSend; + }else{ + m_state = ConnectingReceive; + } + m_cookie = cookie; + m_session = session; + QString ip = addr; + unsigned short port = 0; + int n = ip.indexOf(':'); + if (n > 0){ + port = ip.mid(n + 1).toUShort(); + ip = ip.left(n); + } + if (port == 0){ + m_socket->error_state("Bad address"); + return; + } + m_socket->connect(ip, port, m_client); +} + +bool SBSocket::send(Message *msg) +{ + + m_bTyping = false; + m_queue.push_back(msg); + switch (m_state){ + case Unknown: + connect(); + break; + case Connected: + process(); + break; + default: + break; + } + return true; +} + +bool SBSocket::error_state(const QString&, unsigned) +{ + if (m_queue.size()){ + m_socket->close(); + connect(); + return false; + } + return true; +} + +void SBSocket::connect_ready() +{ + m_socket->readBuffer().init(0); + m_socket->readBuffer().packetStart(); + m_socket->setRaw(true); + QString args = m_client->data.owner.EMail.str(); + args += ' '; + args += m_cookie; + m_cookie = QString::null; + switch (m_state){ + case ConnectingSend: + send("USR", args); + m_state = WaitJoin; + break; + case ConnectingReceive: + args += " "; + args += m_session; + send("ANS", args); + m_state = Connected; + process(); + break; + default: + log(L_WARN, "Bad state for connect ready"); + } +} + +void SBSocket::packet_ready() +{ + if (m_socket->readBuffer().writePos() == 0) + return; + MSNPlugin *plugin = static_cast(m_client->protocol()->plugin()); + EventLog::log_packet(m_socket->readBuffer(), false, plugin->MSNPacket); + for (;;){ + if (m_messageSize && !getMessage()) + break; + QByteArray s; + if (!m_socket->readBuffer().scan("\r\n", s)) + break; + getLine(s); + } + if (m_socket->readBuffer().readPos() == m_socket->readBuffer().writePos()) + m_socket->readBuffer().init(0); +} + +void SBSocket::getMessage(unsigned size) +{ + m_messageSize = size; + m_message = QString::null; + getMessage(); +} + +bool SBSocket::getMessage() +{ + unsigned tail = m_socket->readBuffer().writePos() - m_socket->readBuffer().readPos(); + if (tail > m_messageSize) + tail = m_messageSize; + QString msg; + m_socket->readBuffer().unpack(msg, tail); + m_message += msg; + m_messageSize -= tail; + if (m_messageSize) + return false; + messageReady(); + return true; +} + +void SBSocket::send(const QString &cmd, const QString &args) +{ + m_socket->writeBuffer().packetStart(); + m_socket->writeBuffer() + << (const char*)cmd.toUtf8() + << " " + << (const char*)QString::number(++m_packet_id).toUtf8(); + if (!args.isEmpty()){ + m_socket->writeBuffer() + << " " + << (const char*)args.toUtf8(); + } + m_socket->writeBuffer() << "\r\n"; + MSNPlugin *plugin = static_cast(m_client->protocol()->plugin()); + EventLog::log_packet(m_socket->writeBuffer(), true, plugin->MSNPacket); + m_socket->write(); +} + +void SBSocket::getLine(const QByteArray &_line) +{ + QString line = QString::fromUtf8(_line); + QString cmd = getToken(line, ' '); + if (cmd == "BYE"){ + m_socket->error_state(""); + return; + } + if (cmd == "MSG"){ + QString email = getToken(line, ' '); + getToken(line, ' '); + unsigned size = line.toUInt(); + getMessage(size); + } + if (cmd == "JOI"){ + if (m_state != WaitJoin){ + log(L_WARN, "JOI in bad state"); + return; + } + m_state = Connected; + process(); + } + if (cmd == "USR") + send("CAL", m_data->EMail.str()); + if ((cmd == "ACK") || (cmd == "NAK")){ + unsigned id = getToken(line, ' ').toUInt(); + if (id != m_msg_id){ + log(L_WARN, "Bad ACK id"); + return; + } + if (m_queue.empty()) + return; + Message *msg = m_queue.front(); + if (cmd == "NAK"){ + m_msgText = QString::null; + msg->setError(I18N_NOOP("Send message failed")); + EventMessageSent(msg).process(); + delete msg; + m_queue.erase(m_queue.begin()); + process(false); + return; + } + if ((msg->getFlags() & MESSAGE_NOHISTORY) == 0){ + Message m(MessageGeneric); + m.setContact(m_contact->id()); + m.setClient(m_client->dataName(m_data)); + m.setText(m_msgPart); + m.setForeground(msg->getForeground()); + m.setBackground(0xFFFFFF); + m.setFont(msg->getFont()); + EventSent(&m).process(); + } + if (m_msgText.isEmpty()){ + if (msg->type() == MessageFile){ + sendFile(); + }else{ + EventMessageSent(msg).process(); + delete msg; + m_queue.erase(m_queue.begin()); + } + } + process(); + } +} + +typedef map STR_VALUES; + +static STR_VALUES parseValues(const QString &str) +{ + STR_VALUES res; + QString s = str.trimmed(); + while (!s.isEmpty()){ + QString p = getToken(s, ';', false).trimmed(); + QString key = getToken(p, '=', false); + STR_VALUES::iterator it = res.find(key); + if (it == res.end()){ + res.insert(STR_VALUES::value_type(key, p)); + }else{ + it->second = p; + } + s = s.trimmed(); + } + return res; +} + +static char FT_GUID[] = "{5D3E02AB-6190-11d3-BBBB-00C04F795683}"; + +void SBSocket::messageReady() +{ + log(L_DEBUG, "MSG: [%s]", qPrintable(m_message)); + QString content_type; + QString charset; + QString font; + QString typing; + unsigned color = 0; + bool bColor = false; + while (!m_message.isEmpty()){ + int n = m_message.indexOf("\r\n"); + if (n < 0){ + log(L_DEBUG, "Error parse message"); + return; + } + if (n == 0){ + m_message = m_message.mid(2); + break; + } + QString line = m_message.left(n); + m_message = m_message.mid(n + 2); + QString key = getToken(line, ':', false); + if (key == "Content-Type"){ + line = line.trimmed(); + content_type = getToken(line, ';').trimmed(); + STR_VALUES v = parseValues(line.trimmed()); + STR_VALUES::iterator it = v.find("charset"); + if (it != v.end()) + charset = it->second; + continue; + } + if (key == "X-MMS-IM-Format"){ + STR_VALUES v = parseValues(line.trimmed()); + STR_VALUES::iterator it = v.find("FN"); + if (it != v.end()) + font = m_client->unquote(it->second); + it = v.find("EF"); + if (it != v.end()){ + QString effects = it->second; + if (effects.indexOf('B') != -1) + font += ", bold"; + if (effects.indexOf('I') != -1) + font += ", italic"; + if (effects.indexOf('S') != -1) + font += ", strikeout"; + if (effects.indexOf('U') != -1) + font += ", underline"; + } + it = v.find("CO"); + if (it != v.end()) + color = it->second.toULong(&bColor, 16); + continue; + } + if (key == "TypingUser"){ + typing = line.trimmed(); + continue; + } + } + if (content_type == "text/plain"){ + if (m_data->typing_time.toULong()){ + m_data->typing_time.asULong() = 0; + EventContact e(m_contact, EventContact::eStatus);; + e.process(); + } + QString msg_text = m_message; + msg_text = msg_text.remove('\r'); + Message *msg = new Message(MessageGeneric); + msg->setFlags(MESSAGE_RECEIVED); + if (bColor){ + msg->setBackground(0xFFFFFF); + msg->setForeground(color); + } + msg->setFont(font); + msg->setText(msg_text); + msg->setContact(m_contact->id()); + msg->setClient(m_client->dataName(m_data)); + EventMessageReceived e(msg); + if (!e.process()) + delete msg; + return; + } + if (content_type == "text/x-msmsgscontrol"){ + if (typing.toLower() == m_data->EMail.str().toLower()){ + bool bEvent = (m_data->typing_time.toULong() == 0); + QDateTime now(QDateTime::currentDateTime()); + m_data->typing_time.asULong() = now.toTime_t(); + if (bEvent) + { + EventContact e(m_contact, EventContact::eStatus);; + e.process(); + } + } + } + if (content_type == "text/x-msmsgsinvite"){ + QString file; + QString command; + QString guid; + QString code; + QString ip_address; + QString ip_address_internal; + unsigned short port = 0; + unsigned short port_x = 0; + unsigned cookie = 0; + unsigned auth_cookie = 0; + unsigned fileSize = 0; + while (!m_message.isEmpty()){ + QString line; + int n = m_message.indexOf("\r\n"); + if (n < 0){ + line = m_message; + m_message = QString::null; + }else{ + line = m_message.left(n); + m_message = m_message.mid(n + 2); + } + QString key = getToken(line, ':', false); + line = line.trimmed(); + if (key == "Application-GUID"){ + guid = line; + continue; + } + if (key == "Invitation-Command"){ + command = line; + continue; + } + if (key == "Invitation-Cookie"){ + cookie = line.toULong(); + continue; + } + if (key == "Application-File"){ + file = line; + continue; + } + if (key == "Application-FileSize"){ + fileSize = line.toULong(); + continue; + } + if (key == "Cancel-Code"){ + code = line; + continue; + } + if (key == "IP-Address"){ + ip_address = line; + continue; + } + if (key == "IP-Address-Internal"){ + ip_address_internal = line; + continue; + } + if (key == "Port"){ + port = line.toUShort(); + continue; + } + if (key == "PortX"){ + port_x = line.toUShort(); + continue; + } + if (key == "AuthCookie"){ + auth_cookie = line.toULong(); + continue; + } + + } + if (cookie == 0){ + log(L_WARN, "No cookie in message"); + return; + } + if (command == "INVITE"){ + if (guid != FT_GUID){ + log(L_WARN, "Unknown GUID %s", qPrintable(guid)); + return; + } + if (file.isEmpty()){ + log(L_WARN, "No file in message"); + return; + } + FileMessage *msg = new FileMessage; + msg->setDescription(m_client->unquote(file)); + msg->setSize(fileSize); + msg->setFlags(MESSAGE_RECEIVED | MESSAGE_TEMP); + msg->setContact(m_contact->id()); + msg->setClient(m_client->dataName(m_data)); + msgInvite m; + m.msg = msg; + m.cookie = cookie; + m_acceptMsg.push_back(m); + EventMessageReceived e(msg); + if (e.process()){ + for (list::iterator it = m_acceptMsg.begin(); it != m_acceptMsg.end(); ++it){ + if (it->msg == msg){ + m_acceptMsg.erase(it); + break; + } + } + } + }else if (command == "ACCEPT"){ + unsigned ip = QHostAddress(ip_address).toIPv4Address(); + unsigned real_ip = QHostAddress(ip_address_internal).toIPv4Address(); + if (ip != INADDR_NONE) + set_ip(&m_data->IP, ip); + if (real_ip != INADDR_NONE) + set_ip(&m_data->RealIP, real_ip); + if (port) + m_data->Port.asULong() = port; + list::iterator it; + for (it = m_waitMsg.begin(); it != m_waitMsg.end(); ++it){ + if (it->cookie == cookie){ + Message *msg = it->msg; + if (msg->type() == MessageFile){ + m_waitMsg.erase(it); + FileMessage *m = static_cast(msg); + MSNFileTransfer *ft; + bool bNew = false; + if (m->m_transfer){ + ft = static_cast(m->m_transfer); + }else{ + ft = new MSNFileTransfer(m, m_client, m_data); + bNew = true; + } + ft->ip1 = real_ip; + ft->port1 = port; + ft->ip2 = ip; + ft->port2 = port_x; + ft->auth_cookie = auth_cookie; + + if (bNew){ + EventMessageAcked(msg).process(); + } + ft->connect(); + break; + } + msg->setError("Bad type"); + EventMessageSent(msg).process(); + delete msg; + return; + } + } + if (it == m_waitMsg.end()) + log(L_WARN, "No message for accept"); + return; + }else if (command == "CANCEL"){ + if (code == "REJECT"){ + list::iterator it; + for (it = m_waitMsg.begin(); it != m_waitMsg.end(); ++it){ + if (it->cookie == cookie){ + Message *msg = it->msg; + msg->setError(I18N_NOOP("Message declined")); + EventMessageSent(msg).process(); + delete msg; + m_waitMsg.erase(it); + break; + } + } + if (it == m_waitMsg.end()) + log(L_WARN, "No message for cancel"); + return; + } + list::iterator it; + for (it = m_acceptMsg.begin(); it != m_acceptMsg.end(); ++it){ + if (it->cookie == cookie){ + Message *msg = it->msg; + EventMessageDeleted(msg).process(); + delete msg; + m_acceptMsg.erase(it); + break; + } + } + if (it == m_acceptMsg.end()) + log(L_WARN, "No message for cancel"); + }else{ + log(L_WARN, "Unknown command %s", qPrintable(command)); + return; + } + } +} + +void SBSocket::timer(unsigned now) +{ + if (m_data->typing_time.toULong()){ + if (now >= m_data->typing_time.toULong() + TYPING_TIME){ + m_data->typing_time.asULong() = 0; + EventContact e(m_contact, EventContact::eStatus);; + e.process(); + } + } + sendTyping(); +} + +void SBSocket::setTyping(bool bTyping) +{ + if (m_bTyping == bTyping) + return; + m_bTyping = bTyping; + sendTyping(); +} + +void SBSocket::sendTyping() +{ + if (m_bTyping && (m_state == Connected)){ + QString message; + message += "MIME-Version: 1.0\r\n"; + message += "Content-Type: text/x-msmsgcontrol\r\n"; + message += "TypingUser: "; + message += m_client->data.owner.EMail.str(); + message += "\r\n"; + message += "\r\n"; + sendMessage(message, "U"); + } +} + +void SBSocket::sendMessage(const QString &str, const char *type) +{ + m_socket->writeBuffer().packetStart(); + m_socket->writeBuffer() + << "MSG " + << (const char*)QString::number(++m_packet_id).toUtf8() + << " " + << type + << " " + << (const char*)QString::number(str.toUtf8().length()).toUtf8() + << "\r\n" + << (const char*)str.toUtf8(); + MSNPlugin *plugin = static_cast(m_client->protocol()->plugin()); + EventLog::log_packet(m_socket->writeBuffer(), true, plugin->MSNPacket); + m_socket->write(); +} + +bool SBSocket::cancelMessage(Message *msg) +{ + if (m_queue.empty()) + return false; + if (m_queue.front() == msg){ + m_msgPart = QString::null; + m_msgText = QString::null; + m_msg_id = 0; + m_queue.erase(m_queue.begin()); + process(); + return true; + } + list::iterator it = find(m_queue.begin(), m_queue.end(), msg); + if (it == m_queue.end()) + return false; + m_queue.erase(it); + delete msg; + return true; +} + +void SBSocket::sendFile() +{ + if (m_queue.empty()) + return; + Message *msg = m_queue.front(); + if (msg->type() != MessageFile) + return; + m_queue.erase(m_queue.begin()); + FileMessage *m = static_cast(msg); + if (++m_invite_cookie == 0) + m_invite_cookie++; + msgInvite mi; + mi.msg = msg; + mi.cookie = m_invite_cookie; + m_waitMsg.push_back(mi); + QString message; + message += "MIME-Version: 1.0\r\n"; + message += "Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n\r\n" + "Application-Name: File Transfer\r\n" + "Application-GUID: "; + message += FT_GUID; + message += "\r\n" + "Invitation-Command: INVITE\r\n" + "Invitation-Cookie: "; + message += QString::number(m_invite_cookie); + message += "\r\n" + "Application-File: "; + QString name; + unsigned size; + if (m->m_transfer){ + name = m->m_transfer->m_file->fileName(); + size = m->m_transfer->fileSize(); + }else{ + FileMessage::Iterator it(*m); + if (it[0]) + name = *it[0]; + size = it.size(); + } + name = name.replace('\\', '/'); + int n = name.lastIndexOf('/'); + if (n >= 0) + name = name.mid(n + 1); + message += m_client->quote(name); + message += "\r\n" + "Application-FileSize: "; + message += QString::number(size); + message += "\r\n" + "Connectivity: N\r\n\r\n"; + sendMessage(message, "S"); +} + +void SBSocket::process(bool bTyping) +{ + if (bTyping) + sendTyping(); + if (m_msgText.isEmpty() && !m_queue.empty()){ + Message *msg = m_queue.front(); + EventSend e(msg, msg->getPlainText().toUtf8()); + e.process(); + m_msgText = QString::fromUtf8( e.localeText() ); + if (msg->type() == MessageUrl){ + UrlMessage *m = static_cast(msg); + QString msgText = m->getUrl(); + msgText += "\r\n"; + msgText += m_msgText; + m_msgText = msgText; + } + if ((msg->type() == MessageFile) && static_cast(msg)->m_transfer) + m_msgText = QString::null; + if (m_msgText.isEmpty()){ + if (msg->type() == MessageFile){ + sendFile(); + return; + } + EventMessageSent(msg).process(); + delete msg; + m_queue.erase(m_queue.begin()); + } + m_msgText = m_msgText.replace('\n', "\r\n"); + } + if (m_msgText.isEmpty()) + return; + m_msgPart = getPart(m_msgText, 1664); + Message *msg = m_queue.front(); + char color[10]; + sprintf(color, "%06lX", msg->getBackground()); + QString message; + message += "MIME-Version: 1.0\r\n"; + message += "Content-Type: text/plain; charset=UTF-8\r\n"; + message += "X-MMS_IM-Format: "; + if (!msg->getFont().isEmpty()){ + QString font = msg->getFont(); + if (!font.isEmpty()){ + QString font_type; + int n = font.indexOf(", "); + if (n > 0){ + font_type = font.mid(n + 2); + font = font.left(n); + } + message += "FN="; + message += m_client->quote(font); + QString effect; + while (!font_type.isEmpty()){ + QString type = font_type; + int n = font_type.indexOf(", "); + if (n > 0){ + type = font_type.mid(n); + font_type = font_type.mid(n + 2); + }else{ + font_type = QString::null; + } + if (type == "bold") + effect += "B"; + if (type == "italic") + effect += "I"; + if (type == "strikeout") + effect += "S"; + if (type == "underline") + effect += "U"; + } + if (!effect.isEmpty()){ + message += "; EF="; + message += effect; + } + } + } + message += "; CO="; + message += color; + message += "; CS=0\r\n"; + message += "\r\n"; + message += m_msgPart; + sendMessage(message, "A"); + m_msg_id = m_packet_id; +} + +void SBSocket::acceptMessage(unsigned short port, unsigned cookie, unsigned auth_cookie) +{ + QString message; + message += "MIME-Version: 1.0\r\n" + "Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n\r\n" + "IP-Address: "; + message += QHostAddress(get_ip(m_client->data.owner.IP)).toString(); + message += "\r\n" + "IP-Address-Internal: "; + message += QHostAddress(m_client->socket()->localHost()).toString(); + message += "\r\n" + "Port: "; + message += QString::number(port); + message += "\r\n" + "AuthCookie: "; + message += QString::number(auth_cookie); + message += "\r\n" + "Sender-Connect: TRUE\r\n" + "Invitation-Command: ACCEPT\r\n" + "Invitation-Cookie: "; + message += QString::number(cookie); + message += "\r\n" + "Launch-Application: FALSE\r\n" + "Request-Data: IP-Address:\r\n\r\n"; + sendMessage(message, "N"); +} + +bool SBSocket::acceptMessage(Message *msg, const QString &dir, OverwriteMode mode) +{ + for (list::iterator it = m_acceptMsg.begin(); it != m_acceptMsg.end(); ++it){ + if (it->msg->id() != msg->id()) + continue; + Message *msg = it->msg; + unsigned cookie = it->cookie; + m_acceptMsg.erase(it); + MSNFileTransfer *ft = new MSNFileTransfer(static_cast(msg), m_client, m_data); + ft->setDir(dir); + ft->setOverwrite(mode); + ft->auth_cookie = get_random(); + ft->cookie = cookie; + EventMessageAcked(msg).process(); + ft->listen(); + EventMessageDeleted(msg).process(); + return true; + } + return false; +} + +void SBSocket::declineMessage(unsigned cookie) +{ + QString message; + message += "MIME-Version: 1.0\r\n" + "Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n\r\n" + "Invitation-Command: CANCEL\r\n" + "Invitation-Cookie: "; + message += QString::number(cookie); + message += "\r\n" + "Cancel-Code: REJECT\r\n\r\n"; + sendMessage(message, "S"); +} + +bool SBSocket::declineMessage(Message *msg, const QString &reason) +{ + for (list::iterator it = m_acceptMsg.begin(); it != m_acceptMsg.end(); ++it){ + if (it->msg->id() != msg->id()) + continue; + Message *msg = it->msg; + unsigned cookie = it->cookie; + m_acceptMsg.erase(it); + declineMessage(cookie); + if (!reason.isEmpty()){ + Message *msg = new Message(MessageGeneric); + msg->setText(reason); + msg->setFlags(MESSAGE_NOHISTORY); + if (!m_client->send(msg, m_data)) + delete msg; + } + delete msg; + return true; + } + return false; +} + diff --git a/plugins/msn/msnclient.h b/plugins/msn/msnclient.h new file mode 100644 index 0000000..c5c0501 --- /dev/null +++ b/plugins/msn/msnclient.h @@ -0,0 +1,329 @@ +/*************************************************************************** + msnclient.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _MSNCLIENT_H +#define _MSNCLIENT_H + +#include "socket/socket.h" +#include "socket/serversocketnotify.h" +#include "socket/tcpclient.h" +#include "fetch.h" +#include + +const unsigned MSN_SIGN = 0x0003; + +const unsigned STATUS_BRB = 101; +const unsigned STATUS_PHONE = 102; +const unsigned STATUS_LUNCH = 103; + +const unsigned MSN_FORWARD = 0x0001; +const unsigned MSN_ACCEPT = 0x0002; +const unsigned MSN_BLOCKED = 0x0004; +const unsigned MSN_REVERSE = 0x0008; + +const unsigned MSN_FLAGS = 0x000F; +const unsigned MSN_CHECKED = 0x1000; + +class SBSocket; + +struct MSNUserData : public SIM::clientData +{ + SIM::Data EMail; + SIM::Data ScreenName; + SIM::Data Status; + SIM::Data StatusTime; + SIM::Data OnlineTime; + SIM::Data PhoneHome; + SIM::Data PhoneWork; + SIM::Data PhoneMobile; + SIM::Data Mobile; + SIM::Data Group; + SIM::Data Flags; + SIM::Data sFlags; + SIM::Data typing_time; + SIM::Data IP; + SIM::Data RealIP; + SIM::Data Port; + SIM::Data sb; +}; + +struct MSNClientData +{ + SIM::Data Server; + SIM::Data Port; + SIM::Data ListVer; + SIM::Data ListRequests; + SIM::Data Version; + SIM::Data MinPort; + SIM::Data MaxPort; + SIM::Data UseHTTP; + SIM::Data AutoHTTP; + SIM::Data Deleted; + SIM::Data NDeleted; + SIM::Data AutoAuth; + MSNUserData owner; +}; + +class MSNClient; +class XfrPacket; + +struct msgInvite +{ + SIM::Message *msg; + unsigned cookie; +}; + +class SBSocket : public QObject, public SIM::ClientSocketNotify +{ + Q_OBJECT +public: + SBSocket(MSNClient *client, SIM::Contact *contact, MSNUserData *data); + ~SBSocket(); + void connect(const QString &addr, const QString &session, const QString &cookie, bool bDirection); + void connect(); + bool send(SIM::Message *msg); + void timer(unsigned now); + void setTyping(bool bTyping); + bool cancelMessage(SIM::Message *msg); + bool acceptMessage(SIM::Message *msg, const QString &dir, SIM::OverwriteMode mode); + bool declineMessage(SIM::Message *msg, const QString &reason); + void acceptMessage(unsigned short port, unsigned cookie, unsigned auth_cookie); + void declineMessage(unsigned cookie); +protected: + enum State + { + Unknown, + ConnectingSend, + ConnectingReceive, + WaitJoin, + Connected + }; + virtual bool error_state(const QString &err, unsigned code = 0); + virtual void connect_ready(); + virtual void packet_ready(); + void send(const QString &cmd, const QString &args); + void getLine(const QByteArray &line); + void getMessage(unsigned size); + bool getMessage(); + void messageReady(); + void process(bool bTyping=true); + void sendMessage(const QString &msg, const char *type); + void sendTyping(); + void sendFile(); + std::list m_acceptMsg; + std::list m_waitMsg; + + State m_state; + SIM::Contact *m_contact; + MSNClient *m_client; + MSNUserData *m_data; + QString m_session; + QString m_cookie; + SIM::ClientSocket *m_socket; + unsigned m_packet_id; + QString m_message; + unsigned m_messageSize; + bool m_bTyping; + XfrPacket *m_packet; + std::list m_queue; + QString m_msgText; + QString m_msgPart; + unsigned m_msg_id; + unsigned m_invite_cookie; +}; + +const unsigned LR_CONTACTxCHANGED = 0; +const unsigned LR_CONTACTxREMOVED = 1; +const unsigned LR_CONTACTxREMOVED_BL = 2; +const unsigned LR_GROUPxCHANGED = 3; +const unsigned LR_GROUPxREMOVED = 4; + +const unsigned NO_GROUP = (unsigned)(-1); + +struct MSNListRequest +{ + unsigned Type; + QString Name; + unsigned Group; +}; + +class MSNPacket; +class MSNServerMessage; + +class MSNClient : public SIM::TCPClient, public FetchClient +{ + Q_OBJECT +public: + MSNClient(SIM::Protocol*, Buffer *cfg); + ~MSNClient(); + virtual QString name(); + virtual QWidget *setupWnd(); + virtual QByteArray getConfig(); + PROP_STR(Server); + PROP_USHORT(Port); + PROP_ULONG(ListVer); + PROP_UTF8(ListRequests); + PROP_STR(Version); + PROP_USHORT(MinPort); + PROP_USHORT(MaxPort); + PROP_BOOL(UseHTTP); + PROP_BOOL(AutoHTTP); + PROP_STRLIST(Deleted); + PROP_ULONG(NDeleted); + PROP_BOOL(AutoAuth); + QString getLogin(); + QString unquote(const QString&); + QString quote(const QString&); + void sendLine(const QString &line, bool crlf = true); + void setLogin(const QString&); + MSNClientData data; + QString dataName(void*); + MSNUserData *findContact(const QString &mail, const QString &name, SIM::Contact *&contact, bool nJoin=true); + MSNUserData *findContact(const QString &mail, SIM::Contact *&contact); + MSNUserData *findGroup(unsigned long id, const QString &name, SIM::Group *&grp); + void auth_message(SIM::Contact *contact, unsigned type, MSNUserData *data); + std::list m_requests; + void processRequests(); + MSNListRequest *findRequest(unsigned long id, unsigned type, bool bDelete=false); + MSNListRequest *findRequest(const QString &name, unsigned type, bool bDelete=false); + bool add(const QString &mail, const QString &name, unsigned grp); + std::list m_SBsockets; + virtual void setupContact(SIM::Contact*, void *data); + bool m_bJoin; + SIM::Socket *createSBSocket(); + void connected(); + MSNUserData* toMSNUserData(SIM::clientData * data); +protected slots: + void ping(); + void authOk(); + void authFailed(); +protected: + virtual bool done(unsigned code, Buffer &data, const QString &headers); + virtual QString contactName(void *clientData); + virtual void setInvisible(bool bState); + virtual bool compareData(void*, void*); + virtual void contactInfo(void *_data, unsigned long &status, unsigned &style, QString &statusIcon, QSet *icons = NULL); + virtual QString contactTip(void *_data); + virtual SIM::CommandDef *infoWindows(SIM::Contact*, void *_data); + virtual SIM::CommandDef *configWindows(); + virtual QWidget *infoWindow(QWidget *parent, SIM::Contact*, void *_data, unsigned id); + virtual QWidget *configWindow(QWidget *parent, unsigned id); + virtual bool send(SIM::Message*, void*); + virtual bool canSend(unsigned, void*); + virtual bool processEvent(SIM::Event *e); + virtual QWidget *searchWindow(QWidget *parent); + virtual bool isMyData(SIM::clientData*&, SIM::Contact*&); + virtual bool createData(SIM::clientData*&, SIM::Contact*); + SIM::Socket *createSocket(); + void getLine(const QByteArray &line); + void clearPackets(); + void sendStatus(); + void checkEndSync(); + void processLSG(unsigned id, const QString &name); + void processLST(const QString &mail, const QString &alias, unsigned state, unsigned id); + virtual void packet_ready(); + virtual void connect_ready(); + virtual void setStatus(unsigned status); + virtual void disconnected(); + QString getValue(const QString &key, const QString &str); + QString getHeader(const QString &name, const QString &headers); + unsigned m_packetId; + unsigned m_pingTime; + std::listm_packets; + MSNServerMessage *m_msg; + QString m_curBuddy; + void requestLoginHost(const QString &url); + void requestTWN(const QString &url); + enum AuthState + { + None, + LoginHost, + TWN + }; + AuthState m_state; + QString m_authChallenge; + QString m_init_mail; + QString m_new_mail; + bool m_bFirstTry; + bool m_bHTTP; + bool m_bFirst; + unsigned m_nBuddies; + unsigned m_nGroups; + friend class MSNPacket; + friend class UsrPacket; + friend class QryPacket; + friend class SynPacket; + friend class MSNServerMessage; + friend class SBSocket; +}; + +class MSNFileTransfer : public QObject, public SIM::FileTransfer, public SIM::ClientSocketNotify, public SIM::ServerSocketNotify +{ + Q_OBJECT +public: + MSNFileTransfer(SIM::FileMessage *msg, MSNClient *client, MSNUserData *data); + ~MSNFileTransfer(); + void connect(); + void listen(); + void setSocket(SIM::Socket *s); + unsigned ip1; + unsigned ip2; + unsigned short port1; + unsigned short port2; + unsigned auth_cookie; + unsigned cookie; + +protected slots: + + void timeout(); +protected: + enum State + { + None, + ConnectIP1, + ConnectIP2, + ConnectIP3, + Connected, + Send, + Wait, + Listen, + Receive, + Incoming, + WaitDisconnect, + WaitBye + }; + virtual bool error_state(const QString &err, unsigned code = 0); + virtual void packet_ready(); + virtual void connect_ready(); + virtual void write_ready(); + virtual void startReceive(unsigned pos); + virtual bool accept(SIM::Socket*, unsigned long ip); + virtual void bind_ready(unsigned short port); + virtual bool error(const QString &err); + void send(const QString &line); + bool getLine(const QByteArray &line); + bool m_bHeader; + unsigned m_size; + State m_state; + SIM::ClientSocket *m_socket; + MSNClient *m_client; + MSNUserData *m_data; + QTimer *m_timer; +}; + +#endif + diff --git a/plugins/msn/msnconfig.cpp b/plugins/msn/msnconfig.cpp new file mode 100644 index 0000000..236da99 --- /dev/null +++ b/plugins/msn/msnconfig.cpp @@ -0,0 +1,95 @@ +/*************************************************************************** + msnconfig.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include +#include +#include + +#include "simgui/linklabel.h" +#include "misc.h" + +#include "msnconfig.h" +#include "msnclient.h" + +using namespace SIM; + +MSNConfig::MSNConfig(QWidget *parent, MSNClient *client, bool bConfig) : QWidget(parent) +{ + setupUi(this); + m_client = client; + m_bConfig = bConfig; + if (m_bConfig) + tabCfg->removeTab(tabCfg->indexOf(tabMsn)); + QTimer::singleShot(0, this, SLOT(changed())); + edtLogin->setText(m_client->getLogin()); + edtPassword->setText(m_client->getPassword()); + edtServer->setText(m_client->getServer()); + edtPort->setValue(m_client->getPort()); + connect(edtLogin, SIGNAL(textChanged(const QString&)), this, SLOT(changed(const QString&))); + connect(edtPassword, SIGNAL(textChanged(const QString&)), this, SLOT(changed(const QString&))); + connect(edtServer, SIGNAL(textChanged(const QString&)), this, SLOT(changed(const QString&))); + connect(edtPort, SIGNAL(valueChanged(const QString&)), this, SLOT(changed(const QString&))); + lnkReg->setText(i18n("Register in .NET Passport")); + lnkReg->setUrl(i18n("https://register.passport.net/reg.srf?lc=1033&langid=1033&sl=1")); + edtMinPort->setValue(m_client->getMinPort()); + edtMaxPort->setValue(m_client->getMaxPort()); + chkHTTP->setChecked(m_client->getUseHTTP()); + chkAuto->setChecked(m_client->getAutoHTTP()); + connect(chkAuto, SIGNAL(toggled(bool)), this, SLOT(autoToggled(bool))); + autoToggled(m_client->getAutoHTTP()); + chkAuth->setChecked(m_client->getAutoAuth()); +} + +void MSNConfig::apply(Client*, void*) +{ +} + +void MSNConfig::apply() +{ + if (!m_bConfig){ + m_client->setLogin(edtLogin->text()); + m_client->setPassword(edtPassword->text()); + } + m_client->setServer(edtServer->text()); + m_client->setPort(edtPort->text().toUShort()); + m_client->setMinPort(edtMinPort->text().toUShort()); + m_client->setMaxPort(edtMaxPort->text().toUShort()); + m_client->setUseHTTP(chkHTTP->isChecked()); + m_client->setAutoHTTP(chkAuto->isChecked()); + m_client->setAutoAuth(chkAuth->isChecked()); +} + +void MSNConfig::changed(const QString&) +{ + changed(); +} + +void MSNConfig::changed() +{ + emit okEnabled(!edtLogin->text().isEmpty() && + !edtPassword->text().isEmpty() && + !edtServer->text().isEmpty() && + edtPort->text().toUShort()); +} + +void MSNConfig::autoToggled(bool bState) +{ + chkHTTP->setEnabled(!bState); +} + diff --git a/plugins/msn/msnconfig.h b/plugins/msn/msnconfig.h new file mode 100644 index 0000000..76bd83d --- /dev/null +++ b/plugins/msn/msnconfig.h @@ -0,0 +1,47 @@ +/*************************************************************************** + msnconfig.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _MSNCONFIG_H +#define _MSNCONFIG_H + +#include "contacts.h" + +#include "ui_msnconfigbase.h" + +class MSNClient; + +class MSNConfig : public QWidget, public Ui::MSNConfigBase +{ + Q_OBJECT +public: + MSNConfig(QWidget *parent, MSNClient *client, bool bConfig); +signals: + void okEnabled(bool); +public slots: + void apply(); + void apply(SIM::Client*, void*); +protected slots: + void changed(); + void changed(const QString&); + void autoToggled(bool); +protected: + bool m_bConfig; + MSNClient *m_client; +}; + +#endif + diff --git a/plugins/msn/msnconfigbase.ui b/plugins/msn/msnconfigbase.ui new file mode 100644 index 0000000..35ba6c9 --- /dev/null +++ b/plugins/msn/msnconfigbase.ui @@ -0,0 +1,358 @@ + + + + + MSNConfigBase + + + + 0 + 0 + 302 + 297 + + + + Form2 + + + + 11 + + + 6 + + + + + + &MSN + + + + 11 + + + 6 + + + + + Login: + + + Qt::AlignVCenter|Qt::AlignRight + + + false + + + + + + + + + + Password: + + + Qt::AlignVCenter|Qt::AlignRight + + + false + + + + + + + QLineEdit::Password + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Vertical + + + + + + + + + + + &Network + + + + 11 + + + 6 + + + + + Server: + + + Qt::AlignVCenter|Qt::AlignRight + + + false + + + + + + + + + + Port: + + + Qt::AlignVCenter|Qt::AlignRight + + + false + + + + + + + 0 + + + 6 + + + + + 65535 + + + 1 + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Horizontal + + + + + + + + + Port range for direct connections: + + + false + + + + + + + 0 + + + 6 + + + + + 65534 + + + 1024 + + + + + + + - + + + false + + + + + + + 65534 + + + 1024 + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Horizontal + + + + + + + + + Use &HTTP polling + + + + + + + &Automatically use HTTP polling if proxy required + + + + + + + + 5 + 1 + + + + Note: For HTTP-polling using proxy settings for HTTP + + + Qt::AlignVCenter|Qt::AlignLeft + + + false + + + + + + + QFrame::HLine + + + QFrame::Sunken + + + QFrame::HLine + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Vertical + + + + + + + &Automatically add contacts in accept list + + + + + + + + + + + + QWidget + QWidget +
QWidget
+ + -1 + -1 + + 0 + + 5 + 5 + + image0 + + text + +
+ + LinkLabel + QWidget +
simgui/linklabel.h
+ + -1 + -1 + + 0 + + 1 + 1 + + image1 + + text + +
+
+ + + 789c6dd2c10ac2300c00d07bbf2234b7229d1be245fc04c5a3201e4615f430059d0711ff5ddb2e6bb236ec90eed134cb5a19d8ef36602af5ecdbfeeac05dda0798d3abebde87e3faa374d3807fa0d633a52d38d8de6f679fe33fc776e196f53cd010188256a3600a292882096246517815ca99884606e18044a3a40d91824820924265a7923a2e8bcd05f33db1173e002913175f2a6be6d3294871a2d95fa00e8a94ee017b69d339d90df1e77c57ea072ede6758 + + + 789c6dd2c10ac2300c00d07bbf2234b7229d1ddec44f503c0ae2a154410f53d0ed20e2bf6bdb656dd6861dd23d9a66591b0587fd1654235ebded6f0edcd53e419d87ae7b1f4f9b8f906d0bfe012317426a70b07bdc2f3ec77f8ed6b89559061a0343d06a124cc105596482585094bc0ae599b04646c9018926491b2205e140c485cace25755c175d0a967b622ff900b8cc9c7d29af594ea722d589167f813aa852ba07d94b9dce296e883fe7bb163f23896753 + + +
diff --git a/plugins/msn/msnfiletransfer.cpp b/plugins/msn/msnfiletransfer.cpp new file mode 100644 index 0000000..481fb82 --- /dev/null +++ b/plugins/msn/msnfiletransfer.cpp @@ -0,0 +1,407 @@ +/*************************************************************************** + msnfiltetransfer.cpp - description + ------------------- + begin : Fri Jan 05 2007 + copyright : (C) 2007 Christian Ehrlicher + email : ch.ehrlicher@gmx.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "simapi.h" + +#include "log.h" +#include "message.h" +#include "misc.h" + +#include "msn.h" +#include "msnclient.h" +#include "socket/clientsocket.h" + +using namespace SIM; + +const unsigned long FT_TIMEOUT = 60; +const unsigned MAX_FT_PACKET = 2045; + +MSNFileTransfer::MSNFileTransfer(FileMessage *msg, MSNClient *client, MSNUserData *data) + : FileTransfer(msg) +{ + m_socket = new ClientSocket(this); + m_client = client; + m_state = None; + m_data = data; + m_timer = NULL; + m_size = msg->getSize(); + m_bHeader = false; + m_nFiles = 1; +} + +MSNFileTransfer::~MSNFileTransfer() +{ + if (m_socket) + delete m_socket; +} + + +void MSNFileTransfer::setSocket(Socket *s) +{ + m_state = Incoming; + m_socket->setSocket(s); + m_socket->readBuffer().init(0); + m_socket->readBuffer().packetStart(); + m_socket->setRaw(true); + send("VER MSNFTP"); + FileTransfer::m_state = FileTransfer::Negotiation; + if (m_notify) + m_notify->process(); +} + +void MSNFileTransfer::listen() +{ + if (m_notify) + m_notify->createFile(m_msg->getDescription(), m_size, false); +} + +void MSNFileTransfer::connect() +{ + FileTransfer::m_state = FileTransfer::Connect; + if (m_notify) + m_notify->process(); + if ((m_state == None) || (m_state == Wait)){ + m_state = ConnectIP1; + if (ip1 && port1){ + m_socket->connect(QHostAddress(ip1).toString(), port1, NULL); + return; + } + } + if (m_state == ConnectIP1){ + m_state = ConnectIP2; + if (ip2 && port2){ + m_socket->connect(QHostAddress(ip2).toString(), port2, NULL); + return; + } + } + if (m_state == ConnectIP2){ + m_state = ConnectIP3; + if (ip2 && port1){ + m_socket->connect(QHostAddress(ip2).toString(), port1, NULL); + return; + } + } + error_state(I18N_NOOP("Can't established direct connection"), 0); +} + +bool MSNFileTransfer::error_state(const QString &err, unsigned) +{ + if (m_state == WaitDisconnect) + FileTransfer::m_state = FileTransfer::Done; + if (m_state == ConnectIP1){ + connect(); + return false; + } + if (m_state == Wait) + return false; + if (FileTransfer::m_state != FileTransfer::Done){ + m_state = None; + FileTransfer::m_state = FileTransfer::Error; + m_msg->setError(err); + } + m_msg->m_transfer = NULL; + m_msg->setFlags(m_msg->getFlags() & ~MESSAGE_TEMP); + EventMessageSent(m_msg).process(); + return true; +} + +void MSNFileTransfer::packet_ready() +{ + if (m_state == Receive){ + if (m_bHeader){ + char cmd; + char s1, s2; + m_socket->readBuffer() >> cmd >> s1 >> s2; + log(L_DEBUG, "MSN FT header: %02X %02X %02X", cmd & 0xFF, s1 & 0xFF, s2 & 0xFF); + if (cmd != 0){ + m_socket->error_state(I18N_NOOP("Transfer canceled"), 0); + return; + } + unsigned size = (unsigned char)s1 + ((unsigned char)s2 << 8); + m_bHeader = false; + log(L_DEBUG, "MSN FT header: %u", size); + m_socket->readBuffer().init(size); + }else{ + unsigned size = m_socket->readBuffer().size(); + if (size == 0) + return; + log(L_DEBUG, "MSN FT data: %u", size); + m_file->write(m_socket->readBuffer().data(), size); + m_socket->readBuffer().incReadPos(size); + m_bytes += size; + m_totalBytes += size; + m_transferBytes += size; + if (m_notify) + m_notify->process(); + m_size -= size; + if (m_size <= 0){ + m_socket->readBuffer().init(0); + m_socket->setRaw(true); + send("BYE 16777989"); + m_state = WaitDisconnect; + if (m_notify) + m_notify->transfer(false); + return; + } + m_bHeader = true; + m_socket->readBuffer().init(3); + } + return; + } + if (m_socket->readBuffer().writePos() == 0) + return; + MSNPlugin *plugin = static_cast(m_client->protocol()->plugin()); + EventLog::log_packet(m_socket->readBuffer(), false, plugin->MSNPacket); + for (;;){ + QByteArray s; + if (!m_socket->readBuffer().scan("\r\n", s)) + break; + if (getLine(s)) + return; + } + if (m_socket->readBuffer().readPos() == m_socket->readBuffer().writePos()) + m_socket->readBuffer().init(0); +} + +void MSNFileTransfer::connect_ready() +{ + log(L_DEBUG, "Connect ready"); + m_state = Connected; + FileTransfer::m_state = Negotiation; + if (m_notify) + m_notify->process(); + m_socket->readBuffer().init(0); + m_socket->readBuffer().packetStart(); + m_socket->setRaw(true); +} + +void MSNFileTransfer::startReceive(unsigned pos) +{ + if (pos > m_size){ + SBSocket *sock = dynamic_cast(m_data->sb.object()); + FileTransfer::m_state = FileTransfer::Done; + m_state = None; + if (sock) + sock->declineMessage(cookie); + m_socket->error_state("", 0); + return; + } + m_timer = new QTimer(this); + QObject::connect(m_timer, SIGNAL(timeout()), this, SLOT(timeout())); + m_timer->start(FT_TIMEOUT * 1000); + m_state = Listen; + FileTransfer::m_state = FileTransfer::Listen; + if (m_notify) + m_notify->process(); + bind(m_client->getMinPort(), m_client->getMaxPort(), m_client); +} + +void MSNFileTransfer::send(const QString &line) +{ + log(L_DEBUG, "Send: %s", qPrintable(line)); + m_socket->writeBuffer().packetStart(); + m_socket->writeBuffer() << (const char*)line.toUtf8(); + m_socket->writeBuffer() << "\r\n"; + MSNPlugin *plugin = static_cast(m_client->protocol()->plugin()); + EventLog::log_packet(m_socket->writeBuffer(), true, plugin->MSNPacket); + m_socket->write(); +} + +bool MSNFileTransfer::getLine(const QByteArray &line) +{ + QString l = QString::fromUtf8(line); + l = l.remove('\r'); + log(L_DEBUG, "Get: %s", qPrintable(l)); + + QString cmd = getToken(l, ' '); + if ((cmd == "VER") && (l == "MSNFTP")){ + if (m_state == Incoming){ + QString usr = "USR "; + usr += m_client->quote(m_client->data.owner.EMail.str()); + usr += " "; + usr += QString::number(auth_cookie); + send(usr); + }else{ + send("VER MSNFTP"); + } + return false; + } + if (cmd == "USR"){ + QString mail = m_client->unquote(getToken(l, ' ')); + unsigned auth = l.toUInt(); + if (mail.toLower() != m_data->EMail.str().toLower()){ + error_state("Bad address", 0); + return false; + } + if (auth != auth_cookie){ + error_state("Bad auth cookie", 0); + return false; + } + if (m_file == NULL){ + for (;;){ + if (!openFile()){ + if (FileTransfer::m_state == FileTransfer::Done) + m_socket->error_state(""); + if (m_notify) + m_notify->transfer(false); + return false; + } + if (!isDirectory()) + break; + } + } + QString cmd = "FIL "; + cmd += QString::number(m_fileSize); + send(cmd); + return false; + } + if (cmd == "TFR"){ + FileTransfer::m_state = FileTransfer::Write; + m_state = Send; + if (m_notify) + m_notify->transfer(true); + write_ready(); + return false; + } + if (cmd == "FIL"){ + send("TFR"); + m_bHeader = true; + m_socket->readBuffer().init(3); + m_socket->readBuffer().packetStart(); + m_state = Receive; + m_socket->setRaw(false); + FileTransfer::m_state = FileTransfer::Read; + m_size = l.toULong(); + m_bytes = 0; + if (m_notify){ + m_notify->transfer(true); + m_notify->process(); + } + return true; + } + if (cmd == "BYE"){ + if (m_notify) + m_notify->transfer(false); + for (bool doloop=true;doloop;){ + if (!openFile()){ + if (FileTransfer::m_state == FileTransfer::Done) + m_socket->error_state(""); + return true; + } + if (isDirectory()){ + doloop=false; + continue; + } + m_state = Wait; + FileTransfer::m_state = FileTransfer::Wait; + if (!((Client*)m_client)->send(m_msg, m_data)) + error_state(I18N_NOOP("File transfer failed"), 0); + } + if (m_notify) + m_notify->process(); + m_socket->close(); + return true; + } + error_state("Bad line", 0); + return false; +} + +void MSNFileTransfer::timeout() +{ +} + +void MSNFileTransfer::write_ready() +{ + if (m_state != Send){ + ClientSocketNotify::write_ready(); + return; + } + if (m_transfer){ + m_transferBytes += m_transfer; + m_transfer = 0; + if (m_notify) + m_notify->process(); + } + if (m_bytes >= m_fileSize){ + m_state = WaitBye; + return; + } + QDateTime now(QDateTime::currentDateTime()); + if (now != m_sendTime){ + m_sendTime = now; + m_sendSize = 0; + } + if (m_sendSize > (m_speed << 18)){ + m_socket->pause(1); + return; + } + unsigned long tail = m_fileSize - m_bytes; + if (tail > MAX_FT_PACKET) tail = MAX_FT_PACKET; + m_socket->writeBuffer().packetStart(); + char buf[MAX_FT_PACKET + 3]; + buf[0] = 0; + buf[1] = (char)(tail & 0xFF); + buf[2] = (char)((tail >> 8) & 0xFF); + int readn = m_file->read(&buf[3], tail); + if (readn <= 0){ + m_socket->error_state("Read file error"); + return; + } + m_transfer = readn; + m_bytes += readn; + m_totalBytes += readn; + m_sendSize += readn; + m_socket->writeBuffer().pack(buf, readn + 3); + m_socket->write(); +} + +bool MSNFileTransfer::accept(Socket *s, unsigned long ip) +{ + log(L_DEBUG, "Accept direct connection %s", qPrintable(QHostAddress(ip).toString())); + m_socket->setSocket(s); + m_socket->readBuffer().init(0); + m_socket->readBuffer().packetStart(); + m_socket->setRaw(true); + FileTransfer::m_state = Negotiation; + m_state = Incoming; + if (m_notify) + m_notify->process(); + send("VER MSNFTP"); + return true; +} + +void MSNFileTransfer::bind_ready(unsigned short port) +{ + SBSocket *sock = dynamic_cast(m_data->sb.object()); + if (sock == NULL){ + error_state("No switchboard socket", 0); + return; + } + sock->acceptMessage(port, cookie, auth_cookie); +} + +bool MSNFileTransfer::error(const QString &err) +{ + return error_state(err, 0); +} diff --git a/plugins/msn/msnhttp.cpp b/plugins/msn/msnhttp.cpp new file mode 100644 index 0000000..b24b696 --- /dev/null +++ b/plugins/msn/msnhttp.cpp @@ -0,0 +1,172 @@ +/*************************************************************************** + msnhttp.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include + +#include "fetch.h" +#include "log.h" + +#include "msnhttp.h" +#include "msnclient.h" + +using namespace SIM; + +const unsigned POLL_TIMEOUT = 10; + +// ______________________________________________________________________________________ + +MSNHttpPool::MSNHttpPool(MSNClient *client, bool bSB) +{ + m_client = client; + m_bSB = bSB; + writeData = new Buffer; +} + +MSNHttpPool::~MSNHttpPool() +{ + delete writeData; +} + +int MSNHttpPool::read(char *buf, unsigned size) +{ + unsigned tail = readData.size() - readData.readPos(); + if (size > tail) size = tail; + if (size == 0) return 0; + readData.unpack(buf, size); + if (readData.readPos() == (unsigned)readData.size()) + readData.init(0); + return size; +} + +static char MSN_HTTP[] = "/gateway/gateway.dll?"; + +void MSNHttpPool::write(const char *buf, unsigned size) +{ + writeData->pack(buf, size); + if (!isDone()) + return; + QString url = "http://"; + if (m_session_id.isEmpty()){ + url += "gateway.messenger.hotmail.com"; + url += MSN_HTTP; + url += "Action=open&Server="; + url += m_bSB ? "SB" : "NS"; + url += "&IP="; + url += m_ip; + }else{ + url += m_host; + url += MSN_HTTP; + if (writeData->writePos() == 0) + url += "Action=poll&"; + url += "SessionID=" + m_session_id; + } + const char *headers = + "Content-Type: application/x-msn-messenger\n" + "Proxy-Connection: Keep-Alive"; + fetch(url, headers, writeData); + writeData = new Buffer; +} + +void MSNHttpPool::close() +{ + delete writeData; + writeData = new Buffer; + m_session_id = QString::null; + m_host = QString::null; + stop(); +} + +void MSNHttpPool::connect(const QString &host, unsigned short) +{ + m_ip = host; + if (notify) + notify->connect_ready(); +} + +void MSNHttpPool::idle() +{ + if (isDone() && (m_client->isDone())){ + log(L_DEBUG, "send idle"); + write("", 0); + } +} + +bool MSNHttpPool::done(unsigned code, Buffer &data, const QString &headers) +{ + if (code != 200){ + log(L_DEBUG, "HTTP result %u", code); + error("Bad result"); + return false; + } + const QStringList sl = headers.split(QLatin1Char('\0')); + Q_FOREACH(QString h, sl) { + if (getToken(h, ':') == QLatin1String("X-MSN-Messenger")){ + QString h = h.trimmed (); + while (!h.isEmpty()){ + QString part = getToken(h, ';'); + QString v = part.trimmed (); + QString k = getToken(v, '='); + if (k == "SessionID"){ + m_session_id = v; + }else if (k == "GW-IP"){ + m_host = v; + } + } + break; + } + } + if (m_session_id.isEmpty() || m_host.isEmpty()){ + error("No session in answer"); + return false; + } + readData.pack(data.data(), data.writePos()); + if (notify) + notify->read_ready(); + QTimer::singleShot(POLL_TIMEOUT * 1000, this, SLOT(idle())); + return false; +} + +unsigned long MSNHttpPool::localHost() +{ + return 0; +} + +void MSNHttpPool::pause(unsigned) +{ +} + +Socket *MSNClient::createSocket() +{ + m_bHTTP = getUseHTTP(); + if (getAutoHTTP()){ + m_bHTTP = m_bFirstTry; + if (!m_bFirstTry) + m_bFirstTry = true; + } + if (m_bHTTP) + return new MSNHttpPool(this, false); + return NULL; +} + +Socket *MSNClient::createSBSocket() +{ + if (m_bHTTP) + return new MSNHttpPool(this, true); + return NULL; +} + diff --git a/plugins/msn/msnhttp.h b/plugins/msn/msnhttp.h new file mode 100644 index 0000000..bb7be43 --- /dev/null +++ b/plugins/msn/msnhttp.h @@ -0,0 +1,54 @@ +/*************************************************************************** + msnhttp.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef MSNHTTP_H +#define MSNHTTP_H 1 + +#include "socket/socket.h" +#include "fetch.h" + +class MSNClient; + +class MSNHttpPool : public QObject, public SIM::Socket, public FetchClient +{ + Q_OBJECT +public: + MSNHttpPool(MSNClient *client, bool bSB); + ~MSNHttpPool(); + virtual void connect(const QString &host, unsigned short port); + virtual int read(char *buf, unsigned size); + virtual void write(const char *buf, unsigned size); + virtual void close(); + virtual Mode mode() const { return Web; } + virtual bool isEncrypted(){ return false; } + virtual bool startEncryption(){ return false; } +protected slots: + void idle(); +protected: + QString m_session_id; + QString m_host; + QString m_ip; + Buffer readData; + Buffer *writeData; + virtual bool done(unsigned code, Buffer &data, const QString &headers); + virtual unsigned long localHost(); + virtual void pause(unsigned); + bool m_bSB; + MSNClient *m_client; +}; + +#endif diff --git a/plugins/msn/msninfo.cpp b/plugins/msn/msninfo.cpp new file mode 100644 index 0000000..fdd2b1e --- /dev/null +++ b/plugins/msn/msninfo.cpp @@ -0,0 +1,128 @@ +/*************************************************************************** + msninfo.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "icons.h" +#include "misc.h" + +#include "msninfo.h" +#include "msnclient.h" +#include "contacts/contact.h" + +using namespace SIM; + +MSNInfo::MSNInfo(QWidget *parent, MSNUserData *data, MSNClient *client) : QWidget(parent) +{ + setupUi(this); + m_client = client; + m_data = data; + edtOnline->setReadOnly(true); + edtNA->setReadOnly(true); + edtEMail->setReadOnly(true); + if (m_data){ + edtNick->setReadOnly(true); + } + fill(); +} + +void MSNInfo::apply() +{ +} + +bool MSNInfo::processEvent(Event *e) +{ + if ((e->type() == eEventMessageReceived) && m_data){ + EventMessage *em = static_cast(e); + Message *msg = em->msg(); + if ((msg->type() == MessageStatus) && (m_client->dataName(m_data) == msg->client())) + fill(); + } else + if (e->type() == eEventContact){ + EventContact *ec = static_cast(e); + if(ec->action() != EventContact::eChanged) + return false; + Contact *contact = ec->contact(); + if (contact->clientData.have(m_data)) + fill(); + } else + if ((e->type() == eEventClientChanged) && (m_data == 0)){ + EventClientChanged *ecc = static_cast(e); + if (ecc->client() == m_client) + fill(); + } + return false; +} + +void MSNInfo::fill() +{ + MSNUserData *data = m_data; + if (data == NULL) data = &m_client->data.owner; + edtEMail->setText(data->EMail.str()); + edtNick->setText(!data->ScreenName.str().isEmpty() ? data->ScreenName.str() : data->EMail.str()); + int current = 0; + QString text; + unsigned status = m_data ? m_data->Status.toULong() : m_client->getStatus(); + for (const CommandDef *cmd = m_client->protocol()->statusList(); cmd->id; cmd++){ + if (cmd->flags & COMMAND_CHECK_STATE) + continue; + if (status == cmd->id){ + current = cmbStatus->count(); + text = cmd->text; + } + cmbStatus->addItem(Icon(cmd->icon), i18n(cmd->text)); + } + cmbStatus->setCurrentIndex(current); + disableWidget(cmbStatus); + if (status == STATUS_OFFLINE){ + lblOnline->setText(i18n("Last online") + ":"); + edtOnline->setText(formatDateTime(data->StatusTime.toULong())); + lblNA->hide(); + edtNA->hide(); + }else{ + if (data->OnlineTime.toULong()){ + edtOnline->setText(formatDateTime(data->OnlineTime.toULong())); + }else{ + lblOnline->hide(); + edtOnline->hide(); + } + if ((status == STATUS_ONLINE) || (text.isEmpty())){ + lblNA->hide(); + edtNA->hide(); + }else{ + lblNA->setText(i18n(text)); + edtNA->setText(formatDateTime(data->StatusTime.toULong())); + } + } +} + +void MSNInfo::apply(Client *client, void *_data) +{ + if (client != m_client) + return; + QString nick = edtNick->text(); + if (nick == edtEMail->text()) + nick = QString::null; + MSNUserData *data = m_client->toMSNUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + data->ScreenName.str() = nick; +} + diff --git a/plugins/msn/msninfo.h b/plugins/msn/msninfo.h new file mode 100644 index 0000000..e4385f2 --- /dev/null +++ b/plugins/msn/msninfo.h @@ -0,0 +1,44 @@ +/*************************************************************************** + msninfo.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _MSNINFO_H +#define _MSNINFO_H + +#include "ui_msninfobase.h" +#include "event.h" + +struct MSNUserData; +class MSNClient; + +class MSNInfo : public QWidget, public Ui::MSNInfoBase, public SIM::EventReceiver +{ + Q_OBJECT +public: + MSNInfo(QWidget *parent, MSNUserData *data, MSNClient *client); +public slots: + void apply(); + void apply(SIM::Client*, void*); +protected: + virtual bool processEvent(SIM::Event *e); + void fill(); + MSNUserData *m_data; + MSNClient *m_client; +}; + + +#endif + diff --git a/plugins/msn/msninfobase.ui b/plugins/msn/msninfobase.ui new file mode 100644 index 0000000..2eac30c --- /dev/null +++ b/plugins/msn/msninfobase.ui @@ -0,0 +1,225 @@ + + + + + MSNInfoBase + + + + 0 + 0 + 342 + 316 + + + + Form1 + + + + 11 + + + 6 + + + + + + &Names + + + + 11 + + + 6 + + + + + + true + + + + EMail + + + Qt::AlignVCenter|Qt::AlignRight + + + false + + + + + + + + true + + + + + + + + QFrame::HLine + + + QFrame::Sunken + + + QFrame::HLine + + + + + + + Nick: + + + Qt::AlignVCenter|Qt::AlignRight + + + false + + + + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Vertical + + + + + + + + &Status + + + + 11 + + + 6 + + + + + Status: + + + Qt::AlignVCenter|Qt::AlignRight + + + false + + + + + + + + 7 + 0 + + + + + + + + Online: + + + Qt::AlignVCenter|Qt::AlignRight + + + false + + + + + + + + + + + + + Qt::AlignVCenter|Qt::AlignRight + + + false + + + + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Vertical + + + + + + + + + + + + QWidget + QWidget +
QWidget
+ + -1 + -1 + + 0 + + 5 + 5 + + image0 + + text + +
+
+ + + 789c6dd2c10ac2300c00d07bbf2234b7229d1be245fc04c5a3201e4615f430059d0711ff5ddb2e6bb236ec90eed134cb5a19d8ef36602af5ecdbfeeac05dda0798d3abebde87e3faa374d3807fa0d633a52d38d8de6f679fe33fc776e196f53cd010188256a3600a292882096246517815ca99884606e18044a3a40d91824820924265a7923a2e8bcd05f33db1173e002913175f2a6be6d3294871a2d95fa00e8a94ee017b69d339d90df1e77c57ea072ede6758 + + +
diff --git a/plugins/msn/msnpacket.cpp b/plugins/msn/msnpacket.cpp new file mode 100644 index 0000000..b5842c9 --- /dev/null +++ b/plugins/msn/msnpacket.cpp @@ -0,0 +1,530 @@ +/*************************************************************************** + msnpacket.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include +#include +#include + +#include "log.h" +#include "misc.h" + +#include "msnpacket.h" +#include "msnclient.h" +#include "msn.h" +#include "socket/clientsocket.h" +#include "contacts/clientdataiterator.h" +#include "contacts/contact.h" +#include "contacts/group.h" + +using namespace std; +using namespace SIM; + +MSNPacket::MSNPacket(MSNClient *client, const QString &cmd) +{ + m_cmd = cmd; + m_client = client; + m_id = ++m_client->m_packetId; + m_line = cmd; + m_line += ' '; + m_line += QString::number(m_id); +} + +void MSNPacket::addArg(const QString &str) +{ + m_line += ' '; + m_line += str; +} + +void MSNPacket::addArg(const char *str) +{ + m_line += ' '; + m_line += QString::fromUtf8(str); +} + +void MSNPacket::send() +{ + m_client->sendLine(m_line); + m_line = QString::null; + m_client->m_packets.push_back(this); +} + +struct err_str +{ + unsigned code; + const char *str; +}; + +static err_str msn_errors[] = + { + { 200, "Syntax error" }, + { 201, "Invalid parameter" }, + { 205, "Invalid user" }, + { 206, "FQDN missing" }, + { 207, "Already login" }, + { 208, "Invalid username" }, + { 209, "Invalid friendly name" }, + { 210, "List full" }, + { 215, "Already there" }, + { 216, "Not on list" }, + { 217, "User not on-line" }, + { 218, "Already in the mode" }, + { 219, "Already in opposite list" }, + { 223, "Too many groups" }, + { 224, "Invalid group" }, + { 225, "User not in group" }, + { 229, "Group name too long" }, + { 230, "Cannot remove group 0" }, + { 231, "Invalid group" }, + { 280, "Switchboard failed" }, + { 281, "Notify XFR failed" }, + { 300, "required fields missing" }, + { 302, "Not logged in" }, + { 500, "Internal server error" }, + { 501, "DB server error" }, + { 502, "Command disabled" }, + { 510, "File operation error" }, + { 520, "Memory allocation error" }, + { 540, "Challenge response failed" }, + { 600, "Server busy" }, + { 601, "Server unavailable" }, + { 602, "Peer NS down" }, + { 603, "DB connect error" }, + { 604, "Server going down" }, + { 605, "Server unavailable" }, + { 707, "Create connection error" }, + { 710, "Bad CVR parameters sent" }, + { 711, "Blocking write" }, + { 712, "Session overload" }, + { 713, "User too active" }, + { 714, "Too many sessions" }, + { 715, "Not expected (PRP)" }, + { 717, "Bad friend file" }, + { 731, "Not expected (CVR)" }, + { 800, "Changing too rapidly" }, + { 910, "Server too busy" }, + { 911, "Authentication failed" }, + { 912, "Server too busy" }, + { 913, "Not allowed when offline" }, + { 914, "Server unavailable" }, + { 915, "Server unavailable" }, + { 916, "Server unavailable" }, + { 917, "Authentication failed" }, + { 918, "Server too busy" }, + { 919, "Server too busy" }, + { 920, "Not accepting new users" }, + { 921, "Server too busy" }, + { 922, "Server too busy" }, + { 923, "Kids Passport without parental consent" }, + { 924, "Email address not verified" }, + { 928, "Bad ticket" }, + { 0, NULL } + }; + +void MSNPacket::error(unsigned code) +{ + switch (code){ + case 911: + m_client->authFailed(); + return; + } + const err_str *err; + for (err = msn_errors; err->code; err++) + if (err->code == code) + break; + if (err->code){ + m_client->socket()->error_state(err->str); + return; + } + log(L_WARN, "Unknown error code %u", code); + m_client->socket()->error_state("Protocol error"); +} + +VerPacket::VerPacket(MSNClient *client) + : MSNPacket(client, "VER") +{ + addArg("MSNP8 CVR0"); +} + +void VerPacket::answer(const QStringList&) +{ + MSNPacket *packet = new CvrPacket(m_client); + packet->send(); +} + +CvrPacket::CvrPacket(MSNClient *client) + : MSNPacket(client, "CVR") +{ + addArg("0x0409 winnt 5.1 i386 MSNMSGR"); + addArg(client->getVersion()); + addArg("MSMSGS"); + addArg(m_client->getLogin()); +} + +void CvrPacket::answer(const QStringList &arg) +{ + m_client->setVersion(arg[0]); + MSNPacket *packet = new UsrPacket(m_client); + packet->send(); +} + +UsrPacket::UsrPacket(MSNClient *client, const QString &digest) + : MSNPacket(client, "USR") +{ + addArg("TWN"); + if (!digest.isEmpty()){ + addArg("S"); + addArg(digest); + }else{ + addArg("I"); + addArg(m_client->getLogin()); + } +} + +void UsrPacket::answer(const QStringList &args) +{ + if (args[0] == "OK"){ + QTimer::singleShot(0, m_client, SLOT(authOk())); + return; + } + if (args[1] == "S"){ + m_client->m_authChallenge = args[2]; + m_client->requestLoginHost("https://nexus.passport.com/rdr/pprdr.asp"); + } +} + +OutPacket::OutPacket(MSNClient *client) + : MSNPacket(client, "OUT") +{ +} + +ChgPacket::ChgPacket(MSNClient *client) + : MSNPacket(client, "CHG") +{ + const char *status = "NLN"; + if (m_client->getInvisible()){ + status = "HDN"; + }else{ + switch (m_client->getStatus()){ + case STATUS_NA: + status = "IDL"; + break; + case STATUS_AWAY: + status = "AWY"; + break; + case STATUS_DND: + status = "BSY"; + break; + case STATUS_BRB: + status = "BRB"; + break; + case STATUS_PHONE: + status = "PHN"; + break; + case STATUS_LUNCH: + status = "LUN"; + break; + } + } + addArg(status); +} + +SynPacket::SynPacket(MSNClient *client) + : MSNPacket(client, "SYN") +{ + client->m_bJoin = false; + addArg("0"); +} + +void SynPacket::answer(const QStringList &args) +{ + unsigned m_ver = 0; + if (!args[0].isEmpty()) + m_ver = args[0].toUInt(); + m_client->m_nBuddies = 0; + m_client->m_nGroups = 0; + if ((args.size() > 1) && !args[1].isEmpty()) + m_client->m_nBuddies = args[1].toUInt(); + if ((args.size() > 2) && !args[2].isEmpty()) + m_client->m_nGroups = args[2].toUInt(); + m_client->setListVer(m_ver); + ContactList::GroupIterator itg; + Group *grp; + while ((grp = ++itg) != NULL){ + MSNUserData *data; + ClientDataIterator it(grp->clientData, m_client); + while ((data = m_client->toMSNUserData(++it)) != NULL){ + data->sFlags.asULong() = data->Flags.toULong(); + if (args.size() > 1) + data->Flags.asULong() = 0; + } + } + ContactList::ContactIterator itc; + Contact *contact; + while ((contact = ++itc) != NULL){ + MSNUserData *data; + ClientDataIterator it(contact->clientData, m_client); + while ((data = m_client->toMSNUserData(++it)) != NULL){ + data->sFlags.asULong() = data->Flags.toULong(); + if (args.size() > 1) + data->Flags.asULong() = 0; + } + } +} + +QryPacket::QryPacket(MSNClient *client, const QString &qry) + : MSNPacket(client, "QRY") +{ + addArg("PROD0038W!61ZTF9"); + addArg("32"); + m_line += "\r\n"; + char qry_add[] = "VT6PX?UQTM4WM%YR"; + QString md = qry; + md += qry_add; + QByteArray ba = QCryptographicHash::hash(md.toUtf8(), QCryptographicHash::Md5); + for (int i = 0; i < ba.size(); i++) + { + char b[3]; + sprintf(b, "%02x", ba[(int)i] & 0xFF); + m_line += b; + } +} + +void QryPacket::send() +{ + m_client->sendLine(m_line, false); + m_line = QString::null; + m_client->m_packets.push_back(this); +} + +AdgPacket::AdgPacket(MSNClient *client, unsigned grp_id, const QString &name) + : MSNPacket(client, "ADG") +{ + m_id = grp_id; + addArg(name); + addArg("0"); +} + +void AdgPacket::answer(const QStringList &args) +{ + Group *grp = getContacts()->group(m_id); + if (grp == NULL) + return; + MSNUserData *data; + ClientDataIterator it(grp->clientData, m_client); + data = m_client->toMSNUserData(++it); + if (data == NULL) + data = m_client->toMSNUserData((SIM::clientData*)grp->clientData.createData(m_client)); // FIXME unsafe type conversion + data->Group.asULong() = args[2].toULong(); +} + +RegPacket::RegPacket(MSNClient *client, unsigned id, const QString &name) + : MSNPacket(client, "REG") +{ + addArg(QString::number(id)); + addArg(name); + addArg("0"); +} + +RmgPacket::RmgPacket(MSNClient *client, unsigned long id) + : MSNPacket(client, "RMG") +{ + addArg(QString::number(id)); +} + +AddPacket::AddPacket(MSNClient *client, const QString &listType, const QString &mail, const QString &name, unsigned grp) + : MSNPacket(client, "ADD") +{ + m_mail = mail; + addArg(listType); + addArg(mail); + addArg(name); + if (listType == "FL") + addArg(QString::number(grp)); +} + +void AddPacket::error(unsigned) +{ + Contact *contact; + MSNUserData *data = m_client->findContact(m_mail, contact); + if (data){ + contact->clientData.freeData(data); + if (contact->clientData.size() == 0) + delete contact; + } +// not handled anywhere +// Event e(static_cast(m_client->protocol()->plugin())->EventAddFail, (void*)(m_mail.latin1())); +// e.process(); +} + +void AddPacket::answer(const QStringList&) +{ +// not handled anywhere +// Event e(static_cast(m_client->protocol()->plugin())->EventAddOk, (void*)(m_mail.latin1())); +// e.process(); +} + +RemPacket::RemPacket(MSNClient *client, const QString &listType, const QString &mail, unsigned group) + : MSNPacket(client, "REM") +{ + addArg(listType); + addArg(mail); + if (listType == "FL" && (group != NO_GROUP)) + addArg(QString::number(group)); +} + +ReaPacket::ReaPacket(MSNClient *client, const QString &mail, const QString &name) + : MSNPacket(client, "REA") +{ + addArg(mail); + addArg(name); +} + +void ReaPacket::error(unsigned code) +{ + if (code == 216) + return; + MSNPacket::error(code); +} + +BlpPacket::BlpPacket(MSNClient *client) + : MSNPacket(client, "BLP") +{ + addArg("BL"); +} + +XfrPacket::XfrPacket(MSNClient *client, SBSocket *socket) + : MSNPacket(client, "XFR") +{ + m_socket = socket; + addArg("SB"); +} + +void XfrPacket::clear() +{ + m_socket = NULL; +} + +void XfrPacket::answer(const QStringList &args) +{ + if (m_socket) + m_socket->connect(args[1], "", args[3], true); +} + +MSNServerMessage::MSNServerMessage(MSNClient *client, unsigned size) +{ + m_client = client; + m_size = size; +} + +typedef map KEY_MAP; + +MSNServerMessage::~MSNServerMessage() +{ + KEY_MAP values; + QString msg = QString::fromUtf8(m_msg); + for (;!msg.isEmpty();){ + QString line; + int n = msg.indexOf("\r\n"); + if (n >= 0){ + line = msg.left(n); + msg = msg.mid(n + 2); + }else{ + line = msg; + msg = QString::null; + } + n = line.indexOf(':'); + if (n < 0) + continue; + values.insert(KEY_MAP::value_type(line.left(n), line.mid(n + 1).trimmed())); + } + KEY_MAP::iterator it = values.find("ClientIP"); + if (it != values.end()) + set_ip(&m_client->data.owner.IP, QHostAddress(qPrintable(it->second)).toIPv4Address()); + it = values.find("Content-Type"); + if (it != values.end()){ + QString content_type = it->second; + content_type = getToken(content_type, ';'); + if (content_type == "text/x-msmsgsinitialemailnotification"){ + m_client->m_init_mail = QString::null; + it = values.find("Post-URL"); + if (it != values.end()) + m_client->m_init_mail = it->second; + it = values.find("Inbox-URL"); + if (it != values.end()) + m_client->m_init_mail += it->second; + it = values.find("Inbox-Unread"); + if (it == values.end()) + return; + unsigned nUnread = it->second.toUInt(); + if (nUnread){ + EventNotification::ClientNotificationData data; + data.client = m_client; + data.text = "%1"; + data.options = QString::null; + data.args = i18n("You have %n unread message.", "You have %n unread messages.", nUnread); + data.code = 0; + data.flags = EventNotification::ClientNotificationData::E_INFO; + data.id = static_cast(m_client->protocol()->plugin())->MSNInitMail; + EventShowNotification e(data); + e.process(); + } + } + if (content_type == "text/x-msmsgsemailnotification"){ + m_client->m_new_mail = QString::null; + it = values.find("Post-URL"); + if (it != values.end()) + m_client->m_new_mail = it->second; + it = values.find("Message-URL"); + if (it != values.end()) + m_client->m_new_mail += it->second; + QString from; + it = values.find("From-Addr"); + if (it != values.end()) + from = it->second; + QString msg = i18n("You have new mail"); + if (!from.isEmpty()) + msg = i18n("%1 from %2") .arg(msg) .arg(from); + EventNotification::ClientNotificationData data; + data.client = m_client; + data.text = "%1"; + data.options = QString::null; + data.args = msg; + data.code = 0; + data.flags = EventNotification::ClientNotificationData::E_INFO; + data.id = static_cast(m_client->protocol()->plugin())->MSNNewMail; + EventShowNotification e(data); + e.process(); + } + } +} + +bool MSNServerMessage::packet() +{ + Buffer &b = m_client->socket()->readBuffer(); + unsigned size = b.writePos() - b.readPos(); + if (size > m_size) + size = m_size; + if (size > 0){ + m_msg += QByteArray(b.data(b.readPos()), size); + b.incReadPos(size); + m_size -= size; + } + return (m_size == 0); +} + diff --git a/plugins/msn/msnpacket.h b/plugins/msn/msnpacket.h new file mode 100644 index 0000000..04ca8ff --- /dev/null +++ b/plugins/msn/msnpacket.h @@ -0,0 +1,164 @@ +/*************************************************************************** + msnpacket.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _MSNPACKET_H +#define _MSNPACKET_H + +#include "msnclient.h" + +#include + +class MSNPacket +{ +public: + MSNPacket(MSNClient *client, const QString &cmd); + virtual ~MSNPacket(){} + const QString &cmd() const { return m_cmd; } + unsigned id() const { return m_id; } + virtual void answer(const QStringList&) {}; + virtual void error(unsigned code); + void addArg(const QString &str); + void addArg(const char *str); + virtual void send(); +protected: + QString m_line; + QString m_cmd; + MSNClient *m_client; + unsigned m_id; +}; + +class VerPacket : public MSNPacket +{ +public: + VerPacket(MSNClient *client); + void answer(const QStringList &args); +}; + +class CvrPacket : public MSNPacket +{ +public: + CvrPacket(MSNClient *client); + void answer(const QStringList &args); +}; + +class UsrPacket : public MSNPacket +{ +public: + UsrPacket(MSNClient *client, const QString &hash = QString::null); + void answer(const QStringList &args); +}; + +class OutPacket : public MSNPacket +{ +public: + OutPacket(MSNClient *client); +}; + +class ChgPacket : public MSNPacket +{ +public: + ChgPacket(MSNClient *client); +}; + +class SynPacket : public MSNPacket +{ +public: + SynPacket(MSNClient *client); + void answer(const QStringList &args); +}; + +class QryPacket : public MSNPacket +{ +public: + QryPacket(MSNClient *client, const QString &qry); + virtual void send(); +}; + +class AdgPacket : public MSNPacket +{ +public: + AdgPacket(MSNClient *client, unsigned grp_id, const QString &name); + void answer(const QStringList &args); +protected: + unsigned m_id; +}; + +class RegPacket : public MSNPacket +{ +public: + RegPacket(MSNClient *client, unsigned id, const QString &name); +}; + +class RmgPacket : public MSNPacket +{ +public: + RmgPacket(MSNClient *client, unsigned long id); +}; + +class AddPacket : public MSNPacket +{ +public: + AddPacket(MSNClient *client, const QString &listType, const QString &mail, const QString &name, unsigned grp=0); + void answer(const QStringList &args); + virtual void error(unsigned code); +protected: + QString m_mail; +}; + +class RemPacket : public MSNPacket +{ +public: + RemPacket(MSNClient *client, const QString &listType, const QString &mail, unsigned group=NO_GROUP); +}; + +class ReaPacket : public MSNPacket +{ +public: + ReaPacket(MSNClient *client, const QString &mail, const QString &name); + virtual void error(unsigned code); +}; + +class BlpPacket : public MSNPacket +{ +public: + BlpPacket(MSNClient *client); +}; + +class XfrPacket : public MSNPacket +{ +public: + XfrPacket(MSNClient *client, SBSocket *socket); + void clear(); + void answer(const QStringList &args); +protected: + SBSocket *m_socket; +}; + +class MSNServerMessage +{ +public: + MSNServerMessage(MSNClient *client, unsigned size); + ~MSNServerMessage(); + bool packet(); +protected: + QByteArray m_msg; + MSNClient *m_client; + unsigned m_size; +}; + +#endif + diff --git a/plugins/msn/msnsearch.cpp b/plugins/msn/msnsearch.cpp new file mode 100644 index 0000000..53efc5f --- /dev/null +++ b/plugins/msn/msnsearch.cpp @@ -0,0 +1,61 @@ +/*************************************************************************** + msnsearch.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "msnsearch.h" +#include "msnclient.h" +#include "simgui/intedit.h" +#include "contacts/contact.h" + +#include +#include +#include +#include + +using namespace SIM; + +class MSNClient; + +MSNSearch::MSNSearch(MSNClient *client, QWidget *parent) : QWidget(parent) +{ + setupUi(this); + m_client = client; + connect(this, SIGNAL(setAdd(bool)), topLevelWidget(), SLOT(setAdd(bool))); + edtMail->setValidator(new EMailValidator(edtMail)); +} + +void MSNSearch::showEvent(QShowEvent *e) +{ + QWidget::showEvent(e); + emit setAdd(true); +} + +void MSNSearch::createContact(unsigned tmpFlags, Contact *&contact) +{ + QString mail = edtMail->text(); + int pos = 0; + if ((edtMail->validator()->validate(mail, pos) != QValidator::Acceptable)) + return; + if (m_client->findContact(mail, contact)) + return; + QString name = mail; + int n = name.indexOf('@'); + if (n > 0) + name = name.left(n); + m_client->findContact(mail, name, contact, false); + contact->setFlags(contact->getFlags() | tmpFlags); +} + diff --git a/plugins/msn/msnsearch.h b/plugins/msn/msnsearch.h new file mode 100644 index 0000000..7c5ec3e --- /dev/null +++ b/plugins/msn/msnsearch.h @@ -0,0 +1,45 @@ +/*************************************************************************** + msnsearch.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _MSNSEARCH_H +#define _MSNSEARCH_H + +#include "contacts.h" + +#include "ui_msnsearchbase.h" + +#include + +class MSNClient; +class GroupRadioButton; + +class MSNSearch : public QWidget, public Ui::MSNSearch +{ + Q_OBJECT +public: + MSNSearch(MSNClient *client, QWidget *parent); +signals: + void setAdd(bool); +protected slots: + void createContact(unsigned tmpFlags, SIM::Contact *&contact); +protected: + MSNClient *m_client; + void showEvent(QShowEvent*); +}; + +#endif + diff --git a/plugins/msn/msnsearchbase.ui b/plugins/msn/msnsearchbase.ui new file mode 100644 index 0000000..cd3df6d --- /dev/null +++ b/plugins/msn/msnsearchbase.ui @@ -0,0 +1,68 @@ + + + MSNSearch + + + + 0 + 0 + 141 + 293 + + + + Form1 + + + + 6 + + + 0 + + + + + E-Mail + + + + + + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + LinkLabel + QWidget +
simgui/linklabel.h
+
+
+ + +
diff --git a/plugins/navigate/CMakeLists.txt b/plugins/navigate/CMakeLists.txt new file mode 100644 index 0000000..bf74098 --- /dev/null +++ b/plugins/navigate/CMakeLists.txt @@ -0,0 +1,25 @@ +#################### +# navigate library # +#################### +IF(BUILD_DROPPED) +SET(navigate_SRCS + navcfg.cpp + navigate.cpp +) + +SET(navigate_HDRS + navcfg.h + navigate.h +) + +SET(navigate_UICS + navcfgbase.ui +) + +ADD_FLEX_FILES(navigate_SRCS parseurl.ll) + +REMOVE_DEFINITIONS(-DQT3_SUPPORT) +REMOVE_DEFINITIONS(-DQT_3SUPPORT_LIB) +REMOVE_DEFINITIONS(-DQT3_SUPPORT_WARNINGS) +SIM_ADD_PLUGIN(navigate) +ENDIF(BUILD_DROPPED) diff --git a/plugins/navigate/navcfg.cpp b/plugins/navigate/navcfg.cpp new file mode 100644 index 0000000..0c966e8 --- /dev/null +++ b/plugins/navigate/navcfg.cpp @@ -0,0 +1,74 @@ +/*************************************************************************** + navcfg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "simapi.h" + +#include +#include +#include + +#include "navcfg.h" +#include "navigate.h" + +NavCfg::NavCfg(QWidget *parent, NavigatePlugin *plugin) : QWidget(parent) +{ + setupUi(this); + m_plugin = plugin; +#ifdef WIN32 + chkNew->setChecked(plugin->value("NewWindow").toBool()); + edtBrowser->hide(); + edtMailer->hide(); + lblBrowser->hide(); + lblMailer->hide(); +#else + edtBrowser->setText(plugin->value("Browser").toString()); + edtMailer->setText(plugin->value("Mailer").toString()); + chkNew->hide(); +#endif +#ifdef USE_KDE + connect(chkKDE, SIGNAL(toggled(bool)), SLOT(useKDEtoggled(bool))); + chkKDE->setChecked(plugin->getUseKDE()); +#else + chkKDE->hide(); +#endif +} + +void NavCfg::apply() +{ +#ifdef WIN32 + m_plugin->setValue("NewWindow", chkNew->isChecked()); +#else + m_plugin->setValue("Browser", edtBrowser->text()); + m_plugin->setValue("Mailer", edtMailer->text()); +#endif +#ifdef USE_KDE + m_plugin->setUseKDE(chkKDE->isChecked()); +#endif +} + +void NavCfg::useKDEtoggled(bool on) +{ + bool off = !on; +#ifdef USE_KDE + edtBrowser->setEnabled(off); + edtMailer->setEnabled(off); + lblBrowser->setEnabled(off); + lblMailer->setEnabled(off); +#endif + off=false; +} + diff --git a/plugins/navigate/navcfg.h b/plugins/navigate/navcfg.h new file mode 100644 index 0000000..f57fa4c --- /dev/null +++ b/plugins/navigate/navcfg.h @@ -0,0 +1,39 @@ +/*************************************************************************** + navcfg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _NAVCFG_H +#define _NAVCFG_H + +#include "ui_navcfgbase.h" + +class NavigatePlugin; + +class NavCfg : public QWidget, public Ui::NavCfgBase +{ + Q_OBJECT +public: + NavCfg(QWidget *w, NavigatePlugin *plugin); +public slots: + void apply(); +protected: + NavigatePlugin *m_plugin; +protected slots: + void useKDEtoggled(bool on); +}; + +#endif + diff --git a/plugins/navigate/navcfgbase.ui b/plugins/navigate/navcfgbase.ui new file mode 100644 index 0000000..621b911 --- /dev/null +++ b/plugins/navigate/navcfgbase.ui @@ -0,0 +1,108 @@ + + + + + NavCfgBase + + + + 0 + 0 + 278 + 192 + + + + Form1 + + + + 11 + + + 6 + + + + + Use KDE settings + + + + + + + Browser: + + + false + + + + + + + + + + Mailer: + + + false + + + + + + + + + + Open links in &new window (Win32: When unchecked, Explorer is used, else your installed default programs.) + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Vertical + + + + + + + + QWidget + QWidget +
QWidget
+ + -1 + -1 + + 0 + + 5 + 5 + + image0 + + text + +
+
+ + + 789c6dd2c10ac2300c00d07bbf2234b7229d1be245fc04c5a3201e4615f430059d0711ff5ddb2e6bb236ec90eed134cb5a19d8ef36602af5ecdbfeeac05dda0798d3abebde87e3faa374d3807fa0d633a52d38d8de6f679fe33fc776e196f53cd010188256a3600a292882096246517815ca99884606e18044a3a40d91824820924265a7923a2e8bcd05f33db1173e002913175f2a6be6d3294871a2d95fa00e8a94ee017b69d339d90df1e77c57ea072ede6758 + + +
diff --git a/plugins/navigate/navigate.cpp b/plugins/navigate/navigate.cpp new file mode 100644 index 0000000..0e6936a --- /dev/null +++ b/plugins/navigate/navigate.cpp @@ -0,0 +1,623 @@ +/*************************************************************************** + navigate.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +#include +#include +#include + +#include "navigate.h" +#include "navcfg.h" +#include "log.h" +#include "core.h" +#include "core_consts.h" + +#include "profile.h" +#include "profilemanager.h" + +#include "contacts/contact.h" + +#ifdef USE_KDE + #include +#endif + +#ifndef WIN32 + #include + #include +#endif + +using namespace std; +using namespace SIM; + +#ifdef WIN32 +#include +#include + +class DDEbase +{ +public: + DDEbase(); + ~DDEbase(); + operator DWORD() { return m_idDDE; } + static DDEbase *base; +protected: + DWORD m_idDDE; + static HDDEDATA CALLBACK DDECallback(UINT, UINT, HCONV, HSZ, HSZ, HDDEDATA, DWORD, DWORD); +}; + +DDEbase *DDEbase::base = NULL; + +DDEbase::DDEbase() +{ + m_idDDE = 0; + FARPROC lpDdeProc = MakeProcInstance((FARPROC) DDECallback, hInstance); + DdeInitialize((LPDWORD) &m_idDDE, (PFNCALLBACK) lpDdeProc, APPCMD_CLIENTONLY, 0L); + base = this; +} + +DDEbase::~DDEbase() +{ + base = NULL; + if (m_idDDE) + DdeUninitialize(m_idDDE); +} + +HDDEDATA CALLBACK DDEbase::DDECallback(UINT, UINT, HCONV, HSZ, HSZ, HDDEDATA, DWORD, DWORD) +{ + return NULL; +} + +class DDEstring +{ +public: + DDEstring(const QString &name); + ~DDEstring(); + operator HSZ() { return hSz; } +protected: + HSZ hSz; +}; + +DDEstring::DDEstring(const QString &name) : hSz(NULL) +{ + hSz = DdeCreateStringHandle(*DDEbase::base, (WCHAR*)name.utf16(), CP_WINUNICODE); +} + +DDEstring::~DDEstring() +{ + if (hSz) + DdeFreeStringHandle(*DDEbase::base, hSz); +} + +class DDEdataHandle +{ +public: + DDEdataHandle(const char *text); + DDEdataHandle(HDDEDATA data); + ~DDEdataHandle(); + operator HDDEDATA() { return hData; } + operator const char *(); +protected: + HDDEDATA hData; +}; + +DDEdataHandle::DDEdataHandle(const char *text) +{ + hData = DdeCreateDataHandle(*DDEbase::base, (unsigned char*)text, strlen(text) + 1, 0, NULL, CF_TEXT, 0); +} + +DDEdataHandle::DDEdataHandle(HDDEDATA data) +{ + hData = data; +} + +DDEdataHandle::~DDEdataHandle() +{ + if (hData) DdeFreeDataHandle(hData); +} + +DDEdataHandle::operator const char*() +{ + if (hData == NULL) + return NULL; + return (const char*)DdeAccessData(hData, NULL); +} + +class DDEconversation +{ +protected: + HCONV hConv; +public: + DDEconversation(const QString &_server, const QString &_topic); + ~DDEconversation(); + operator HCONV() { return hConv; } + HDDEDATA Execute(const QString &cmd); +}; + +DDEconversation::DDEconversation(const QString &_server, const QString &_topic) + : hConv(NULL) +{ + DDEstring server(_server); + DDEstring topic(_topic); + hConv = DdeConnect(*DDEbase::base, server, topic, NULL); +} + +DDEconversation::~DDEconversation() +{ + if (hConv) + DdeDisconnect(hConv); +} + +HDDEDATA DDEconversation::Execute(const QString &cmd) +{ + if (hConv == NULL) + return NULL; + DDEstring c(cmd); + DWORD res = 0; + HDDEDATA hData = DdeClientTransaction(NULL, 0, hConv, c, CF_TEXT, XTYP_REQUEST, 30000, &res); + if (hData == NULL) + DdeGetLastError((DWORD)DDEbase::base); + return hData; +} + +class RegEntry +{ +public: + RegEntry(HKEY hRootKey, const QString &path); + ~RegEntry(); + operator HKEY() { return hKey; } + QString value(const QString &key); +protected: + HKEY hKey; +}; + +QString getCurrentUrl() +{ + RegEntry r(HKEY_CLASSES_ROOT, "HTTP\\Shell\\open\\ddeexec\\application"); + QString topic = r.value(""); + if (topic.isEmpty()) + return QString::null; + + DDEbase b; + DDEconversation conv(topic, "WWW_GetWindowInfo"); + DDEdataHandle answer(conv.Execute("-1")); + const char *url = answer; + return url; +} + +RegEntry::RegEntry(HKEY hRootKey, const QString &path) +{ + if (RegOpenKey(hRootKey, (LPCWSTR)path.utf16(), &hKey) != ERROR_SUCCESS) + hKey = NULL; +} + +RegEntry::~RegEntry() +{ + if (hKey) + RegCloseKey(hKey); +} + +QString RegEntry::value(const QString &key) +{ + if (hKey == NULL) + return QString::null; + long size = 0; + if (RegQueryValue(hKey, (LPCWSTR)key.utf16(), NULL, &size) != ERROR_SUCCESS) + return QString::null; + QVarLengthArray ba(size + 1); + if (RegQueryValue(hKey, (LPCWSTR)key.utf16(), (LPWSTR)ba.data(), &size) != ERROR_SUCCESS) + return QString(); + return QString::fromUtf16(ba.constData()); +} + +#endif + +#ifdef __OS2__ + +static char browserExe[ CCHMAXPATH ] = ""; + +static char *detectBrowser() +{ + char *prfApp = "WPURLDEFAULTSETTINGS"; + + if ( browserExe[0] == 0 ) { + PrfQueryProfileString( HINI_USER, prfApp, "DefaultBrowserExe", "", + browserExe, CCHMAXPATH ); + } + + if ( browserExe[0] == 0 ) + { + APIRET rc; + rc = DosSearchPath( SEARCH_CUR_DIRECTORY | SEARCH_ENVIRONMENT | SEARCH_IGNORENETERRS, + "PATH", "NETSCAPE.EXE", browserExe, CCHMAXPATH ); + if ( rc != 0 ) { + strcpy( browserExe , "" ); + } + } + + return browserExe; +} + +// Starts the browser, returns 1 if started, 0 otherwise. +int startBrowser( const char *browser, const char *url ) +{ + PROGDETAILS pd = { 0 }; + HAPP happ = NULL; + + if ( url == NULL ) { + return 0; + } + if ( browser == NULL ) { + return 0; + } + if ( browser[0] == 0 ) { + return 0; + } + + log(L_WARN, "Strarting '%s', url '%s'", browser, url ); + + char startupDir[ CCHMAXPATH ]; + strcpy( startupDir, browser ); + char *slash = strrchr( startupDir, '\\' ); + if ( slash != NULL ) { + *slash = 0; + } + + pd.Length = sizeof( PROGDETAILS ); + pd.progt.progc = PROG_DEFAULT; + pd.progt.fbVisible = SHE_VISIBLE; + pd.pszTitle = NULL; + pd.pszExecutable = (char *)browser; + pd.pszParameters = NULL; + pd.pszStartupDir = startupDir; + pd.pszIcon = NULL; + pd.pszEnvironment = NULL; + pd.swpInitial.fl = SWP_ACTIVATE; + pd.swpInitial.cy = 0; + pd.swpInitial.cx = 0; + pd.swpInitial.y = 0; + pd.swpInitial.x = 0; + pd.swpInitial.hwndInsertBehind = HWND_TOP; + pd.swpInitial.hwnd = NULLHANDLE; + pd.swpInitial.ulReserved1 = 0; + pd.swpInitial.ulReserved2 = 0; + happ = WinStartApp( NULLHANDLE, &pd, url, NULL, 0 ); + if ( happ == NULL ) { + log(L_ERROR, "Can't start '%s', error 0x%X", browser, WinGetLastError(0) ); + } + return ( happ != NULL ); +} + +#endif + +Plugin *createNavigatePlugin(unsigned base, bool, Buffer *config) +{ + Plugin *plugin = new NavigatePlugin(base, config); + return plugin; +} + +static PluginInfo info = + { + I18N_NOOP("Navigate"), + I18N_NOOP("Plugin provides navigation on hyperlinks, call an external browser and mailer"), + VERSION, + createNavigatePlugin, + PLUGIN_DEFAULT + }; + +EXPORT_PROC PluginInfo* GetPluginInfo() +{ + return &info; +} + + +NavigatePlugin::NavigatePlugin(unsigned base, Buffer *config) + : QObject(), Plugin(base) +{ + m_propertyHub = SIM::PropertyHub::create("navigate"); + CmdMail = registerType(); + CmdMailList = registerType(); + MenuMail = registerType(); + CmdCopyLocation = registerType(); + + EventMenu(MenuMail, EventMenu::eAdd).process(); + + Command cmd; + cmd->id = CmdMail; + cmd->text = I18N_NOOP("Send mail"); + cmd->icon = "mail_generic"; + cmd->menu_id = MenuContact; + cmd->menu_grp = 0x30F0; + cmd->popup_id = 0; + cmd->flags = COMMAND_DEFAULT; + EventCommandCreate(cmd).process(); + + cmd->id = CmdMailList; + cmd->text = "_"; + cmd->menu_grp = 0x1000; + cmd->menu_id = MenuMail; + EventCommandCreate(cmd).process(); + + cmd->id = CmdCopyLocation; + cmd->text = I18N_NOOP("Copy &location"); + cmd->icon = QString::null; + cmd->menu_id = MenuTextEdit; + cmd->menu_grp = 0x7010; + cmd->menu_id = MenuMsgView; + EventCommandCreate(cmd).process(); + + + //EventCommandCreate(cmd).process(); +} + +NavigatePlugin::~NavigatePlugin() +{ + EventCommandRemove(CmdMail).process(); + EventMenu(MenuMail, EventMenu::eRemove).process(); + +} + +bool NavigatePlugin::processEvent(Event *e) +{ +#ifdef WIN32 + if (e->type() == eEventGetURL){ + EventGetURL *u = static_cast(e); + u->setUrl(getCurrentUrl()); + return true; + } +#endif + if (e->type() == eEventGoURL){ + EventGoURL *u = static_cast(e); + QString url = u->url(); + QString proto; + if (url.length() == 0) + return false; + int n = url.indexOf(':'); + if (n < 0) + return false; + proto = url.left(n); + if ((proto != "http") && + (proto != "https") && + (proto != "ftp") && + (proto != "file") && + (proto != "mailto") && + (proto != "file")) + return false; +#ifdef WIN32 + bool bExec = false; + if (value("NewWindow").toBool()){ + QString key_name = proto + "\\Shell\\Open"; + RegEntry rp(HKEY_CLASSES_ROOT, key_name); + QString prg = rp.value("command"); + QString action = rp.value("ddeexec"); + QString topic = rp.value("ddeexec\\Topic"); + QString server = rp.value("ddeexec\\Application"); + + int pos = action.indexOf("%l"); + if (!action.isEmpty() && pos >= 0) + action = action.left(pos) + url + action.mid(pos + 2); + + //prg=prg.replace("\%l","\%1"); + if (proto=="file") { + pos = prg.indexOf("%l"); + if (pos >= 0) + prg = prg.left(pos) + url + prg.mid(pos + 2); + } + else + prg = QString(prg).arg(url); + + if (!prg.isEmpty()){ + STARTUPINFO si; + PROCESS_INFORMATION pi; + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + ZeroMemory(&pi, sizeof(pi)); + if (CreateProcess(NULL, (LPWSTR)prg.utf16(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)){ + WaitForInputIdle(pi.hProcess, INFINITE); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + bExec = true; + } + } + if(!bExec) { + DDEbase b; + DDEconversation conv(server, topic); + if (conv.Execute(action)) + bExec = true; + } + } + if (!bExec) + { + if (proto == "file") + url = url.mid(5); + //ShellExecuteA(NULL, NULL, url.data(), NULL, NULL, SW_SHOWNORMAL); //Fixme: Bug, does not work + QString program = "explorer"; + QStringList arguments; + arguments << url; + + QProcess *openPathInExplorer = new QProcess(this); + openPathInExplorer->start(program, arguments); + + //QProcess openPathInExplorer; + //QString path(url); + //path.replace("%20", " "); + + /*openPathInExplorer .addArgument("explorer"); + openPathInExplorer.addArgument(path); + if (openPathInExplorer.start()) + qDebug() << i18n("Explorer started for Path"); + else + qDebug() << i18n("ERR: Explorer started for Path FAILED!"); */ + } +#else +#ifdef USE_KDE + if (getUseKDE()) + { + if (proto == "mailto") + kapp->invokeMailer(QString(url.mid(proto.length() + 1)), QString::null); + else + kapp->invokeBrowser(url); + return true; + } +#endif // USE_KDE +#ifdef __OS2__ + startBrowser( (proto == "mailto") ? value("Mailer") : value("Browser").toString(), url ); +#else + QString param; + if (proto == "mailto"){ + param = value("Mailer").toString(); + url = url.mid(proto.length() + 1); + }else{ + param = value("Browser").toString(); + QUrl qurl(url); + QString encodedUrl = qurl.toString(); + url = encodedUrl; + } + QStringList ul; + ul.append(url); + EventExec(param, ul).process(); +#endif +#endif // WIN32 + return true; + } else + if (e->type() == eEventAddHyperlinks){ + EventAddHyperlinks *h = static_cast(e); + h->setText(parseUrl(h->text())); + return true; + } else + if (e->type() == eEventCheckCommandState){ + EventCheckCommandState *ecs = static_cast(e); + CommandDef *cmd = ecs->cmd(); + if (cmd->id == CmdMail){ + Contact *contact = getContacts()->contact((unsigned long)(cmd->param)); + if (contact == NULL) + return false; + QString mails = contact->getEMails(); + if (mails.length() == 0) + return false; + int nMails = 0; + while (mails.length()){ + getToken(mails, ';'); + nMails++; + } + cmd->popup_id = (nMails <= 1) ? 0 : MenuMail; + return true; + } + if (cmd->id == CmdMailList){ + Contact *contact = getContacts()->contact((unsigned long)(cmd->param)); + if (contact == NULL) + return false; + QString mails = contact->getEMails(); + if (mails.length() == 0) + return false; + int nMails = 0; + while (mails.length()){ + getToken(mails, ';'); + nMails++; + } + CommandDef *cmds = new CommandDef[nMails + 1]; + unsigned n = 0; + mails = contact->getEMails(); + while (mails.length()){ + QString mail = getToken(mails, ';', false); + mail = getToken(mail, '/'); + cmds[n] = *cmd; + cmds[n].id = CmdMailList + n; + cmds[n].flags = COMMAND_DEFAULT; + cmds[n].text_wrk = mail; + n++; + } + cmds[n].clear(); + cmd->param = cmds; + cmd->flags |= COMMAND_RECURSIVE; + return true; + } + } else + if (e->type() == eEventCommandExec){ + EventCommandExec *ece = static_cast(e); + CommandDef *cmd = ece->cmd(); + if (cmd->id == CmdMail){ + QString mail; + Contact *contact = getContacts()->contact((unsigned long)(cmd->param)); + if (contact) + mail = contact->getEMails(); + mail = getToken(mail, ';', false); + mail = getToken(mail, '/'); + if (mail.length()){ + QString addr = "mailto:" + mail; + EventGoURL eMail(addr); + eMail.process(); + } + return true; + } + if (cmd->menu_id == MenuMail){ + unsigned n = cmd->id - CmdMailList; + QString mails; + Contact *contact = getContacts()->contact((unsigned long)(cmd->param)); + if (contact) + mails = contact->getEMails(); + while (mails.length()){ + QString mail = getToken(mails, ';', false); + if (n-- == 0){ + mail = getToken(mail, '/'); + if (mail.length()){ + QString addr = "mailto:" + mail; + EventGoURL(addr).process(); + } + break; + } + } + return true; + } + } + if(e->type() == eEventPluginLoadConfig) + { + PropertyHubPtr hub = ProfileManager::instance()->getPropertyHub("navigate"); + if(!hub.isNull()) + setPropertyHub(hub); + // TODO defaults + } + return false; +} + +QByteArray NavigatePlugin::getConfig() +{ + return QByteArray();//Fixme +} + +QWidget *NavigatePlugin::createConfigWindow(QWidget *parent) +{ + return new NavCfg(parent, this); +} + + +void NavigatePlugin::setPropertyHub(SIM::PropertyHubPtr hub) +{ + m_propertyHub = hub; +} + +SIM::PropertyHubPtr NavigatePlugin::propertyHub() +{ + return m_propertyHub; +} + +QVariant NavigatePlugin::value(const QString& key) +{ + return m_propertyHub->value(key); +} + +void NavigatePlugin::setValue(const QString& key, const QVariant& v) +{ + m_propertyHub->setValue(key, v); +} diff --git a/plugins/navigate/navigate.h b/plugins/navigate/navigate.h new file mode 100644 index 0000000..363bfed --- /dev/null +++ b/plugins/navigate/navigate.h @@ -0,0 +1,54 @@ +/*************************************************************************** + navigate.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _NAVIGATE_H +#define _NAVIGATE_H + +#include "simapi.h" + +#include "cfg.h" +#include "event.h" +#include "plugins.h" +#include "propertyhub.h" +#include + + +class NavigatePlugin : public QObject, public SIM::Plugin, public SIM::EventReceiver +{ +public: + NavigatePlugin(unsigned, Buffer *name); + virtual ~NavigatePlugin(); + void setPropertyHub(SIM::PropertyHubPtr hub); + SIM::PropertyHubPtr propertyHub(); + QVariant value(const QString& key); + void setValue(const QString& key, const QVariant& v); +protected: + virtual bool processEvent(SIM::Event *e); + QString parseUrl(const QString &text); + unsigned long CmdMail; + unsigned long CmdMailList; + unsigned long CmdCopyLocation; + unsigned long MenuMail; + virtual QByteArray getConfig(); + virtual QWidget *createConfigWindow(QWidget *parent); + friend class NavCfg; +private: + SIM::PropertyHubPtr m_propertyHub; +}; + +#endif + diff --git a/plugins/navigate/navigate.rc b/plugins/navigate/navigate.rc new file mode 100644 index 0000000..3209c06 --- /dev/null +++ b/plugins/navigate/navigate.rc @@ -0,0 +1,97 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,9,6,0 + PRODUCTVERSION 0,9,6,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Vladimir Shutoff\0" + VALUE "FileDescription", "Navigate plugin\0" + VALUE "FileVersion", "0, 9, 6, 0\0" + VALUE "InternalName", "navigate\0" + VALUE "LegalCopyright", "Copyright © 2002-2003\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "navigate.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "SIM\0" + VALUE "ProductVersion", "0, 9, 6, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/navigate/navigate.vcproj b/plugins/navigate/navigate.vcproj new file mode 100644 index 0000000..22b6d18 --- /dev/null +++ b/plugins/navigate/navigate.vcproj @@ -0,0 +1,416 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/navigate/parseurl.ll b/plugins/navigate/parseurl.ll new file mode 100644 index 0000000..70ff59a --- /dev/null +++ b/plugins/navigate/parseurl.ll @@ -0,0 +1,114 @@ +%{ +/*************************************************************************** + parse.ll - description + ------------------- + begin : Sun Mar 10 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "unquot.h" + +#include "navigate.h" +//Added by qt3to4: +#include + +#define TXT 1 +#define URL 2 +#define MAIL_URL 3 +#define HTTP_URL 4 +#define FTP_URL 5 + +#define YY_NEVER_INTERACTIVE 1 +#define YY_ALWAYS_INTERACTIVE 0 +#define YY_MAIN 0 + +%} + +%option nounput +%option nostack +%option prefix="parseurl" + +%x x_tag +%x x_word +%x x_link +%% + +(http|https|ftp)"://"[A-Za-z0-9/\,\.\?\@\&:\;\(\)\-_\+\'\%=~\#]+ { return URL; } +"file:///"[A-Za-z0-9/\,\.\?\@\&:\;\(\)\-_\+\'\%=\\~\#]+ { return URL; } +(mailto:)?[A-Za-z0-9\-_][A-Za-z0-9\-_\.]*\@([A-Za-z0-9\-]+\.)+[A-Za-z]+ { return MAIL_URL; } +"www."[A-Za-z0-9/\,\.\?\&:\;\(\)\-_\+\%=~\#\']+ { return HTTP_URL; } +"ftp."[A-Za-z0-9/\,\.:\;\-_\+~\']+ { return FTP_URL; } +""" { BEGIN(INITIAL); return TXT; } +"&" { BEGIN(INITIAL); return TXT; } +"<" { BEGIN(INITIAL); return TXT; } +">" { BEGIN(INITIAL); return TXT; } +"\t" { BEGIN(INITIAL); return TXT; } +" " { BEGIN(INITIAL); return TXT; } +[\:\.\,\ \(\)] { BEGIN(INITIAL); return TXT; } +"" { BEGIN(x_link); return TXT; } +"<" { BEGIN(x_tag); return TXT; } +">" { BEGIN(INITIAL); return TXT; } +. { return TXT; } +"" { BEGIN(INITIAL); return TXT; } +. { return TXT; } +[\xC0-\xDF][\x80-\xBF] { BEGIN(x_word); return TXT; } +[\xE0-\xEF][\x00-\xFF]{2} { BEGIN(x_word); return TXT; } +[\xF0-\xF7][\x00-\xFF]{3} { BEGIN(x_word); return TXT; } +[\xF8-\xFB][\x00-\xFF]{4} { BEGIN(x_word); return TXT; } +[\xFC-\xFD][\x00-\xFF]{5} { BEGIN(x_word); return TXT; } +"\n" { BEGIN(INITIAL); return TXT; } +. { BEGIN(x_word); return TXT; } +%% + +int yywrap() { return 1; } + +QString NavigatePlugin::parseUrl(const QString &text) +{ + QByteArray str = text.toUtf8(); + YY_BUFFER_STATE yy_current_buffer = yy_scan_string(str); + yy_start = 1; /* == BEGIN(INITIAL) - go to initial state since yy_start + is static and can have an old invalid value */ + QString res; + int r; + while ((r = yylex())) {; + if (r == TXT){ + res += QString::fromUtf8(yytext); + continue; + } + QString url = yytext; + QString link = SIM::unquoteString(QString::fromUtf8(yytext)); + switch (r){ + case MAIL_URL: + if (link.left(7) != "mailto:") + link = QString("mailto:") + link; + break; + case HTTP_URL: + link = QString("http://") + link; + break; + case FTP_URL: + link = QString("ftp://") + link; + break; + } + res += ""; + res += url; + res += ""; + }; + yy_delete_buffer(yy_current_buffer); + return res; +} + + + + diff --git a/plugins/netmonitor/CMakeLists.txt b/plugins/netmonitor/CMakeLists.txt new file mode 100644 index 0000000..09306ce --- /dev/null +++ b/plugins/netmonitor/CMakeLists.txt @@ -0,0 +1,21 @@ +###################### +# netmonitor library # +###################### +IF(BUILD_DROPPED) +PROJECT(netmonitor) + +SET(netmonitor_SRCS + monitor.cpp + netmonitor.cpp +) + +SET(netmonitor_HDRS + monitor.h + netmonitor.h +) + +REMOVE_DEFINITIONS(-DQT3_SUPPORT) +REMOVE_DEFINITIONS(-DQT_3SUPPORT_LIB) +REMOVE_DEFINITIONS(-DQT3_SUPPORT_WARNINGS) +SIM_ADD_PLUGIN(netmonitor) +ENDIF(BUILD_DROPPED) diff --git a/plugins/netmonitor/monitor.cpp b/plugins/netmonitor/monitor.cpp new file mode 100644 index 0000000..392505b --- /dev/null +++ b/plugins/netmonitor/monitor.cpp @@ -0,0 +1,279 @@ +/*************************************************************************** + monitor.cpp - description + ------------------- + begin : Sun Mar 24 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "simapi.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "icons.h" +#include "log.h" +#include "misc.h" +#include "unquot.h" + +#include "monitor.h" +#include "netmonitor.h" + +using namespace SIM; + +MonitorWindow *monitor = NULL; + +MonitorWindow::MonitorWindow(NetmonitorPlugin *plugin) + : QMainWindow(NULL, Qt::Window) + , m_plugin(plugin) +{ + bPause = true; // no debug output during creation + SET_WNDPROC("monitor") + setWindowTitle(i18n("Network monitor")); + setWindowIcon(Icon("network")); + + edit = new QTextEdit(this); + edit->setLineWrapMode(QTextEdit::NoWrap); + edit->setReadOnly(true); + setCentralWidget(edit); + QMenuBar *menu = menuBar(); + + QMenu *menuFile = new QMenu(i18n("&File"), menu); + connect(menuFile, SIGNAL(aboutToShow()), this, SLOT(adjustFile())); + m_saveAction = menuFile->addAction(Icon("filesave"), i18n("&Save"), this, SLOT(save())); + menuFile->addSeparator(); + m_autoscrollAction = menuFile->addAction(i18n("&Autoscroll"), this, SLOT(toggleAutoscroll())); + m_autoscrollAction->setCheckable(true); + m_pauseAction = menuFile->addAction(i18n("&Pause"), this, SLOT(pause())); + menuFile->addSeparator(); + menuFile->addAction(Icon("exit"), i18n("E&xit"), this, SLOT(exit())); + menu->addMenu(menuFile); + + QMenu *menuEdit = new QMenu(i18n("&Edit"), menu); + connect(menuEdit, SIGNAL(aboutToShow()), this, SLOT(adjustEdit())); + m_copyAction = menuEdit->addAction(i18n("&Copy"), this, SLOT(copy())); + m_eraseAction = menuEdit->addAction(i18n("&Erase"), this, SLOT(erase())); + menu->addMenu(menuEdit); + + m_menuLog = new QMenu(i18n("&Log"), menu); + connect(m_menuLog, SIGNAL(aboutToShow()), this, SLOT(adjustLog())); + connect(m_menuLog, SIGNAL(triggered(QAction*)), this, SLOT(toggleType(QAction*))); + menu->addMenu(m_menuLog); + + bPause = false; + bAutoscroll = true; + edit->append( "
" );
+}
+
+void MonitorWindow::closeEvent(QCloseEvent *e)
+{
+    QMainWindow::closeEvent(e);
+    emit finished();
+}
+
+void MonitorWindow::save()
+{
+    QString s = QFileDialog::getSaveFileName (this, QString(), QString(), "sim.log");
+    if (s.isEmpty())
+        return;
+    QFile f(s);
+    if (!f.open(QIODevice::WriteOnly)){
+        QMessageBox::warning(this, i18n("Error"), i18n("Can't create file %1") .arg(s));
+        return;
+    }
+    QTextStream ts(&f);
+    QString t;
+    if (edit->textCursor().hasSelection()){
+        t = unquoteText(edit->textCursor().selectedText());
+    }else{
+        t = unquoteText(edit->toPlainText());
+    }
+#if defined(WIN32) || defined(__OS2__)
+    t.replace('\n',"\r\n");
+#endif
+    ts << t;
+    f.close();
+}
+
+void MonitorWindow::exit()
+{
+    close();
+}
+
+void MonitorWindow::adjustFile()
+{
+    m_saveAction->setEnabled(edit->textCursor().hasSelection());
+    m_pauseAction->setText(bPause ? i18n("&Resume") : i18n("&Pause"));
+    m_autoscrollAction->setChecked(bAutoscroll);
+}
+
+void MonitorWindow::copy()
+{
+    edit->copy();
+}
+
+void MonitorWindow::erase()
+{
+    edit->clear();
+}
+
+void MonitorWindow::adjustEdit()
+{
+    m_copyAction->setEnabled(edit->textCursor().hasSelection());
+    m_eraseAction->setEnabled(!edit->textCursor().hasSelection());
+}
+
+void MonitorWindow::toggleType(QAction *a)
+{
+    int id = a->data().toInt();
+    switch (id){
+    case L_DEBUG:
+    case L_WARN:
+    case L_ERROR:
+    case L_PACKETS:
+        m_plugin->setValue("LogLevel", m_plugin->value("LogLevel").toUInt() ^ id);
+        return;
+    }
+    m_plugin->setLogType(id, !m_plugin->isLogType(id));
+}
+
+void MonitorWindow::toggleAutoscroll()
+{
+    bAutoscroll = !bAutoscroll;
+}
+
+void MonitorWindow::pause()
+{
+    bPause = !bPause;
+}
+
+struct level_def
+{
+    unsigned	level;
+    const char	*name;
+};
+
+static level_def levels[] =
+    {
+        { L_DEBUG, I18N_NOOP("&Debug") },
+        { L_WARN, I18N_NOOP("&Warnings") },
+        { L_ERROR, I18N_NOOP("&Errors") },
+        { L_PACKETS, I18N_NOOP("&Packets") },
+        { 0, NULL }
+    };
+
+void MonitorWindow::adjustLog()
+{
+    m_menuLog->clear();
+    PacketType *packet;
+    ContactList::PacketIterator it;
+    while ((packet = ++it) != NULL){
+        QAction *a = m_menuLog->addAction(i18n(packet->name()));
+        a->setCheckable(true);
+        a->setChecked(m_plugin->isLogType(packet->id()));
+        a->setData(packet->id());
+    }
+    m_menuLog->addSeparator();
+    for (const level_def *d = levels; d->name; d++){
+        QAction *a = m_menuLog->addAction(i18n(d->name));
+        a->setCheckable(true);
+        a->setChecked((m_plugin->value("LogLevel").toUInt() & d->level) != 0);
+        a->setData(d->level);
+    }
+}
+
+struct LevelColorDef
+{
+    unsigned	level;
+    const char	*color;
+};
+
+static LevelColorDef levelColors[] =
+    {
+        { L_DEBUG,	"008000" },
+        { L_WARN,	"808000" },
+        { L_ERROR,	"800000" },
+        { L_PACKET_IN,	"000080" },
+        { L_PACKET_OUT, "000000" },
+        { 0,		 NULL 	 }
+    };
+
+bool MonitorWindow::processEvent(Event *e)
+{
+    if (!e) {
+        return false;
+    }
+
+	EventLog *l = static_cast(e);
+
+    if (e->type() == eEventLog && !bPause &&
+			(
+                        ((l->packetID() == 0 && (l->logLevel() & m_plugin->value("LogLevel").toUInt())) ||
+                        ( l->packetID()      && ((m_plugin->value("LogLevel").toUInt() & L_PACKETS) || m_plugin->isLogType(l->packetID()))))
+			)
+		)
+	{
+
+		const char *font = NULL;
+        for (const LevelColorDef *d = levelColors; d->color; d++)
+			if (l->logLevel() == d->level){
+				font = d->color;
+				break;
+			}
+		
+        QString logString;
+		if (font)
+			logString += QString("") .arg(font);
+		QString s = EventLog::make_packet_string(*l);
+		logString += quoteString(s);
+		if (font)
+			logString += QString("");
+		QMutexLocker lock(&m_mutex);
+		m_logStrings += logString;
+		QTimer::singleShot(10, this, SLOT(outputLog()));
+    }
+    return false;
+}
+
+void MonitorWindow::outputLog()
+{
+    if(m_logStrings.isEmpty())
+        return;
+    setLogEnable(false);
+
+    QMutexLocker lock(&m_mutex);
+
+    for(int i = 0; i < m_logStrings.count(); i++)
+        edit->append(m_logStrings[i]);
+
+    m_logStrings.clear();
+    if (bAutoscroll)
+    {
+        QScrollBar *sb = edit->verticalScrollBar();
+        if (NULL != sb)
+        {
+            sb->setValue(sb->maximum());
+        }
+    }
+    setLogEnable(true);
+}
+
diff --git a/plugins/netmonitor/monitor.h b/plugins/netmonitor/monitor.h
new file mode 100644
index 0000000..426b7f5
--- /dev/null
+++ b/plugins/netmonitor/monitor.h
@@ -0,0 +1,71 @@
+/***************************************************************************
+                          monitor.h  -  description
+                             -------------------
+    begin                : Sun Mar 17 2002
+    copyright            : (C) 2002 by Vladimir Shutoff
+    email                : vovan@shutoff.ru
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   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.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#ifndef _MONITOR_H
+#define _MONITOR_H
+
+#include 
+#include 
+
+#include "event.h"
+
+class QAction;
+class QMenu;
+class QTextEdit;
+class NetmonitorPlugin;
+
+const unsigned short L_PACKETS = 0x08;
+
+class MonitorWindow : public QMainWindow, public SIM::EventReceiver
+{
+    Q_OBJECT
+public:
+    MonitorWindow(NetmonitorPlugin*);
+signals:
+    void finished();
+protected slots:
+    void save();
+    void exit();
+    void copy();
+    void erase();
+    void pause();
+    void toggleType(QAction*);
+    void toggleAutoscroll();
+    void adjustFile();
+    void adjustEdit();
+    void adjustLog();
+protected:
+    virtual bool processEvent(SIM::Event *e);
+    void closeEvent(QCloseEvent*);
+    bool bPause;
+    bool bAutoscroll;
+    QTextEdit  *edit;
+    QAction *m_saveAction;
+    QAction *m_autoscrollAction;
+    QAction *m_pauseAction;
+    QAction *m_copyAction;
+    QAction *m_eraseAction;
+    QMenu *m_menuLog;
+    NetmonitorPlugin *m_plugin;
+    QMutex m_mutex;
+    QStringList m_logStrings;
+protected slots:
+    void outputLog();
+};
+
+#endif
+
diff --git a/plugins/netmonitor/netmonitor.cpp b/plugins/netmonitor/netmonitor.cpp
new file mode 100644
index 0000000..cdbf910
--- /dev/null
+++ b/plugins/netmonitor/netmonitor.cpp
@@ -0,0 +1,198 @@
+/***************************************************************************
+  netmonitor.cpp  -  description
+  -------------------
+begin                : Sun Mar 17 2002
+copyright            : (C) 2002 by Vladimir Shutoff
+email                : vovan@shutoff.ru
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   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.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#include 
+#include 
+
+#include "misc.h"
+#include "core_consts.h"
+
+#include "profile.h"
+#include "profilemanager.h"
+
+#include "netmonitor.h"
+#include "monitor.h"
+
+using namespace std;
+using namespace SIM;
+
+Plugin *createNetmonitorPlugin(unsigned base, bool, Buffer *config)
+{
+    Plugin *plugin = new NetmonitorPlugin(base, config);
+    return plugin;
+}
+
+static PluginInfo info =
+{
+    I18N_NOOP("Network monitor"),
+    I18N_NOOP("Plugin provides monitoring of net and messages\n"
+            "For show monitor on start run sim -m"),
+    VERSION,
+    createNetmonitorPlugin,
+    PLUGIN_DEFAULT
+};
+
+EXPORT_PROC PluginInfo* GetPluginInfo()
+{
+    return &info;
+}
+
+//static DataDef monitorData[] =
+//{
+    //        { "LogLevel", DATA_ULONG, 1, DATA(7) },
+    //        { "LogPackets", DATA_STRING, 1, 0 },
+//    { "Geometry", DATA_LONG, 5, DATA(-1) },
+//    { "Show", DATA_BOOL, 1, 0 },
+//    { NULL, DATA_UNKNOWN, 0, 0 }
+//};
+
+NetmonitorPlugin::NetmonitorPlugin(unsigned base, Buffer *config)
+    : QObject(), Plugin(base)
+    , monitor(NULL)
+{
+    m_propertyHub = SIM::PropertyHub::create("netmonitor");
+
+    const QStringList packets = value("LogPackets").toString().split(',');
+    Q_FOREACH( const QString &v, packets)
+        setLogType(v.toULong(), true);
+    
+    CmdNetMonitor = registerType();
+
+    Command cmd;
+    cmd->id          = CmdNetMonitor;
+    cmd->text        = I18N_NOOP("Network monitor");
+    cmd->icon        = "network";
+    cmd->bar_id      = ToolBarMain;
+    cmd->menu_id     = MenuMain;
+    cmd->menu_grp    = 0x8000;
+    cmd->flags		= COMMAND_DEFAULT;
+    EventCommandCreate(cmd).process();
+
+    EventArg e("-m", I18N_NOOP("Show network monitor"));
+    if (e.process() || value("Show").toBool())
+        showMonitor();
+}
+
+NetmonitorPlugin::~NetmonitorPlugin()
+{
+    saveState();
+    setValue("Show", monitor != NULL);
+    QString packets;
+    QSetIterator it(m_packets);
+    while (it.hasNext()) {
+        if (packets.length())
+            packets += ',';
+        packets += QString::number(it.next());
+    }
+    setValue("LogPackets", packets);
+    EventCommandRemove(CmdNetMonitor).process();
+
+    delete monitor;
+
+}
+
+QByteArray NetmonitorPlugin::getConfig()
+{
+    return QByteArray();
+}
+
+bool NetmonitorPlugin::isLogType(unsigned id)
+{
+    return ( m_packets.contains( id ) );
+}
+
+void NetmonitorPlugin::setLogType(unsigned id, bool bLog)
+{
+    if (bLog){
+        m_packets.insert(id);
+    }else{
+        m_packets.remove(id);
+    }
+}
+
+const unsigned NO_DATA = (unsigned)(-1);
+
+void NetmonitorPlugin::showMonitor()
+{
+    if (monitor == NULL)
+    {
+        monitor = new MonitorWindow(this);
+        //bool bPos = (data.geometry[LEFT].toLong() != NO_DATA) && (data.geometry[TOP].toLong() != NO_DATA);
+        //bool bSize = (data.geometry[WIDTH].toLong() != NO_DATA) && (data.geometry[HEIGHT].toLong() != NO_DATA);
+        //restoreGeometry(monitor, data.geometry, bPos, bSize);
+        connect(monitor, SIGNAL(finished()), this, SLOT(finished()));
+    }
+    raiseWindow(monitor);
+}
+
+bool NetmonitorPlugin::processEvent(Event *e)
+{
+    if (e->type() == eEventCommandExec){
+        EventCommandExec *ece = static_cast(e);
+        CommandDef *cmd = ece->cmd();
+        if (cmd->id == CmdNetMonitor){
+            showMonitor();
+            return true;
+        }
+    }
+    else if(e->type() == eEventPluginLoadConfig)
+    {
+        PropertyHubPtr hub = ProfileManager::instance()->getPropertyHub("netmonitor");
+        if(!hub.isNull())
+            setPropertyHub(hub);
+    }
+    return false;
+}
+
+void NetmonitorPlugin::finished()
+{
+    saveState();
+    QTimer::singleShot(0, this, SLOT(realFinished()));
+}
+
+void NetmonitorPlugin::realFinished()
+{
+    delete monitor; //Fixme: Crash
+    monitor = NULL;
+}
+
+void NetmonitorPlugin::saveState()
+{
+    if (monitor == NULL)
+        return;
+    //saveGeometry(monitor, data.geometry);
+}
+
+void NetmonitorPlugin::setPropertyHub(SIM::PropertyHubPtr hub)
+{
+	m_propertyHub = hub;
+}
+
+SIM::PropertyHubPtr NetmonitorPlugin::propertyHub()
+{
+	return m_propertyHub;
+}
+
+QVariant NetmonitorPlugin::value(const QString& key)
+{
+	return m_propertyHub->value(key);
+}
+
+void NetmonitorPlugin::setValue(const QString& key, const QVariant& v)
+{
+	m_propertyHub->setValue(key, v);
+}
diff --git a/plugins/netmonitor/netmonitor.h b/plugins/netmonitor/netmonitor.h
new file mode 100644
index 0000000..dde01e7
--- /dev/null
+++ b/plugins/netmonitor/netmonitor.h
@@ -0,0 +1,74 @@
+/***************************************************************************
+                          netmonitor.h  -  description
+                             -------------------
+    begin                : Sun Mar 17 2002
+    copyright            : (C) 2002 by Vladimir Shutoff
+    email                : vovan@shutoff.ru
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   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.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#ifndef _NETMONITOR_H
+#define _NETMONITOR_H
+
+#include 
+#include 
+
+#include "cfg.h"
+#include "event.h"
+#include "plugins.h"
+#include "propertyhub.h"
+
+struct NetMonitorData
+{
+//    SIM::Data	LogLevel;
+//    SIM::Data	LogPackets;
+//    SIM::Data	geometry[5];
+//    SIM::Data	Show;
+};
+
+class MonitorWindow;
+
+class NetmonitorPlugin : public QObject, public SIM::Plugin, public SIM::EventReceiver
+{
+    Q_OBJECT
+public:
+    NetmonitorPlugin(unsigned, Buffer *name);
+    virtual ~NetmonitorPlugin();
+//    PROP_ULONG(LogLevel);
+//    PROP_STR(LogPackets);
+//    PROP_BOOL(Show);
+    bool isLogType(unsigned id);
+    void setLogType(unsigned id, bool bLog);
+        
+    void setPropertyHub(SIM::PropertyHubPtr hub);
+    SIM::PropertyHubPtr propertyHub();
+    QVariant value(const QString& key);
+    void setValue(const QString& key, const QVariant& v);
+
+protected slots:
+    void finished();
+    void realFinished();
+
+protected:
+    virtual bool processEvent(SIM::Event *e);
+    virtual QByteArray getConfig();
+    void showMonitor();
+    void saveState();
+    unsigned long CmdNetMonitor;
+    QSet m_packets;
+    MonitorWindow *monitor;
+
+private:
+    SIM::PropertyHubPtr m_propertyHub;
+};
+
+#endif
+
diff --git a/plugins/netmonitor/netmonitor.vcproj b/plugins/netmonitor/netmonitor.vcproj
new file mode 100644
index 0000000..11eb244
--- /dev/null
+++ b/plugins/netmonitor/netmonitor.vcproj
@@ -0,0 +1,349 @@
+
+
+	
+		
+	
+	
+	
+	
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+	
+	
+	
+	
+		
+			
+				
+					
+				
+				
+					
+				
+			
+			
+				
+					
+				
+				
+					
+				
+			
+			
+				
+					
+				
+				
+					
+				
+			
+			
+				
+					
+				
+				
+					
+				
+			
+		
+		
+			
+				
+					
+				
+				
+					
+				
+			
+			
+				
+					
+				
+				
+					
+				
+			
+		
+	
+	
+	
+
diff --git a/plugins/ontop/CMakeLists.txt b/plugins/ontop/CMakeLists.txt
new file mode 100644
index 0000000..78fee32
--- /dev/null
+++ b/plugins/ontop/CMakeLists.txt
@@ -0,0 +1,23 @@
+#################
+# ontop library #
+#################
+IF(BUILD_DROPPED)
+SET(ontop_SRCS
+        ontop.cpp
+        ontopcfg.cpp
+)
+
+SET(ontop_HDRS
+        ontop.h
+        ontopcfg.h
+)
+
+SET(ontop_UICS
+        ontopcfgbase.ui
+)
+
+REMOVE_DEFINITIONS(-DQT3_SUPPORT)
+REMOVE_DEFINITIONS(-DQT_3SUPPORT_LIB)
+REMOVE_DEFINITIONS(-DQT3_SUPPORT_WARNINGS)
+SIM_ADD_PLUGIN(ontop)
+ENDIF(BUILD_DROPPED)
diff --git a/plugins/ontop/configure.in.in b/plugins/ontop/configure.in.in
new file mode 100644
index 0000000..7751bd9
--- /dev/null
+++ b/plugins/ontop/configure.in.in
@@ -0,0 +1 @@
+AM_CONDITIONAL(ENABLE_ONTOP, test "$use_kde" = "yes" || test "$kde_use_qt_win" = "yes")
diff --git a/plugins/ontop/ontop.cpp b/plugins/ontop/ontop.cpp
new file mode 100644
index 0000000..ca82463
--- /dev/null
+++ b/plugins/ontop/ontop.cpp
@@ -0,0 +1,346 @@
+/***************************************************************************
+                          ontop.cpp  -  description
+                             -------------------
+    begin                : Sun Mar 17 2002
+    copyright            : (C) 2002 by Vladimir Shutoff
+    email                : vovan@shutoff.ru
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   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.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#include "simapi.h"
+#include "mainwin.h"
+#include "core.h"
+
+#include "profile.h"
+#include "profilemanager.h"
+
+#include 
+#include 
+#include 
+#include 
+
+#ifdef WIN32
+#include 
+#else
+#if defined(USE_KDE)
+#include "kdeisversion.h"
+#include 
+#endif
+#endif
+
+#include "misc.h"
+#include "core_consts.h"
+
+#include "ontop.h"
+#include "ontopcfg.h"
+
+using namespace SIM;
+
+Plugin *createOnTopPlugin(unsigned base, bool, Buffer *config)
+{
+#if defined(WIN32) || defined(USE_KDE)
+    return new OnTopPlugin(base, config);
+#else
+    return NULL;
+#endif
+}
+
+static PluginInfo info =
+    {
+        I18N_NOOP("On Top"),
+        I18N_NOOP("Plugin provides main window and containers always on top"),
+        VERSION,
+        createOnTopPlugin,
+        PLUGIN_DEFAULT
+    };
+
+EXPORT_PROC PluginInfo* GetPluginInfo()
+{
+    return &info;
+}
+
+//static DataDef onTopData[] =
+//    {
+//        { "OnTop", DATA_BOOL, 1, DATA(1) },
+//        { "InTask", DATA_BOOL, 1, 0 },
+//        { "ContainerOnTop", DATA_BOOL, 1, 0 },
+//        { NULL, DATA_UNKNOWN, 0, 0 }
+//    };
+
+OnTopPlugin::OnTopPlugin(unsigned base, Buffer *config)
+    : QObject(), Plugin(base)
+{
+    m_propertyHub = SIM::PropertyHub::create("ontop");
+
+    CmdOnTop = registerType();
+
+    Command cmd;
+    cmd->id          = CmdOnTop;
+    cmd->text        = I18N_NOOP("Always on top");
+    cmd->menu_id     = MenuMain;
+    cmd->menu_grp    = 0x7000;
+    cmd->flags		= COMMAND_CHECK_STATE;
+    EventCommandCreate(cmd).process();
+
+#ifdef WIN32
+    m_state = HWND_NOTOPMOST;
+#endif
+
+#if defined(WIN32) || defined (USE_KDE)
+    qApp->installEventFilter(this);
+#endif
+
+    setState();
+}
+
+OnTopPlugin::~OnTopPlugin()
+{
+    EventCommandRemove(CmdOnTop).process();
+
+    setValue("OnTop", false);
+    setState();
+}
+
+bool OnTopPlugin::processEvent(Event *e)
+{
+    // FIXME what a mess...
+    if (e->type() == eEventInit)
+        setState();
+    else if(e->type() == eEventPluginLoadConfig)
+    {
+        PropertyHubPtr hub = ProfileManager::instance()->getPropertyHub("ontop");
+        if(!hub.isNull())
+            setPropertyHub(hub);
+        if(!value("OnTop").isValid())
+            setValue("OnTop", true);
+    }
+    else
+    if (e->type() == eEventCommandExec){
+        EventCommandExec *ece = static_cast(e);
+        CommandDef *cmd = ece->cmd();
+        if (cmd->id == CmdOnTop){
+            setValue("OnTop", !value("OnTop").toBool());
+            setState();
+            return true;
+        }
+    } else
+    if (e->type() == eEventCheckCommandState){
+        EventCheckCommandState *ecs = static_cast(e);
+        CommandDef *cmd = ecs->cmd();
+        if (cmd->id == CmdOnTop){
+            getState();
+            cmd->flags &= ~COMMAND_CHECKED;
+            if (value("OnTop").toBool())
+                cmd->flags |= COMMAND_CHECKED;
+            return true;
+        }
+    }
+#ifdef WIN32
+    if (e->type() == eEventOnTop){
+        EventOnTop *eot = static_cast(e);
+        QWidget *main = getMainWindow();
+        if (main == NULL)
+            return false;
+        HWND hState = HWND_NOTOPMOST;
+        if (value("OnTop").toBool())
+            hState = HWND_TOPMOST;
+        if (eot->showOnTop())
+            hState = HWND_BOTTOM;
+        if (m_state != hState)
+        {
+            SetWindowPos(main->winId(), hState, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
+            m_state = hState;
+        }
+    } else
+    if (e->type() == eEventInTaskManager){
+        EventInTaskManager *eitm = static_cast(e);
+        QWidget *main = getMainWindow();
+        if (main == NULL)
+            return false;
+        if (IsWindowUnicode(main->winId())){
+            if (eitm->showInTaskmanager() && value("InTask").toBool()){
+                SetWindowLongW(main->winId(), GWL_EXSTYLE,
+                               (GetWindowLongW(main->winId(), GWL_EXSTYLE) | WS_EX_APPWINDOW) & (~WS_EX_TOOLWINDOW));
+            }else{
+                DWORD exStyle = GetWindowLongW(main->winId(), GWL_EXSTYLE);
+                if ((exStyle & WS_EX_TOOLWINDOW) == 0){
+                    SetWindowLongW(main->winId(), GWL_EXSTYLE, (exStyle  & ~WS_EX_APPWINDOW) | WS_EX_TOOLWINDOW);
+                    QPoint p = main->pos();
+                    QSize s = main->size();
+                    main->resize(s.width() + 1, s.height());
+                    main->resize(s.width(), s.height());
+                    main->move(p);
+                }
+            }
+        }else{
+            if (eitm->showInTaskmanager() && value("InTask").toBool()){
+                SetWindowLongA(main->winId(), GWL_EXSTYLE,
+                               (GetWindowLongA(main->winId(), GWL_EXSTYLE) | WS_EX_APPWINDOW) & (~WS_EX_TOOLWINDOW));
+            }else{
+                DWORD exStyle = GetWindowLongA(main->winId(), GWL_EXSTYLE);
+                if ((exStyle & WS_EX_TOOLWINDOW) == 0){
+                    SetWindowLongA(main->winId(), GWL_EXSTYLE, (exStyle  & ~WS_EX_APPWINDOW) | WS_EX_TOOLWINDOW);
+                    QSize s = main->size();
+                    main->resize(s.width() + 1, s.height());
+                    main->resize(s.width(), s.height());
+                }
+            }
+        }
+        return true;
+    }
+#endif
+    return false;
+}
+
+QByteArray OnTopPlugin::getConfig()
+{
+    getState();
+    return QByteArray();
+}
+
+QWidget *OnTopPlugin::getMainWindow()
+{
+    CorePlugin *core = GET_CorePlugin();
+    return core->getMainWindow();
+}
+
+void OnTopPlugin::getState()
+{
+#ifdef USE_KDE
+    QWidget *main = getMainWindow();
+    if (main == NULL) return;
+#if KDE_IS_VERSION(3,2,0)
+    setOnTop(KWin::windowInfo(main->winId()).state() & NET::StaysOnTop);
+#else
+    setOnTop(KWin::info(main->winId()).state & NET::StaysOnTop);
+#endif
+#endif
+}
+
+void OnTopPlugin::setState()
+{
+    QWidget *main = getMainWindow();
+    if (main){
+#ifdef WIN32
+        EventOnTop(false).process();
+        EventInTaskManager(value("InTask").toBool()).process();
+#else
+#ifdef USE_KDE
+        if (getOnTop()){
+            KWin::setState(main->winId(), NET::StaysOnTop);
+        }else{
+            KWin::clearState(main->winId(), NET::StaysOnTop);
+        }
+        if (getInTask()){
+            KWin::clearState(main->winId(), NET::SkipTaskbar);
+        }else{
+            KWin::setState(main->winId(), NET::SkipTaskbar);
+        }
+#endif
+#endif
+    }
+    QWidgetList list = QApplication::topLevelWidgets();
+    QWidget *w;
+    foreach(w,list)
+	{
+			if (w->inherits("Container")){
+#ifdef WIN32
+				HWND hState = HWND_NOTOPMOST;
+                                if (value("ContainerOnTop").toBool()) hState = HWND_TOPMOST;
+				SetWindowPos(w->winId(), hState, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+#else
+#ifdef USE_KDE
+				if (getContainerOnTop())
+				{
+					KWin::setState(w->winId(), NET::StaysOnTop);
+				}
+				else
+				{
+					KWin::clearState(w->winId(), NET::StaysOnTop);
+				}
+#endif
+#endif
+			}
+		}
+	}
+
+#if defined(USE_KDE) || defined(WIN32)
+QWidget *OnTopPlugin::createConfigWindow(QWidget *parent)
+{
+    return new OnTopCfg(parent, this);
+}
+#endif
+
+bool OnTopPlugin::eventFilter(QObject *o, QEvent *e)
+{
+#ifdef WIN32
+    if ((e->type() == QEvent::WindowActivate) &&
+            (value("OnTop").toBool() || value("ContainerOnTop").toBool() ) &&
+            o->inherits("QDialog")){
+        QWidget *w = static_cast(o);
+        SetWindowPos(w->winId(), HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+    }
+    if ((e->type() == QEvent::WindowDeactivate) &&
+            (value("OnTop").toBool() || value("ContainerOnTop").toBool()) &&
+            o->inherits("QDialog")){
+        QWidget *w = static_cast(o);
+        SetWindowPos(w->winId(), HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+    }
+    if ((e->type() == QEvent::Show) &&
+            value("ContainerOnTop").toBool() &&
+            o->inherits("Container")){
+        QWidget *w = static_cast(o);
+        SetWindowPos(w->winId(), HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+    }
+#endif
+#ifdef USE_KDE
+    if ((e->type() == QEvent::WindowActivate) &&
+            (value("OnTop").toBool() || value("ContainerOnTop").toBool()) &&
+            o->inherits("QDialog")){
+        QWidget *w = static_cast(o);
+        KWin::setState(w->winId(), NET::StaysOnTop);
+    }
+    if ((e->type() == QEvent::WindowDeactivate) &&
+            (value("OnTop").toBool() || value("ContainerOnTop").toBool()) &&
+            o->inherits("QDialog")){
+        QWidget *w = static_cast(o);
+        KWin::clearState(w->winId(), NET::StaysOnTop);
+    }
+    if ((e->type() == QEvent::Show) &&
+            value("ContainerOnTop").toBool() &&
+            o->inherits("Container")){
+        QWidget *w = static_cast(o);
+        KWin::setState(w->winId(), NET::StaysOnTop);
+    }
+#endif
+    return QObject::eventFilter(o, e);
+}
+
+void OnTopPlugin::setPropertyHub(SIM::PropertyHubPtr hub)
+{
+	m_propertyHub = hub;
+}
+
+SIM::PropertyHubPtr OnTopPlugin::propertyHub()
+{
+	return m_propertyHub;
+}
+
+QVariant OnTopPlugin::value(const QString& key)
+{
+	return m_propertyHub->value(key);
+}
+
+void OnTopPlugin::setValue(const QString& key, const QVariant& v)
+{
+	m_propertyHub->setValue(key, v);
+}
+
diff --git a/plugins/ontop/ontop.h b/plugins/ontop/ontop.h
new file mode 100644
index 0000000..5e2b290
--- /dev/null
+++ b/plugins/ontop/ontop.h
@@ -0,0 +1,101 @@
+/***************************************************************************
+                          ontop.h  -  description
+                             -------------------
+    begin                : Sun Mar 17 2002
+    copyright            : (C) 2002 by Vladimir Shutoff
+    email                : vovan@shutoff.ru
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   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.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#ifndef _ONTOP_H
+#define _ONTOP_H
+
+#ifdef WIN32
+#include 
+#endif
+
+#include 
+#include 
+#include 
+
+#include "cfg.h"
+#include "event.h"
+#include "plugins.h"
+#include "propertyhub.h"
+
+class EventInTaskManager : public SIM::Event
+{
+public:
+    EventInTaskManager(bool bShowInTask)
+        : Event(SIM::eEventInTaskManager), m_bShowInTask(bShowInTask) {}
+
+    bool showInTaskmanager() const { return m_bShowInTask; }
+protected:
+    bool m_bShowInTask;
+};
+
+class EventOnTop : public SIM::Event
+{
+public:
+    // bShowOnTop is maybe wrong, rename if someone knows what it means
+    EventOnTop(bool bShowOnTop)
+        : Event(SIM::eEventOnTop), m_bShowOnTop(bShowOnTop) {}
+
+    bool showOnTop() const { return m_bShowOnTop; }
+protected:
+    bool m_bShowOnTop;
+};
+
+struct OnTopData
+{
+//    SIM::Data	OnTop;
+//    SIM::Data	InTask;
+//    SIM::Data	ContainerOnTop;
+};
+
+class OnTopPlugin : public QObject, public SIM::Plugin, public SIM::EventReceiver
+{
+    Q_OBJECT
+public:
+    OnTopPlugin(unsigned, Buffer*);
+    virtual ~OnTopPlugin();
+
+    void setPropertyHub(SIM::PropertyHubPtr hub);
+    SIM::PropertyHubPtr propertyHub();
+    QVariant value(const QString& key);
+    void setValue(const QString& key, const QVariant& v);
+
+protected:
+    virtual bool eventFilter(QObject*, QEvent*);
+    virtual bool processEvent(SIM::Event *e);
+#if defined(USE_KDE) || defined(WIN32)
+    virtual QWidget *createConfigWindow(QWidget *parent);
+#endif
+    virtual QByteArray getConfig();
+    void getState();
+    void setState();
+    QWidget *getMainWindow();
+    unsigned CmdOnTop;
+//    PROP_BOOL(OnTop);
+//    PROP_BOOL(InTask);
+//    PROP_BOOL(ContainerOnTop);
+//    OnTopData data;
+#ifdef WIN32
+    HWND m_state;
+#endif
+    friend class OnTopCfg;
+
+private:
+    SIM::PropertyHubPtr m_propertyHub;
+};
+
+#endif
+
diff --git a/plugins/ontop/ontop.rc b/plugins/ontop/ontop.rc
new file mode 100644
index 0000000..f959ba1
--- /dev/null
+++ b/plugins/ontop/ontop.rc
@@ -0,0 +1,97 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+/////////////////////////////////////////////////////////////////////////////
+// Neutral resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU)
+#ifdef _WIN32
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+#pragma code_page(1251)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+    "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+    "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+
+#ifndef _MAC
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 0,9,6,0
+ PRODUCTVERSION 0,9,6,0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "000004b0"
+        BEGIN
+            VALUE "Comments", "\0"
+            VALUE "CompanyName", "Vladimir Shutoff\0"
+            VALUE "FileDescription", "OnTop plugin\0"
+            VALUE "FileVersion", "0, 9, 6, 0\0"
+            VALUE "InternalName", "ontop\0"
+            VALUE "LegalCopyright", "Copyright © 2002-2003\0"
+            VALUE "LegalTrademarks", "\0"
+            VALUE "OriginalFilename", "ontop.dll\0"
+            VALUE "PrivateBuild", "\0"
+            VALUE "ProductName", "SIM\0"
+            VALUE "ProductVersion", "0, 9, 6, 0\0"
+            VALUE "SpecialBuild", "\0"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x0, 1200
+    END
+END
+
+#endif    // !_MAC
+
+#endif    // Neutral resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+
diff --git a/plugins/ontop/ontop.vcproj b/plugins/ontop/ontop.vcproj
new file mode 100644
index 0000000..84eefb2
--- /dev/null
+++ b/plugins/ontop/ontop.vcproj
@@ -0,0 +1,406 @@
+
+
+	
+		
+	
+	
+		
+	
+	
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+	
+	
+	
+	
+		
+			
+				
+					
+				
+				
+					
+				
+			
+			
+				
+					
+				
+				
+					
+				
+			
+			
+				
+					
+				
+				
+					
+				
+			
+			
+				
+					
+				
+				
+					
+				
+			
+		
+		
+			
+				
+					
+				
+				
+					
+				
+			
+			
+				
+					
+				
+				
+					
+				
+			
+		
+		
+			
+				
+					
+				
+				
+					
+				
+			
+		
+		
+			
+				
+					
+				
+				
+					
+				
+			
+		
+	
+	
+	
+
diff --git a/plugins/ontop/ontopcfg.cpp b/plugins/ontop/ontopcfg.cpp
new file mode 100644
index 0000000..ef5d6f0
--- /dev/null
+++ b/plugins/ontop/ontopcfg.cpp
@@ -0,0 +1,37 @@
+/***************************************************************************
+                          ontopcfg.cpp  -  description
+                             -------------------
+    begin                : Sun Mar 17 2002
+    copyright            : (C) 2002 by Vladimir Shutoff
+    email                : vovan@shutoff.ru
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   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.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#include "ontopcfg.h"
+#include "ontop.h"
+
+#include 
+
+OnTopCfg::OnTopCfg(QWidget *parent, OnTopPlugin *plugin) : QWidget(parent)
+{
+	setupUi(this);
+    m_plugin = plugin;
+    chkInTask->setChecked(m_plugin->value("InTask").toBool());
+    chkContainer->setChecked(m_plugin->value("ContainerOnTop").toBool());
+}
+
+void OnTopCfg::apply()
+{
+    m_plugin->setValue("InTask", chkInTask->isChecked());
+    m_plugin->setValue("ContainerOnTop", chkContainer->isChecked());
+    m_plugin->setState();
+}
+
diff --git a/plugins/ontop/ontopcfg.h b/plugins/ontop/ontopcfg.h
new file mode 100644
index 0000000..f4bd611
--- /dev/null
+++ b/plugins/ontop/ontopcfg.h
@@ -0,0 +1,37 @@
+/***************************************************************************
+                          ontopcfg.h  -  description
+                             -------------------
+    begin                : Sun Mar 17 2002
+    copyright            : (C) 2002 by Vladimir Shutoff
+    email                : vovan@shutoff.ru
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   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.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#ifndef _ONTOPCFG_H
+#define _ONTOPCFG_H
+
+#include "ui_ontopcfgbase.h"
+
+class OnTopPlugin;
+
+class OnTopCfg : public QWidget, public Ui::OnTopCfgBase
+{
+    Q_OBJECT
+public:
+    OnTopCfg(QWidget *w, OnTopPlugin *plugin);
+public slots:
+    void apply();
+protected:
+    OnTopPlugin *m_plugin;
+};
+
+#endif
+
diff --git a/plugins/ontop/ontopcfgbase.ui b/plugins/ontop/ontopcfgbase.ui
new file mode 100644
index 0000000..422dabe
--- /dev/null
+++ b/plugins/ontop/ontopcfgbase.ui
@@ -0,0 +1,82 @@
+
+  
+  
+  
+  OnTopCfgBase
+  
+    
+      
+        0
+        0
+        320
+        140
+      
+    
+    
+      Form1
+    
+    
+      
+        11
+      
+      
+        6
+      
+      
+        
+          
+            Show &main window in task manager
+          
+        
+      
+      
+        
+          
+            &Container always on top
+          
+        
+      
+      
+        
+          
+            
+              20
+              20
+            
+          
+          
+            QSizePolicy::Expanding
+          
+          
+            Qt::Vertical
+          
+        
+      
+    
+  
+  
+    
+      QWidget
+      QWidget
+      
QWidget
+ + -1 + -1 + + 0 + + 5 + 5 + + image0 + + text + +
+
+ + + 789c6dd2c10ac2300c00d07bbf2234b7229d1be245fc04c5a3201e4615f430059d0711ff5ddb2e6bb236ec90eed134cb5a19d8ef36602af5ecdbfeeac05dda0798d3abebde87e3faa374d3807fa0d633a52d38d8de6f679fe33fc776e196f53cd010188256a3600a292882096246517815ca99884606e18044a3a40d91824820924265a7923a2e8bcd05f33db1173e002913175f2a6be6d3294871a2d95fa00e8a94ee017b69d339d90df1e77c57ea072ede6758 + + +
diff --git a/plugins/osd/CMakeLists.txt b/plugins/osd/CMakeLists.txt new file mode 100644 index 0000000..bf553e8 --- /dev/null +++ b/plugins/osd/CMakeLists.txt @@ -0,0 +1,24 @@ +############### +# osd library # +############### +SET(osd_SRCS + osd.cpp + osdconfig.cpp + osdiface.cpp +) + +SET(osd_HDRS + osd.h + osdconfig.h + osdiface.h +) + +SET(osd_UICS + osdconfigbase.ui + osdifacebase.ui +) + +REMOVE_DEFINITIONS(-DQT3_SUPPORT) +REMOVE_DEFINITIONS(-DQT_3SUPPORT_LIB) +REMOVE_DEFINITIONS(-DQT3_SUPPORT_WARNINGS) +SIM_ADD_PLUGIN(osd) diff --git a/plugins/osd/osd.cpp b/plugins/osd/osd.cpp new file mode 100644 index 0000000..b70dab4 --- /dev/null +++ b/plugins/osd/osd.cpp @@ -0,0 +1,847 @@ +/************************************************************************** + osd.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + *************************************************************************** + + Check screen saver state from xscreensaver-command, Copyright (c) 1991-1998 + by Jamie Zawinski + + Set the LEDS Methods are taken from setleds. + CapsLED-Notification, Copyright (c) 2007 by Tobias Franz + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "simgui/fontedit.h" +#include "contacts/contact.h" + +#include "core.h" + +#include "log.h" +#include "icons.h" + + +#include "osd.h" +#include "osdconfig.h" + +#ifdef WIN32 + #include +#else // assume POSIX + #include +#endif + + +#ifndef Q_WS_WIN + /*#include + #include + #include + #include + #include + #include + + #include "local.h" + #include "utils.h" + #define KD "/dev/console" */ + + #if !defined(Q_OS_MAC) && !defined(__OS2__) + #include + #include + #include + #endif +#endif + +using namespace std; +using namespace SIM; + +const unsigned SHADOW_DEF = 1; +const unsigned XOSD_MARGIN = 5; +static const int cTCD = 5; +static const int cFadeTime = 10; + + + +Plugin *createOSDPlugin(unsigned base, bool, Buffer*) +{ + Plugin *plugin = new OSDPlugin(base); + return plugin; +} + +static PluginInfo info = + { + I18N_NOOP("OSD"), + I18N_NOOP("Plugin provides on screen notification about messages and contacts status"), + VERSION, + createOSDPlugin, + PLUGIN_DEFAULT + }; + +EXPORT_PROC PluginInfo* GetPluginInfo() +{ + return &info; +} + +static OSDPlugin *osdPlugin = NULL; + +static QWidget *getOSDSetup(QWidget *parent, SIM::PropertyHubPtr data) +{ + return new OSDConfig(parent, data, osdPlugin); +} + +OSDPlugin::OSDPlugin(unsigned base) + : Plugin(base) + , m_osd(NULL) + , bCapsState(false) + , bHaveUnreadMessages(false) + , bTimerActive(false) +{ + osdPlugin = this; + + Command cmd; + cmd->id = 0; + cmd->text = I18N_NOOP("&OSD"); + cmd->icon = "alert"; + cmd->param = (void*)getOSDSetup; + cmd->accel = "OSD"; + EventAddPreferences(cmd).process(); + + m_request.contact = 0; + m_request.type = OSD_NONE; + + m_timer = new QTimer(this); + connect(m_timer, SIGNAL(timeout()), this, SLOT(timeout())); +} + +OSDPlugin::~OSDPlugin() +{ + delete m_osd; + osdPlugin = NULL; + EventRemovePreferences(user_data_id).process(); + getContacts()->unregisterUserData(user_data_id); +} + +QWidget *OSDPlugin::createConfigWindow(QWidget *parent) +{ + return new OSDConfig(parent, getContacts()->getUserData("OSD"), this); +} + +void OSDPlugin::timeout() +{ + m_osd->hide(); + m_timer->stop(); bTimerActive=false; //Due to a fucking bug in QTimer::isActive() + processQueue(); +} + +QFont OSDPlugin::getBaseFont(QFont font) +{ + QFont baseFont; + + baseFont = font; + int size = baseFont.pixelSize(); + if (size <= 0) + { + size = baseFont.pointSize(); + baseFont.setPointSize(size * 2); + } + else + { + baseFont.setPixelSize(size * 2); + } + baseFont.setBold(true); + + return baseFont; +} + +OSDWidget::OSDWidget(OSDPlugin *plugin) + : QLabel(NULL, Qt::Tool | + Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint ) +{ + m_plugin = plugin; + baseFont = m_plugin->getBaseFont(font()); + setFocusPolicy(Qt::NoFocus); + setAttribute(Qt::WA_TranslucentBackground, true); + setAttribute(Qt::WA_NoSystemBackground, true); + setAttribute(Qt::WA_OpaquePaintEvent, true); + setAttribute(Qt::WA_MacAlwaysShowToolWindow, true); + setAutoFillBackground(false); + connect(&m_transTimer, SIGNAL(timeout()), this, SLOT(slotTimerFadeInTimeout())); + QPalette pal = palette(); + pal.setColor(QPalette::Background,Qt::transparent); + setPalette(pal); +} + +bool OSDWidget::isScreenSaverActive() +{ +#if defined( Q_WS_WIN ) && defined( SPI_GETSCREENSAVERRUNNING ) + BOOL pvParam; + if (SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, &pvParam, 0)){ + if (pvParam) + return true; + } +#endif + return false; +} + +static const char * const close_h_xpm[] = { + "8 8 3 1", + " c None", + ". c #000000", + "+ c none", + ".++++++.", + "+.++++.+", + "++.++.++", + "+++..+++", + "+++..+++", + "++.++.++", + "+.++++.+", + ".++++++."}; + +void OSDWidget::showOSD(const QString &str, SIM::PropertyHubPtr data) +{ + currentData = data; + m_bFading = data->value("Fading").toBool(); + m_sText = str; + if (isScreenSaverActive()) + { + hide(); + return; + } + m_text_y = 0; + m_bBackground = data->value("Background").toBool(); + m_bShadow = data->value("Shadow").toBool(); + + setFont(FontEdit::str2font(data->value("Font").toString(), baseFont)); + + //int SHADOW_OFFS = SHADOW_DEF; + + recalcGeometry(); + resize(m_Rect.size()); + + QImage image(size(),QImage::Format_ARGB32); + image.fill(Qt::transparent); + + QPainter p(&image); + p.setRenderHints(QPainter::HighQualityAntialiasing|QPainter::TextAntialiasing|QPainter::Antialiasing); + draw(p); + p.end(); + setPixmap(QPixmap::fromImage(image)); + if (m_bFading) + setMask(QPixmap::fromImage(image.createAlphaMask(), Qt::MonoOnly)); + + transCounter = 0; + transCounterDelta = cTCD; + setWindowOpacity(transCounter/100.); + + QLabel::show(); + raise(); + + if (m_bFading) + m_transTimer.start(cFadeTime); + +} + +QRect OSDWidget::recalcGeometry() +{ + int SHADOW_OFFS = SHADOW_DEF; + unsigned nScreen = currentData->value("Screen").toUInt(); + unsigned nScreens = screens(); + if (nScreen >= nScreens) + nScreen = 0; + QRect rcScreen = screenGeometry(nScreen); + rcScreen = QRect(0, 0, + rcScreen.width() - SHADOW_OFFS - XOSD_MARGIN * 2 - currentData->value("Offset").toUInt(), + rcScreen.height() - SHADOW_OFFS - XOSD_MARGIN * 2 - currentData->value("Offset").toUInt()); + QFontMetrics fm(font()); + QRect rc = fm.boundingRect(rcScreen, Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, m_sText); + if (rc.height() >= rcScreen.height() / 2){ + rcScreen = QRect(0, 0, + rcScreen.width() - SHADOW_OFFS - XOSD_MARGIN * 2 - currentData->value("Offset").toUInt(), + rcScreen.height() - SHADOW_OFFS - XOSD_MARGIN * 2 - currentData->value("Offset").toUInt()); + rc = fm.boundingRect(rcScreen, Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, m_sText); + } + if (currentData->value("EnableMessageShowContent").toBool() && currentData->value("ContentLines").toUInt()) + { + QFontMetrics fm(font()); + int maxHeight = fm.height() * (currentData->value("ContentLines").toUInt() + 1); + if (rc.height() > maxHeight) + rc.setHeight(maxHeight); + } + int x = rcScreen.left(); + int y = rcScreen.top(); + int w = rc.width() + 1; + int h = rc.height() + 1; + m_text_y = 0; + if (m_bBackground) + { + w += XOSD_MARGIN * 2; + h += XOSD_MARGIN * 2; + if (m_imageButton.isNull()) + { + m_imageButton = Image("button_cancel"); + if( m_imageButton.isNull() ) + m_imageButton = QPixmap((const char **)close_h_xpm).toImage(); + } + m_rectButton = QRect(QPoint(w - m_imageButton.width() - 3, 3),m_imageButton.size()); + m_text_y = m_imageButton.height() + 4; + h += m_text_y; + } + if (m_bShadow) + { + w += SHADOW_OFFS; + h += SHADOW_OFFS; + } + switch (currentData->value("Position").toUInt()){ + case 1: + move(x + currentData->value("Offset").toUInt(), y + currentData->value("Offset").toUInt()); + break; + case 2: + move(x + rcScreen.width() - currentData->value("Offset").toUInt() - w, y + rcScreen.height() - currentData->value("Offset").toUInt() - h); + break; + case 3: + move(x + rcScreen.width() - currentData->value("Offset").toUInt() - w, y + currentData->value("Offset").toUInt()); + break; + case 4: + move(x + (rcScreen.width() - w) / 2, y + rcScreen.height() - currentData->value("Offset").toUInt() - h); + break; + case 5: + move(x + (rcScreen.width() - w) / 2, y + currentData->value("Offset").toUInt()); + break; + case 6: + move(x + (rcScreen.width() - w) / 2, y + (rcScreen.height() - h) /2); + break; + default: + move(x + currentData->value("Offset").toUInt(), y + rcScreen.height() - currentData->value("Offset").toUInt() - h); + } + + m_Rect = QRect(x,y,w,h); + return m_Rect; +} + +QSize OSDWidget::sizeHint() const +{ + return m_Rect.size(); +} + +void OSDWidget::slotTimerFadeInTimeout() +{ + transCounter += transCounterDelta; + if (transCounter>100) + { + transCounter = 100; + m_transTimer.stop(); + } + else if (transCounter<=0) + { + transCounter = 0; + m_transTimer.stop(); + QLabel::hide(); + } + setWindowOpacity(transCounter/100.); + update(); +} + +void OSDWidget::draw(QPainter &p) +{ + QSize s = size(); + int w = s.width(); + int h = s.height(); + QRect rc(0, 0, w, h); + + if (m_bBackground) + { + if (m_bShadow) + { + w -= SHADOW_DEF; + h -= SHADOW_DEF; + rc = QRect(0, 0, w, h); + } + p.setPen(QPen(QColor(0x00,0x00,0x00))); + p.setBrush(QBrush(currentData->value("BgColor").toUInt())); + p.drawRoundedRect(rc,7,7); + p.drawImage(m_rectButton,m_imageButton); + rc = QRect(XOSD_MARGIN, XOSD_MARGIN, w - XOSD_MARGIN * 2, h - XOSD_MARGIN * 2); + } + + rc.translate(0,m_text_y); + p.setFont(font()); + + if( m_bShadow ) + { + p.setPen(Qt::darkGray); + QRect src(rc); + src.translate(SHADOW_DEF,SHADOW_DEF); + p.drawText(src, Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, m_sText); + } + + p.setPen(currentData->value("Color").toUInt()); + p.drawText(rc, Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, m_sText); +} + +void OSDWidget::mouseDoubleClickEvent(QMouseEvent*) +{ + emit dblClick(); + close(); +} + +void OSDWidget::mousePressEvent(QMouseEvent *event) +{ + if(m_rectButton.contains(event->pos())) + emit closeClick(); +} + +void OSDWidget::slotCloseClick() +{ + emit closeClick(); +} + +void OSDWidget::hide() +{ + if( m_bFading ) + { + transCounter = 100; + transCounterDelta = -cTCD; + m_transTimer.start(cFadeTime); + } + else + QLabel::hide(); +} + +#if 0 +i18n("male", "%1 is online") +i18n("female", "%1 is online") +i18n("male", "%1 is away") +i18n("female", "%1 is away") +i18n("male", "%1 is not available") +i18n("female", "%1 is not available") +i18n("male", "%1 doesn't want to be disturbed") +i18n("female", "%1 doesn't want to be disturbed") +i18n("male", "%1 is occupied") +i18n("female", "%1 is occupied") +i18n("male", "%1 is free for chat") +i18n("female", "%1 is free for chat") +i18n("male", "%1 is offline") +i18n("female", "%1 is offline") +i18n("male", "%1 is typing") +i18n("female", "%1 is typing") +#endif + +typedef map TYPE_MAP; + +void OSDPlugin::processQueue() +{ + if (bTimerActive /*m_timer->isActive()*/) //Due to a fucking bug in QTimer::isActive() + return; + while (m_queue.size()){ + m_request = m_queue.takeFirst(); + Contact *contact = getContacts()->contact(m_request.contact); + if ((contact == NULL) || contact->getIgnore()) + continue; + QString text; + SIM::PropertyHubPtr data = contact->getUserData("OSD"); + uint ms = STATUS_ONLINE; + switch (m_request.type){ + case OSD_ALERTONLINE: + if (data->value("EnableAlert").toBool() && data->value("EnableAlertOnline").toBool()){ + unsigned style = 0; + QString statusIcon; + if (contact->contactInfo(style, statusIcon) == STATUS_ONLINE) + text = g_i18n("%1 is online", contact) .arg(contact->getName()); + } + break; + case OSD_ALERTAWAY: + if (data->value("EnableAlert").toBool() && data->value("EnableAlertAway").toBool()){ + text = g_i18n("%1 is away", contact) .arg(contact->getName()); + } + break; + case OSD_ALERTNA: + if (data->value("EnableAlert").toBool() && data->value("EnableAlertNA").toBool()){ + text = g_i18n("%1 is not available", contact) .arg(contact->getName()); + } + break; + case OSD_ALERTDND: + if (data->value("EnableAlert").toBool() && data->value("EnableAlertDND").toBool()){ + text = g_i18n("%1 doesn't want to be disturbed", contact) .arg(contact->getName()); + } + break; + case OSD_ALERTOCCUPIED: + if (data->value("EnableAlert").toBool() && data->value("EnableAlertOccupied").toBool()){ + text = g_i18n("%1 is occupied", contact) .arg(contact->getName()); + } + break; + case OSD_ALERTFFC: + if (data->value("EnableAlert").toBool() && data->value("EnableAlertFFC").toBool()){ + text = g_i18n("%1 is free for chat", contact) .arg(contact->getName()); + } + break; + case OSD_ALERTOFFLINE: + if (data->value("EnableAlert").toBool() && data->value("EnableAlertOffline").toBool() && (ms-1) ){ + text = g_i18n("%1 is offline", contact) .arg(contact->getName()); + } + break; + case OSD_TYPING: + if (data->value("EnableTyping").toBool()){ + unsigned style = 0; + QSet wrkIcons; + QString statusIcon; + contact->contactInfo(style, statusIcon, &wrkIcons); + if (wrkIcons.contains("typing")) + text = g_i18n("%1 is typing", contact) .arg(contact->getName()); + } + break; + case OSD_MESSAGE: +/* if (data->EnableMessage.toBool() && core ){ + * list::iterator it; + * TYPE_MAP types; + * TYPE_MAP::iterator itc; + * QString msg_text; + * for (it = core->unread.begin(); it != core->unread.end(); ++it){ + * if (it->contact != m_request.contact) + * continue; + * unsigned type = it->type; + * itc = types.find(type); + * if (itc == types.end()){ + * types.insert(TYPE_MAP::value_type(type, 1)); + * }else{ + * (*itc).second++; + * } + * if (!data->EnableMessageShowContent.toBool()) + * continue; + * EventLoadMessage e(it->id, it->client, it->contact); + * e.process(); + * Message *msg = e.message(); + * if (msg == NULL) + * continue; + * QString msgText = msg->getPlainText().trimmed(); + * if (msgText.isEmpty()) + * continue; + * if (!msg_text.isEmpty()) + * msg_text += "\n"; + * msg_text += msgText; + * } + * if (types.empty()) + * break; + * for (itc = types.begin(); itc != types.end(); ++itc){ + * CommandDef *def = core->messageTypes.find((*itc).first); + * if (def == NULL) + * continue; + * MessageDef *mdef = (MessageDef*)(def->param); + * QString msg = i18n(mdef->singular, mdef->plural, (*itc).second); + * if ((*itc).second == 1){ + * int pos = msg.indexOf("1 "); + * if (pos > 0){ + * msg = msg.left(pos); + * }else if (pos == 0){ + * msg = msg.mid(2); + * } + * msg = msg.left(1).toUpper() + msg.mid(1); + * } + * if (!text.isEmpty()) + * text += ", "; + * text += msg; + * } + * + * + * if ( core->getManualStatus()==STATUS_NA && + * data->EnableCapsLockFlash.toBool() && + * ! this->isRunning() + * ) + * this->start(); //Start flashing the CapsLock if enabled + * text = i18n("%1 from %2") .arg(text) .arg(contact->getName()); + * if (msg_text.isEmpty()) + * break; + * text += ":\n"; + * text += msg_text; + * } + */ + break; + default: + break; + } + if (!text.isEmpty()){ + if (m_osd == NULL){ + m_osd = new OSDWidget(this); + connect(m_osd, SIGNAL(dblClick()), this, SLOT(dblClick())); + connect(m_osd, SIGNAL(closeClick()), this, SLOT(closeClick())); + } + static_cast(m_osd)->showOSD(text, data); + m_timer->start(data->value("Timeout").toUInt() * 1000); + bTimerActive=true; //Due to a fucking bug in QTimer::isActive() + return; + } + } + m_timer->stop(); bTimerActive=false; //Due to a fucking bug in QTimer::isActive() + m_request.contact = 0; + m_request.type = OSD_NONE; +} + +void OSDPlugin::run(){ + while ( bHaveUnreadMessages ) { + flashCapsLockLED(!bCapsState); + +#ifdef WIN32 + // milliseconds + Sleep(200); +#else + // microseconds + usleep(200*1000); +#endif + } + if (bCapsState) flashCapsLockLED(!bCapsState); //switch LED off +} + +void OSDPlugin::flashCapsLockLED(bool bCapsState){ + +#ifdef WIN32 + BYTE keyState[256]; + + GetKeyboardState((LPBYTE)&keyState); + if( ( !(keyState[VK_CAPITAL] & 1))) + //|| + //(!bCapsState && (keyState[VK_CAPITAL] & 1)) ) + + // Simulate a key press + keybd_event( VK_CAPITAL, + 0x45, + KEYEVENTF_EXTENDEDKEY | 0, + 0 ); + + // Simulate a key release + keybd_event( VK_CAPITAL, + 0x45, + KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, + 0); + +#elif defined(__OS2__) + // TODO: add OS/2 code to switch leds +#else + if (bCapsState) + system("xset led 3"); + else + system("xset -led 3"); +#endif + this->bCapsState= bCapsState; +} + +void OSDPlugin::closeClick() +{ +/* if (m_request.type == OSD_MESSAGE){ + * for (list::iterator it = core->unread.begin(); it != core->unread.end(); ){ + * if (it->contact != m_request.contact){ + * ++it; + * continue; + * } + * EventLoadMessage e(it->id, it->client, it->contact); + * e.process(); + * Message *msg = e.message(); + * core->unread.erase(it); + * if (msg){ + * EventMessageRead(msg).process(); + * delete msg; + * } + * it = core->unread.begin(); + * } + * } + * timeout(); + */ +} + +void OSDPlugin::dblClick() +{ + EventDefaultAction(m_request.contact).process(); + m_timer->stop(); bTimerActive=false; + m_timer->start(100); bTimerActive=true; +} + +bool OSDPlugin::processEvent(Event *e) +{ + OSDRequest osd; + switch (e->type()){ + case eEventContact: { + EventContact *ec = static_cast(e); + Contact *contact = ec->contact(); + if (contact->getIgnore()) + break; + switch(ec->action()) { + case EventContact::eOnline: { + osd.contact = contact->id(); + osd.type = OSD_ALERTONLINE; + m_queue.push_back(osd); + processQueue(); + break; + } + case EventContact::eStatus: + { + SIM::PropertyHubPtr data = contact->getUserData("OSD"); + if(!data.isNull()) { + unsigned style = 0; + QSet wrkIcons; + QString statusIcon; + contact->contactInfo(style, statusIcon, &wrkIcons); + if (wrkIcons.contains("typing")){ + if (!m_typing.contains(contact->id())) { + m_typing += contact->id(); + osd.contact = contact->id(); + osd.type = OSD_TYPING; + m_queue.push_back(osd); + processQueue(); + } + }else{ + m_typing.remove(contact->id()); + if ((m_request.type == OSD_TYPING) && (m_request.contact == contact->id())){ + m_timer->stop(); bTimerActive=false; + m_timer->start(100); bTimerActive=true; + } + } + } + break; + } + default: + break; + } + break; + } + case eEventMessageReceived: + { + EventMessage *em = static_cast(e); + Message *msg = em->msg(); + Contact *contact = getContacts()->contact(msg->contact()); + if (contact == NULL) + break; + SIM::PropertyHubPtr data = contact->getUserData("OSD"); + if(data.isNull()) + break; + osd.contact = msg->contact(); + CorePlugin* core = GET_CorePlugin(); + if (!core->unread.empty()) + bHaveUnreadMessages=true; + if (msg->type() == MessageStatus) { + StatusMessage *smsg = (StatusMessage*)msg; + switch (smsg->getStatus()) { + case STATUS_AWAY: + osd.type = OSD_ALERTAWAY; + break; + case STATUS_NA: + osd.type = OSD_ALERTNA; + break; + case STATUS_DND: + osd.type = OSD_ALERTDND; + break; + case STATUS_OCCUPIED: /* STATUS_OCCUPIED, took over from contacts.h! */ + osd.type = OSD_ALERTOCCUPIED; + break; + case STATUS_FFC: + osd.type = OSD_ALERTFFC; + break; + case STATUS_OFFLINE: + osd.type = OSD_ALERTOFFLINE; + break; + case STATUS_ONLINE: + osd.type = OSD_NONE; + return false; + default: + log(L_DEBUG,"OSD: Unknown status %ld",smsg->getStatus()); + osd.type = OSD_NONE; + return false; + } + m_queue.push_back(osd); + processQueue(); + }else{ + osd.type = OSD_MESSAGE; + if ((m_request.type == OSD_MESSAGE) && (m_request.contact == msg->contact())){ + m_queue.push_front(osd); + m_timer->stop(); bTimerActive=false; + m_timer->start(100);bTimerActive=true; + }else{ + m_queue.push_back(osd); + processQueue(); + } + } + break; + } + case eEventMessageDeleted: + case eEventMessageRead: { + EventMessage *em = static_cast(e); + Message *msg = em->msg(); + Contact *contact = getContacts()->contact(msg->contact()); + if (contact == NULL) + break; + SIM::PropertyHubPtr data = contact->getUserData("OSD"); + if (data.isNull()) + break; + osd.contact = msg->contact(); + CorePlugin* core = GET_CorePlugin(); + if (core->unread.empty()) + bHaveUnreadMessages=false; + if (msg->type() == MessageStatus) { + StatusMessage *smsg = (StatusMessage*)msg; + switch (smsg->getStatus()) { + case STATUS_AWAY: + osd.type = OSD_ALERTAWAY; + break; + case STATUS_NA: + osd.type = OSD_ALERTNA; + break; + case STATUS_DND: + osd.type = OSD_ALERTDND; + break; + case STATUS_OCCUPIED: /* STATUS_OCCUPIED, took over from contacts.h! */ + osd.type = OSD_ALERTOCCUPIED; + break; + case STATUS_FFC: + osd.type = OSD_ALERTFFC; + break; + case STATUS_OFFLINE: + osd.type = OSD_ALERTOFFLINE; + break; + case STATUS_ONLINE: + osd.type = OSD_NONE; + return false; + default: + log(L_DEBUG,"OSD: Unknown status %ld",smsg->getStatus()); + osd.type = OSD_NONE; + return false; + } + m_queue.push_back(osd); + processQueue(); + }else{ + osd.type = OSD_MESSAGE; + if ((m_request.type == OSD_MESSAGE) && (m_request.contact == msg->contact())){ + m_queue.push_front(osd); + m_timer->stop(); bTimerActive=false; + m_timer->start(100);bTimerActive=true; + }else{ + m_queue.push_back(osd); + processQueue(); + } + } + break; + } + default: + break; + } + return false; +} + diff --git a/plugins/osd/osd.h b/plugins/osd/osd.h new file mode 100644 index 0000000..be2e866 --- /dev/null +++ b/plugins/osd/osd.h @@ -0,0 +1,129 @@ +/*************************************************************************** + osd.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _OSD_H +#define _OSD_H + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +enum OSDType +{ + OSD_NONE, + OSD_ALERTONLINE, + OSD_ALERTAWAY, + OSD_ALERTNA, + OSD_ALERTDND, + OSD_ALERTOCCUPIED, + OSD_ALERTFFC, + OSD_ALERTOFFLINE, + OSD_TYPING, + OSD_MESSAGE +}; + +struct OSDRequest +{ + unsigned long contact; + OSDType type; +}; + +class OSDPlugin; + +class OSDWidget : public QLabel +{ + Q_OBJECT +public: + OSDWidget(OSDPlugin* plugin); + void showOSD(const QString &text, SIM::PropertyHubPtr data); + + virtual QSize sizeHint () const; + +signals: + void dblClick(); + void closeClick(); +protected slots: + void slotCloseClick(); + void slotTimerFadeInTimeout(); +public slots: + void hide(); + +private: + SIM::PropertyHubPtr currentData; + bool isScreenSaverActive(); + virtual void mouseDoubleClickEvent(QMouseEvent *e); + virtual void mousePressEvent(QMouseEvent *event); + QRect recalcGeometry(); + void draw(QPainter &p); + + QFont baseFont; + QPixmap bgPict; + OSDPlugin *m_plugin; + QTimer m_transTimer; + int transCounter; + int transCounterDelta; + bool m_bBackground; + bool m_bShadow; + int m_text_y; + QString m_sText; + bool m_bFading; + QRect m_Rect; + QImage m_imageButton; + QRect m_rectButton; +}; + +class OSDPlugin : public QThread, public SIM::Plugin, public SIM::EventReceiver +{ + Q_OBJECT +public: + OSDPlugin(unsigned); + QFont getBaseFont(QFont font); + virtual ~OSDPlugin(); + unsigned long user_data_id; +protected slots: + void timeout(); + void dblClick(); + void closeClick(); +protected: + virtual QWidget *createConfigWindow(QWidget *parent); + virtual bool processEvent(SIM::Event *e); + virtual void run(); + void processQueue(); + void flashCapsLockLED(bool); + OSDRequest m_request; + QList m_queue; + QSet m_typing; + OSDWidget *m_osd; + QTimer *m_timer; + bool bCapsState; + bool bHaveUnreadMessages; // Should use this flag in OSDPlugin::run instead of core->unread.size() + // see patch #2304 for more info. + bool bTimerActive; +}; + +#endif + diff --git a/plugins/osd/osd.rc b/plugins/osd/osd.rc new file mode 100644 index 0000000..ba4e580 --- /dev/null +++ b/plugins/osd/osd.rc @@ -0,0 +1,97 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,9,6,0 + PRODUCTVERSION 0,9,6,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Vladimir Shutoff\0" + VALUE "FileDescription", "OSD plugin\0" + VALUE "FileVersion", "0, 9, 6, 0\0" + VALUE "InternalName", "osd\0" + VALUE "LegalCopyright", "Copyright © 2002-2003\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "osd.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "SIM\0" + VALUE "ProductVersion", "0, 9, 6, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/osd/osd.vcproj b/plugins/osd/osd.vcproj new file mode 100644 index 0000000..a61b8d7 --- /dev/null +++ b/plugins/osd/osd.vcproj @@ -0,0 +1,499 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/osd/osdconfig.cpp b/plugins/osd/osdconfig.cpp new file mode 100644 index 0000000..606bc5a --- /dev/null +++ b/plugins/osd/osdconfig.cpp @@ -0,0 +1,116 @@ +/*************************************************************************** + osdconfig.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include +#include +#include + +#include "simgui/fontedit.h" +#include "misc.h" +#include "simgui/qcolorbutton.h" + +#include "osdconfig.h" +#include "osdiface.h" +#include "osd.h" + +using SIM::getContacts; + +OSDConfig::OSDConfig(QWidget *parent, SIM::PropertyHubPtr data, OSDPlugin *plugin) + : QWidget(parent) + , m_plugin(plugin) +{ + setupUi(this); + chkMessage->setChecked(data->value("EnableMessage").toBool()); + chkMessageContent->setChecked(data->value("EnableMessageShowContent").toBool()); + chkCapsLockFlash->setChecked(data->value("EnableCapsLockFlash").toBool()); + chkStatus->setChecked(data->value("EnableAlert").toBool()); + chkStatusOnline->setChecked(data->value("EnableAlertOnline").toBool()); + chkStatusAway->setChecked(data->value("EnableAlertAway").toBool()); + chkStatusNA->setChecked(data->value("EnableAlertNA").toBool()); + chkStatusDND->setChecked(data->value("EnableAlertDND").toBool()); + chkStatusOccupied->setChecked(data->value("EnableAlertOccupied").toBool()); + chkStatusFFC->setChecked(data->value("EnableAlertFFC").toBool()); + chkStatusOffline->setChecked(data->value("EnableAlertOffline").toBool()); + chkTyping->setChecked(data->value("EnableTyping").toBool()); + for (QObject *p = parent; p != NULL; p = p->parent()){ + QTabWidget *tab = qobject_cast(p); + if (!tab) + continue; + SIM::PropertyHubPtr data = getContacts()->getUserData("OSD"); + m_iface = new OSDIface(tab, data, plugin); + tab->addTab(m_iface, i18n("&Interface")); + break; + } + edtLines->setValue(data->value("ContentLines").toUInt()); + connect(chkStatus, SIGNAL(toggled(bool)), this, SLOT(statusToggled(bool))); + connect(chkMessage, SIGNAL(toggled(bool)), this, SLOT(showMessageToggled(bool))); + connect(chkMessageContent, SIGNAL(toggled(bool)), this, SLOT(contentToggled(bool))); + showMessageToggled(chkMessage->isChecked()); + contentToggled(chkMessageContent->isChecked()); + statusToggled(data->value("EnableAlert").toBool()); +} + +void OSDConfig::apply() +{ + apply(getContacts()->getUserData("OSD")); +} + +void OSDConfig::apply(SIM::PropertyHubPtr data) +{ + data->setValue("EnableMessage", chkMessage->isChecked()); + data->setValue("EnableMessageShowContent", chkMessageContent->isChecked()); + data->setValue("EnableCapsLockFlash", chkCapsLockFlash->isChecked()); + data->setValue("EnableAlert", chkStatus->isChecked()); + data->setValue("EnableAlertOnline", chkStatusOnline->isChecked()); + data->setValue("EnableAlertAway", chkStatusAway->isChecked()); + data->setValue("EnableAlertNA", chkStatusNA->isChecked()); + data->setValue("EnableAlertDND", chkStatusDND->isChecked()); + data->setValue("EnableAlertOccupied", chkStatusOccupied->isChecked()); + data->setValue("EnableAlertFFC", chkStatusFFC->isChecked()); + data->setValue("EnableAlertOffline", chkStatusOffline->isChecked()); + data->setValue("EnableTyping", chkTyping->isChecked()); + data->setValue("ContentLines", (uint)edtLines->text().toULong()); + m_iface->apply(data); +} + +void OSDConfig::statusToggled(bool bState) +{ + chkStatusOnline->setEnabled(bState); + chkStatusAway->setEnabled(bState); + chkStatusNA->setEnabled(bState); + chkStatusDND->setEnabled(bState); + chkStatusOccupied->setEnabled(bState); + chkStatusFFC->setEnabled(bState); + chkStatusOffline->setEnabled(bState); + chkCapsLockFlash->setEnabled(bState); +} + +void OSDConfig::showMessageToggled(bool bState) +{ + chkMessageContent->setEnabled(bState); + edtLines->setEnabled(bState && chkMessageContent->isChecked()); + lblLines->setEnabled(bState && chkMessageContent->isChecked()); +} + +void OSDConfig::contentToggled(bool bState) +{ + edtLines->setEnabled(bState && chkMessage->isChecked()); + lblLines->setEnabled(bState && chkMessage->isChecked()); +} + diff --git a/plugins/osd/osdconfig.h b/plugins/osd/osdconfig.h new file mode 100644 index 0000000..8e219f2 --- /dev/null +++ b/plugins/osd/osdconfig.h @@ -0,0 +1,44 @@ +/*************************************************************************** + osdconfig.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _OSDCONFIG_H +#define _OSDCONFIG_H + +#include "ui_osdconfigbase.h" +#include "propertyhub.h" + +class OSDPlugin; +class OSDIface; + +class OSDConfig : public QWidget, public Ui::OSDConfigBase +{ + Q_OBJECT +public: + OSDConfig(QWidget *parent, SIM::PropertyHubPtr data, OSDPlugin *plugin); +public slots: + void apply(SIM::PropertyHubPtr data); + void apply(); + void statusToggled(bool); + void showMessageToggled(bool); + void contentToggled(bool); +protected: + OSDIface *m_iface; + OSDPlugin *m_plugin; +}; + +#endif + diff --git a/plugins/osd/osdconfigbase.ui b/plugins/osd/osdconfigbase.ui new file mode 100644 index 0000000..020dcce --- /dev/null +++ b/plugins/osd/osdconfigbase.ui @@ -0,0 +1,163 @@ + + + OSDConfigBase + + + + 0 + 0 + 588 + 346 + + + + Form1 + + + + 11 + + + 6 + + + + + Enable &messages notification + + + + + + + Enable &status notification + + + + + + + Online + + + + + + + Away + + + + + + + N/A + + + + + + + Do not Disturb + + + + + + + Occupied + + + + + + + Free for chat + + + + + + + Offline + + + + + + + Enable &typing notification + + + + + + + Show message &content + + + + + + + Show lines of content: + + + false + + + + + + + All + + + 0 + + + + + + + Enable keyboard LED-notification in N/A state + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + diff --git a/plugins/osd/osdiface.cpp b/plugins/osd/osdiface.cpp new file mode 100644 index 0000000..4b89c11 --- /dev/null +++ b/plugins/osd/osdiface.cpp @@ -0,0 +1,120 @@ +/*************************************************************************** + osdiface.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include +#include + +#include "simgui/fontedit.h" +#include "misc.h" +#include "simgui/qcolorbutton.h" + +#include "osdiface.h" +#include "osd.h" + +using namespace SIM; + +OSDIface::OSDIface(QWidget *parent, SIM::PropertyHubPtr data, OSDPlugin *plugin) : QWidget(parent) +{ + setupUi(this); + m_plugin = plugin; +#ifndef WIN32 + chkFading->setChecked(false); + chkFading->hide(); +#endif + cmbPos->addItem(i18n("Left-bottom")); + cmbPos->addItem(i18n("Left-top")); + cmbPos->addItem(i18n("Right-bottom")); + cmbPos->addItem(i18n("Right-top")); + cmbPos->addItem(i18n("Center-bottom")); + cmbPos->addItem(i18n("Center-top")); + cmbPos->addItem(i18n("Center")); + cmbPos->setCurrentIndex(data->value("Position").toUInt()); + spnOffs->setMinimum(0); + spnOffs->setMaximum(500); + spnOffs->setValue(data->value("Offset").toUInt()); + spnTimeout->setMinimum(1); + spnTimeout->setMaximum(60); + spnTimeout->setValue(data->value("Timeout").toUInt()); + btnColor->setColor(data->value("Color").toUInt()); + if (data->value("Font").toString().isEmpty()){ + edtFont->setFont(FontEdit::font2str(plugin->getBaseFont(font()), false)); + }else{ + edtFont->setFont(data->value("Font").toString()); + } + chkShadow->setChecked(data->value("Shadow").toBool()); + chkFading->setChecked(data->value("Fading").toBool()); + if (data->value("Background").toBool()){ + chkBackground->setChecked(true); + btnBgColor->setColor(data->value("BgColor").toUInt()); + }else{ + chkBackground->setChecked(false); + } + bgToggled(data->value("Background").toBool()); + connect(chkBackground, SIGNAL(toggled(bool)), this, SLOT(bgToggled(bool))); + unsigned nScreens = screens(); + if (nScreens <= 1){ + lblScreen->hide(); + cmbScreen->hide(); + }else{ + for (unsigned i = 0; i < nScreens; i++) + cmbScreen->addItem(QString::number(i)); + unsigned curScreen = data->value("Screen").toUInt(); + if (curScreen >= nScreens) + curScreen = 0; + cmbScreen->setCurrentIndex(curScreen); + } +} + +void OSDIface::bgToggled(bool bState) +{ + if (bState){ + btnBgColor->setEnabled(true); + return; + } + btnBgColor->setColor(palette().color(QPalette::Base)); + btnBgColor->setEnabled(false); +} + +void OSDIface::apply(SIM::PropertyHubPtr data) +{ + data->setValue("Position", cmbPos->currentIndex()); + data->setValue("Offset", spnOffs->text().toUInt()); + data->setValue("Timeout", spnTimeout->text().toUInt()); + data->setValue("Color", btnColor->color().rgb()); + QString f = edtFont->getFont(); + QString base = FontEdit::font2str(m_plugin->getBaseFont(font()), false); + if (f == base) + f.clear(); + data->setValue("Font", f); + data->setValue("Shadow", chkShadow->isChecked()); + data->setValue("Fading", chkFading->isChecked()); + data->setValue("Background", chkBackground->isChecked()); + if (data->value("Background").toBool()){ + data->setValue("BgColor", btnBgColor->color().rgb()); + }else{ + data->setValue("BgColor", 0); + } + unsigned nScreens = screens(); + if (nScreens <= 1){ + data->setValue("Screen", 0); + }else{ + data->setValue("Screen", cmbScreen->currentIndex()); + } +} + diff --git a/plugins/osd/osdiface.h b/plugins/osd/osdiface.h new file mode 100644 index 0000000..d4ba25d --- /dev/null +++ b/plugins/osd/osdiface.h @@ -0,0 +1,40 @@ +/*************************************************************************** + osdiface.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _OSDIFACE_H +#define _OSDIFACE_H + +#include "ui_osdifacebase.h" +#include "propertyhub.h" + +class OSDPlugin; + +class OSDIface : public QWidget, public Ui::OSDIfaceBase +{ + Q_OBJECT +public: + OSDIface(QWidget *parent, SIM::PropertyHubPtr data, OSDPlugin *plugin); +public slots: + void apply(SIM::PropertyHubPtr data); +protected slots: + void bgToggled(bool); +protected: + OSDPlugin *m_plugin; +}; + +#endif + diff --git a/plugins/osd/osdifacebase.ui b/plugins/osd/osdifacebase.ui new file mode 100644 index 0000000..d375925 --- /dev/null +++ b/plugins/osd/osdifacebase.ui @@ -0,0 +1,201 @@ + + + OSDIfaceBase + + + + 0 + 0 + 375 + 330 + + + + Form2 + + + + 11 + + + 6 + + + + + Offset: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Show time: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Color: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + Font: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + Show sha&dow + + + + + + + Show F&ading + + + + + + + Show &background + + + + + + + Background color: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + Place: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Shown on screen: + + + false + + + + + + + + + + + FontEdit + QWidget +
simgui/fontedit.h
+
+ + QColorButton + QWidget +
simgui/qcolorbutton.h
+
+
+ + +
diff --git a/plugins/proxy/CMakeLists.txt b/plugins/proxy/CMakeLists.txt new file mode 100644 index 0000000..844ace7 --- /dev/null +++ b/plugins/proxy/CMakeLists.txt @@ -0,0 +1,28 @@ +################# +# proxy library # +################# +IF(BUILD_DROPPED) +PROJECT(proxy) + +SET(proxy_SRCS + proxy.cpp + proxycfg.cpp + proxyerror.cpp +) + +SET(proxy_HDRS + proxy.h + proxycfg.h + proxyerror.h +) + +SET(proxy_UICS + proxycfgbase.ui + proxyerrorbase.ui +) + +# some needed include dirs +INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR}/plugins/_core) + +SIM_ADD_PLUGIN(proxy) +ENDIF(BUILD_DROPPED) diff --git a/plugins/proxy/proxy.cpp b/plugins/proxy/proxy.cpp new file mode 100644 index 0000000..afd815f --- /dev/null +++ b/plugins/proxy/proxy.cpp @@ -0,0 +1,1311 @@ +/*************************************************************************** + proxy.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include + +#ifdef WIN32 +#include +#else +#include +#include +#include +#include +#include +#endif + +#include "fetch.h" +#include "log.h" +#include "misc.h" +#include "socket/socket.h" +#include "socket/serversocketnotify.h" +#include "socket/serversocket.h" +#include "socket/clientsocket.h" +#include "socket/tcpclient.h" +#include "socket/socketfactory.h" + +#include "proxy.h" +#include "proxycfg.h" +#include "newprotocol.h" +#include "proxyerror.h" + +using namespace std; +using namespace SIM; + +#ifndef INADDR_NONE +#define INADDR_NONE 0xFFFFFFFF +#endif + +static const char *CONNECT_ERROR = I18N_NOOP("Can't connect to proxy"); +static const char *ANSWER_ERROR = I18N_NOOP("Bad proxy answer"); +static const char *AUTH_ERROR = I18N_NOOP("Proxy authorization failed"); +static const char *STATE_ERROR = "Connect in bad state"; + +static DataDef _proxyData[] = + { + { "Client", DATA_STRING, 1, 0 }, + { "Clients", DATA_STRLIST, 1, 0 }, + { "Type", DATA_ULONG, 1, DATA(0) }, + { "Host", DATA_STRING, 1, "proxy" }, + { "Port", DATA_ULONG, 1, DATA(1080) }, + { "Auth", DATA_BOOL, 1, 0 }, + { "User", DATA_STRING, 1, 0 }, + { "Password", DATA_STRING, 1, 0 }, + { "", DATA_BOOL, 1, 0 }, + { "NoShow", DATA_BOOL, 1, 0 }, + { NULL, DATA_UNKNOWN, 0, 0 } + }; + +ProxyData::ProxyData() +{ + bInit = false; + load_data(_proxyData, this, NULL); +} + +ProxyData::ProxyData(const ProxyData &d) +{ + bInit = false; + *this = d; +} + +ProxyData::ProxyData(const char *cfg) +{ + bInit = false; + if (cfg) { + Buffer config; + config << "[Title]\n" << cfg; + config.setWritePos(0); + config.getSection(); + load_data(_proxyData, this, &config); + bInit = true; + }else{ + load_data(_proxyData, this, NULL); + } +} + +ProxyData::~ProxyData() +{ + if (bInit) + free_data(_proxyData, this); +} + +bool ProxyData::operator == (const ProxyData &d) const +{ + if (Type.toULong() != d.Type.toULong()) + return false; + if (Type.toULong() == PROXY_NONE) + return true; + if ((Port.toULong() != d.Port.toULong()) && (Host.str() != d.Host.str())) + return false; + if (Type.toULong() == PROXY_SOCKS4) + return true; + if (Auth.toBool() != d.Auth.toBool()) + return false; + if (!d.Auth.toBool()) + return true; + return ((User.str() == d.User.str()) && (Password.str() == d.Password.str())); +} + +ProxyData& ProxyData::operator = (const ProxyData &d) +{ + if (bInit){ + free_data(_proxyData, this); + bInit = false; + } + if (d.bInit){ + Buffer cfg; + cfg = "[Title]\n" + save_data(_proxyData, (void*)(&d)); + cfg.setWritePos(0); + cfg.getSection(); + load_data(_proxyData, this, &cfg); + bInit = true; + Default = d.Default; + }else{ + load_data(_proxyData, this, NULL); + } + + return *this; +} + +ProxyData& ProxyData::operator = (Buffer *cfg) +{ + if (bInit){ + free_data(_proxyData, this); + bInit = false; + } + load_data(_proxyData, this, cfg); + bInit = true; + return *this; +} + +class Proxy : public Socket, public SocketNotify +{ +public: + Proxy(ProxyPlugin *plugin, ProxyData *data, TCPClient *client); + ~Proxy(); + virtual int read(char *buf, unsigned int size); + virtual void write(const char *buf, unsigned int size); + void setSocket(ClientSocket*); + virtual void close(); + virtual unsigned long localHost(); + virtual void pause(unsigned); + virtual Mode mode() const { return Indirect; } + virtual bool isEncrypted(){ return false; } + virtual bool startEncryption(){ return false; } + PROP_ULONG(Type); + PROP_STR(Host); + PROP_USHORT(Port); + PROP_BOOL(Auth); + PROP_STR(User); + PROP_STR(Password); + PROP_BOOL(NoShow); + ProxyPlugin *m_plugin; +protected: + virtual void write(); + virtual void write_ready(); + virtual void error_state(const QString &text, unsigned code = 0); + virtual void proxy_connect_ready(); + void read(unsigned size, unsigned minsize=0); + bool m_bClosed; + TCPClient *m_client; + Socket *m_sock; + Buffer bOut; + Buffer bIn; + ProxyData data; + QString m_host; + unsigned short m_port; +}; + +class Listener : public SocketNotify, public ServerSocket +{ +public: + Listener(ProxyPlugin *plugin, ProxyData *data, ServerSocketNotify *notify, unsigned long ip); + ~Listener(); + PROP_ULONG(Type); + PROP_STR(Host); + PROP_USHORT(Port); + PROP_BOOL(Auth); + PROP_STR(User); + PROP_STR(Password); +protected: + virtual void write(); + virtual void write_ready(); + virtual void bind(unsigned short mixPort, unsigned short maxPort, TCPClient *client); +#ifndef WIN32 + virtual void bind(const char *path); +#endif + virtual void close(); + void read(unsigned size, unsigned minsize=0); + unsigned long m_ip; + Socket *m_sock; + ProxyData data; + ProxyPlugin *m_plugin; + Buffer bOut; + Buffer bIn; +}; + +Proxy::Proxy(ProxyPlugin *plugin, ProxyData *d, TCPClient *client) +{ + data = *d; + m_plugin = plugin; + m_sock = NULL; + m_client = client; + m_bClosed = false; + m_plugin->proxies.push_back(this); + bIn.packetStart(); + bOut.packetStart(); +} + +Proxy::~Proxy() +{ + if (notify) + static_cast(notify)->setSocket(m_sock); + if (m_sock) + delete m_sock; + for (list::iterator it = m_plugin->proxies.begin(); it != m_plugin->proxies.end(); ++it){ + if (*it == this){ + m_plugin->proxies.erase(it); + break; + } + } +} + +void Proxy::setSocket(ClientSocket *s) +{ + m_sock = s->socket(); + s->setSocket(this); + m_sock->setNotify(this); +} + +int Proxy::read(char*, unsigned int) +{ + return 0; +} + +void Proxy::write(const char*, unsigned int) +{ + log(L_WARN, "Proxy can't write"); + if (notify) + notify->error_state("Error proxy write"); +} + +void Proxy::close() +{ + if (m_bClosed) + return; + m_bClosed = true; + if (m_sock){ + m_sock->setNotify(notify); + m_sock->close(); + } +} + +unsigned long Proxy::localHost() +{ + return m_sock->localHost(); +} + +void Proxy::pause(unsigned n) +{ + m_sock->pause(n); +} + +void Proxy::write_ready() +{ +} + +void Proxy::error_state(const QString &err, unsigned code) +{ + if (notify){ + if (code == m_plugin->ProxyErr){ + if (getNoShow()){ + code = 0; + }else{ + if (m_client != (TCPClient*)(-1)) + m_client->m_reconnect = NO_RECONNECT; + } + } + notify->error_state(err, code); + } +} + +void Proxy::read(unsigned size, unsigned minsize) +{ + bIn.init(size); + bIn.packetStart(); + int readn = m_sock->read(bIn.data(0), size); + if ((readn != (int)size) || (minsize && (readn < (int)minsize))){ + if (notify) + notify->error_state("Error proxy read"); + return; + } + EventLog::log_packet(bIn, false, m_plugin->ProxyPacket); +} + +void Proxy::write() +{ + EventLog::log_packet(bOut, true, m_plugin->ProxyPacket); + m_sock->write(bOut.data(0), bOut.size()); + bOut.init(0); + bOut.packetStart(); +} + +void Proxy::proxy_connect_ready() +{ + if (notify){ + SocketNotify *n = notify; + static_cast(n)->setSocket(m_sock); + m_sock = NULL; + n->connect_ready(); + } + getSocketFactory()->remove(this); +} + +Listener::Listener(ProxyPlugin *plugin, ProxyData *_data, ServerSocketNotify *notify, unsigned long ip) +{ + m_ip = ip; + m_plugin = plugin; + m_sock = getSocketFactory()->createSocket(); + m_sock->setNotify(this); + data = *_data; + notify->setListener(this); +} + +Listener::~Listener() +{ + if (m_sock) + delete m_sock; +} + +void Listener::bind(unsigned short, unsigned short, TCPClient*) +{ +} + +#ifndef WIN32 + +void Listener::bind(const char*) +{ +} + +#endif + +void Listener::close() +{ +} + +void Listener::write() +{ + EventLog::log_packet(bOut, true, m_plugin->ProxyPacket); + m_sock->write(bOut.data(0), bOut.size()); + bOut.init(0); + bOut.packetStart(); +} + +void Listener::read(unsigned size, unsigned minsize) +{ + bIn.init(size); + bIn.packetStart(); + int readn = m_sock->read(bIn.data(0), size); + if ((readn != (int)size) || (minsize && (readn < (int)minsize))){ + if (notify && notify->error("Error proxy read")) + delete notify; + return; + } + EventLog::log_packet(bIn, false, m_plugin->ProxyPacket); +} + +void Listener::write_ready() +{ +} + +// ______________________________________________________________________________________ + +class SOCKS4_Proxy : public Proxy +{ +public: + SOCKS4_Proxy(ProxyPlugin *plugin, ProxyData *data, TCPClient *client); + virtual void connect(const QString &host, unsigned short port); +protected: + virtual void connect_ready(); + virtual void read_ready(); + virtual void error_state(const QString &text, unsigned code); + enum State + { + None, + Connect, + WaitConnect + }; + State m_state; +}; + +class SOCKS4_Listener : public Listener +{ +public: + SOCKS4_Listener(ProxyPlugin *plugin, ProxyData *data, ServerSocketNotify *notify, unsigned long ip); +protected: + virtual void connect_ready(); + virtual void read_ready(); + virtual void error_state(const QString &text, unsigned code = 0); + enum State + { + Connect, + WaitListen, + Accept + }; + State m_state; +}; + +SOCKS4_Proxy::SOCKS4_Proxy(ProxyPlugin *plugin, ProxyData *data, TCPClient *client) + : Proxy(plugin, data, client) +{ + m_state = None; +} + +void SOCKS4_Proxy::connect(const QString &host, unsigned short port) +{ + if (m_state != None){ + if (notify) notify->error_state(STATE_ERROR); + return; + } + m_host = host; + m_port = port; + log(L_DEBUG, "Connect to proxy SOCKS4 %s:%u", qPrintable(getHost()), getPort()); + m_sock->connect(getHost(), getPort()); + m_state = Connect; +} + +void SOCKS4_Proxy::error_state(const QString &text, unsigned code) +{ + if (m_state == Connect){ + Proxy::error_state(CONNECT_ERROR, m_plugin->ProxyErr); + return; + } + Proxy::error_state(text, code); +} + +void SOCKS4_Proxy::connect_ready() +{ + if (m_state != Connect){ + error_state(STATE_ERROR, 0); + return; + } + unsigned long addr = inet_addr(qPrintable(m_host)); + if (addr == INADDR_NONE){ + struct hostent *hp = gethostbyname(qPrintable(m_host)); + if (hp) addr = *((unsigned long*)(hp->h_addr_list[0])); + } + if (notify) + notify->resolve_ready(QHostAddress(addr)); + bOut + << (char)4 + << (char)1 + << m_port + << (unsigned long)htonl(addr) + << (char)0; + m_state = WaitConnect; +} + +void SOCKS4_Proxy::read_ready() +{ + if (m_state != WaitConnect) return; + read(9, 4); + char b1, b2; + bIn >> b1 >> b2; + if (b2 != 90){ + error_state(ANSWER_ERROR, m_plugin->ProxyErr); + return; + } + proxy_connect_ready(); +} + +SOCKS4_Listener::SOCKS4_Listener(ProxyPlugin *plugin, ProxyData *data, ServerSocketNotify *notify, unsigned long ip) + : Listener(plugin, data, notify, ip) +{ + log(L_DEBUG, "Connect to proxy SOCKS4 %s:%u", qPrintable(getHost()), getPort()); + m_sock->connect(getHost(), getPort()); + m_state = Connect; +} + +void SOCKS4_Listener::connect_ready() +{ + bOut + << (char)4 + << (char)2 + << (unsigned short)0 + << (unsigned long)m_ip + << (char)0; + m_state = WaitListen; +} + +void SOCKS4_Listener::read_ready() +{ + char b1, b2; + unsigned short port; + unsigned long ip; + switch (m_state){ + case WaitListen: + read(8); + bIn >> b1 >> b2; + if (b2 != 90){ + error_state("bad proxy answer", 0); + return; + } + bIn >> port; + m_state = Accept; + if (notify) + notify->bind_ready(port); + break; + case Accept: + read(8); + bIn >> b1 >> b2; + if (b2 != 90){ + error_state("bad proxy answer", 0); + return; + } + bIn >> port >> ip; + if (notify){ + notify->accept(m_sock, ip); + m_sock = NULL; + }else{ + error_state("Bad state", 0); + } + break; + default: + break; + } +} + +void SOCKS4_Listener::error_state(const QString &err, unsigned) +{ + if (notify) + notify->error(err); +} + +// ______________________________________________________________________________________ + +class SOCKS5_Proxy : public Proxy +{ +public: + SOCKS5_Proxy(ProxyPlugin*, ProxyData*, TCPClient*); + virtual void connect(const QString &host, unsigned short port); +protected: + virtual void connect_ready(); + virtual void read_ready(); + virtual void error_state(const QString &text, unsigned code); + enum State + { + None, + Connect, + WaitAnswer, + WaitAuth, + WaitConnect + }; + State m_state; + void send_connect(); +}; + +class SOCKS5_Listener : public Listener +{ +public: + SOCKS5_Listener(ProxyPlugin *plugin, ProxyData *data, ServerSocketNotify *notify, unsigned long ip); +protected: + virtual void connect_ready(); + virtual void read_ready(); + virtual void error_state(const QString &text, unsigned code = 0); + void send_listen(); + enum State + { + Connect, + WaitAnswer, + WaitAuth, + WaitListen, + Accept + }; + State m_state; +}; + +SOCKS5_Proxy::SOCKS5_Proxy(ProxyPlugin *plugin, ProxyData *d, TCPClient *client) + : Proxy(plugin, d, client) +{ + m_state = None; +} + +void SOCKS5_Proxy::connect(const QString &host, unsigned short port) +{ + if (m_state != None){ + error_state(STATE_ERROR, 0); + return; + } + m_host = host; + m_port = port; + log(L_DEBUG, "Connect to proxy SOCKS5 %s:%u", qPrintable(getHost()), getPort()); + m_sock->connect(getHost(), getPort()); + m_state = Connect; +} + +void SOCKS5_Proxy::connect_ready() +{ + if (m_state != Connect){ + error_state(STATE_ERROR, 0); + return; + } + bOut << 0x05020002L; + m_state = WaitAnswer; + write(); +} + +void SOCKS5_Proxy::read_ready() +{ + char b1, b2; + unsigned long ip; + switch (m_state){ + case WaitAnswer: + read(2); + bIn >> b1 >> b2; + if ((b1 != 0x05) || (b2 == '\xFF')) { + error_state(ANSWER_ERROR, m_plugin->ProxyErr); + return; + } + if (b2 == 0x02) { + const QByteArray user = getUser().toUtf8(); + const QByteArray pswd = getPassword().toUtf8(); + bOut + << (char)0x01 + << (char)user.length() + << user.data() + << (char)pswd.length() + << pswd.data(); + m_state = WaitAuth; + write(); + return; + } + send_connect(); + return; + case WaitAuth: + read(2); + bIn >> b1 >> b2; + if ((b1 != 0x01) || (b2 != 0x00)) { + error_state(AUTH_ERROR, m_plugin->ProxyErr); + return; + } + send_connect(); + return; + case WaitConnect: + read(10); + bIn >> b1 >> b2; + if ((b1 != 0x05) || (b2 != 0x00)) { + error_state(ANSWER_ERROR, m_plugin->ProxyErr); + return; + } + bIn >> b1 >> b2; + bIn >> ip; + if (notify) + notify->resolve_ready(QHostAddress(ip)); + proxy_connect_ready(); + return; + default: + break; + } +} + +void SOCKS5_Proxy::error_state(const QString &text, unsigned code) +{ + if (m_state == Connect){ + Proxy::error_state(CONNECT_ERROR, m_plugin->ProxyErr); + return; + } + Proxy::error_state(text, code); +} + +void SOCKS5_Proxy::send_connect() +{ + unsigned long addr = inet_addr(qPrintable(m_host)); + bOut << (char)0x05 + << (char)0x01 /* CONNECT */ + << (char)0x00; /* reserved */ + if (addr != INADDR_NONE){ + bOut << (char)0x01 /* address type -- ip addr */ + << (unsigned long)htonl(addr); + }else{ + bOut << (char)0x03 /* address type -- host name */ + << (char)m_host.length(); + const QByteArray ba = m_host.toLocal8Bit(); + bOut.pack(ba.data(), ba.length()); + } + bOut << m_port; + m_state = WaitConnect; + write(); +} + +SOCKS5_Listener::SOCKS5_Listener(ProxyPlugin *plugin, ProxyData *data, ServerSocketNotify *notify, unsigned long ip) + : Listener(plugin, data, notify, ip) +{ + log(L_DEBUG, "Connect to proxy SOCKS5 %s:%u", qPrintable(getHost()), getPort()); + m_sock->connect(getHost(), getPort()); + m_state = Connect; +} + +void SOCKS5_Listener::connect_ready() +{ + if (m_state != Connect){ + error_state(STATE_ERROR, 0); + return; + } + bOut << 0x05020002L; + m_state = WaitAnswer; + write(); +} + +void SOCKS5_Listener::read_ready() +{ + char b1, b2; + unsigned short port; + unsigned long ip; + switch (m_state){ + case WaitAnswer: + read(2); + bIn >> b1 >> b2; + if ((b1 != 0x05) || (b2 == '\xFF')) { + error_state(ANSWER_ERROR, m_plugin->ProxyErr); + return; + } + if (b2 == 0x02) { + const QByteArray user = getUser().toUtf8(); + const QByteArray pswd = getPassword().toUtf8(); + bOut + << (char)0x01 + << (char)user.length() + << user.data() + << (char)pswd.length() + << pswd.data(); + m_state = WaitAuth; + write(); + return; + } + send_listen(); + return; + case WaitAuth: + read(2); + bIn >> b1 >> b2; + if ((b1 != 0x01) || (b2 != 0x00)) { + error_state(AUTH_ERROR, m_plugin->ProxyErr); + return; + } + send_listen(); + return; + case WaitListen: + read(10); + bIn >> b1 >> b2; + if ((b1 != 0x05) || (b2 != 0x00)) { + error_state(AUTH_ERROR, m_plugin->ProxyErr); + return; + } + bIn >> b1 >> b2; + bIn >> ip; + bIn >> port; + m_state = Accept; + if (notify) + notify->bind_ready(port); + return; + case Accept: + read(10); + bIn >> b1 >> b2; + if ((b1 != 0x05) || (b2 != 0x02)) { + error_state("Bad accept code", 0); + return; + } + bIn >> b1 >> b2; + bIn >> ip; + if (notify){ + notify->accept(m_sock, ip); + m_sock = NULL; + }else{ + error_state("Bad accept code", 0); + return; + } + return; + default: + break; + } +} + +void SOCKS5_Listener::send_listen() +{ + bOut << 0x05020001L << m_ip << (unsigned short)0; + write(); + m_state = WaitListen; +} + +void SOCKS5_Listener::error_state(const QString &err, unsigned) +{ + if (notify) + notify->error(err); +} + +// ______________________________________________________________________________________ + +class HTTPS_Proxy : public Proxy +{ +public: + HTTPS_Proxy(ProxyPlugin *plugin, ProxyData*, TCPClient *client); + virtual void connect(const QString &host, unsigned short port); +protected: + virtual void connect_ready(); + virtual void read_ready(); + void error_state(const QString &text, unsigned code); + void send_auth(); + enum State + { + None, + Connect, + WaitConnect, + WaitEmpty + }; + State m_state; + bool readLine(QByteArray &s); +}; + +HTTPS_Proxy::HTTPS_Proxy(ProxyPlugin *plugin, ProxyData *d, TCPClient *client) + : Proxy(plugin, d, client) +{ + m_state = None; +} + +void HTTPS_Proxy::connect(const QString &host, unsigned short port) +{ + if (m_state != None){ + error_state(STATE_ERROR, 0); + return; + } + m_host = host; + m_port = port; + if ((m_client != (TCPClient*)(-1)) && (m_client->protocol()->description()->flags & PROTOCOL_ANY_PORT)) + m_port = 443; + log(L_DEBUG, "Connect to proxy HTTPS %s:%u", qPrintable(getHost()), getPort()); + m_sock->connect(getHost(), getPort()); + m_state = Connect; +} + +void HTTPS_Proxy::connect_ready() +{ + if (m_state != Connect){ + log(L_WARN, "Proxy::connect_ready in bad state"); + error_state(CONNECT_ERROR, 0); + return; + } + bIn.packetStart(); + bOut << "CONNECT " + << qPrintable(m_host) + << ":" + << QByteArray::number(m_port).data() + << " HTTP/1.0\r\n" + << "User-Agent: " + << qPrintable(get_user_agent()) + << "\r\n"; + send_auth(); + bOut << "\r\n"; + m_state = WaitConnect; + write(); +} + +static char HTTP[] = "HTTP/"; + +void HTTPS_Proxy::send_auth() +{ + if (getAuth()){ + QByteArray s = basic_auth(getUser(), getPassword()); + bOut << "Proxy-Authorization: Basic "; + bOut << s.constData(); + bOut << "\r\n"; + } +} + +void HTTPS_Proxy::error_state(const QString &text, unsigned code) +{ + if (m_state == Connect){ + Proxy::error_state(CONNECT_ERROR, m_plugin->ProxyErr); + return; + } + Proxy::error_state(text, code); +} + +void HTTPS_Proxy::read_ready() +{ + if (m_state == WaitConnect){ + QByteArray s; + if (!readLine(s)) + return; + if ((unsigned)s.length() < strlen(HTTP)){ + error_state(ANSWER_ERROR, m_plugin->ProxyErr); + return; + } + int idx = s.indexOf(' '); + if (idx == -1){ + error_state(ANSWER_ERROR, m_plugin->ProxyErr); + return; + } + s = s.mid(idx + 1); + idx = s.indexOf(' '); + if (idx!=-1) + s=s.left(idx+1); + int code = s.toInt(); + if (code == 407){ + error_state(AUTH_ERROR, m_plugin->ProxyErr); + return; + } + if (code != 200){ + error_state(ANSWER_ERROR, m_plugin->ProxyErr); + return; + } + m_state = WaitEmpty; + } + if (m_state == WaitEmpty){ + for (;;){ + QByteArray s; + if (!readLine(s)) + return; + if (s.length() == 0) + break; + } + proxy_connect_ready(); + } +} + +bool HTTPS_Proxy::readLine(QByteArray &s) +{ + for (;;){ + char c; + int n = m_sock->read(&c, 1); + if (n < 0){ + error_state(ANSWER_ERROR, m_plugin->ProxyErr); + return false; + } + if (n == 0) + return false; + if (c == '\r') + continue; + if (c == '\n') + break; + bIn << c; + } + bIn << '\0'; + EventLog::log_packet(bIn, false, m_plugin->ProxyPacket); + if(bIn.size()) + s = bIn; + bIn.init(0); + bIn.packetStart(); + return true; +} + +// ______________________________________________________________________________________ + +class HTTP_Proxy : public HTTPS_Proxy +{ +public: + HTTP_Proxy(ProxyPlugin *plugin, ProxyData*, TCPClient *client); + void connect(const QString &host, unsigned short port); +protected: + virtual void write(const char *buf, unsigned int size); + virtual int read(char *buf, unsigned int size); + void read_ready(); + void write_ready(); + void connect_ready(); + enum State + { + WaitHeader, + Headers, + Data + }; + State m_state; + Buffer m_out; + bool m_bHTTP; + unsigned m_size; + QByteArray m_head; +}; + +HTTP_Proxy::HTTP_Proxy(ProxyPlugin *plugin, ProxyData *data, TCPClient *client) + : HTTPS_Proxy(plugin, data, client) +{ + m_bHTTP = true; + m_state = WaitHeader; + m_size = 0; +} + +void HTTP_Proxy::read_ready() +{ + if (!m_bHTTP){ + HTTPS_Proxy::read_ready(); + return; + } + if (!m_head.isEmpty()) + return; + if (!readLine(m_head)) + return; + if ((unsigned)m_head.length() < strlen(HTTP)){ + error_state(ANSWER_ERROR, m_plugin->ProxyErr); + return; + } + int idx = m_head.indexOf(' '); + if (idx == -1){ + error_state(ANSWER_ERROR, m_plugin->ProxyErr); + return; + } + QByteArray str = m_head.mid(idx + 1); + int code = str.toInt(); + if (code == 407){ + error_state(AUTH_ERROR, m_plugin->ProxyErr); + return; + } + m_head += "\r\n"; + if (notify) + notify->read_ready(); +} + +void HTTP_Proxy::connect(const QString &host, unsigned short port) +{ + if (port == 443) + m_bHTTP = false; + HTTPS_Proxy::connect(host, port); +} + +void HTTP_Proxy::connect_ready() +{ + if (!m_bHTTP){ + HTTPS_Proxy::connect_ready(); + return; + } + bIn.packetStart(); + if (notify) + notify->connect_ready(); +} + +void HTTP_Proxy::write_ready() +{ + if ((m_state == Data) && notify) + notify->write_ready(); +} + +int HTTP_Proxy::read(char *buf, unsigned int size) +{ + if (!m_bHTTP) + return HTTPS_Proxy::read(buf, size); + if (m_head.isEmpty()) + return 0; + if (size > (unsigned)m_head.length()) + size = m_head.length(); + memcpy(buf, m_head.data(), size); + m_head = m_head.mid(size); + if (m_head.isEmpty()){ + static_cast(notify)->setSocket(m_sock); + m_sock = NULL; + getSocketFactory()->remove(this); + } + return size; +} + +void HTTP_Proxy::write(const char *buf, unsigned int size) +{ + if (!m_bHTTP){ + HTTPS_Proxy::write(buf, size); + return; + } + if (m_state == Data){ + unsigned out_size = size; + if (out_size > m_size) + out_size = m_size; + if (out_size == 0) + return; + bOut.pack(buf, out_size); + m_size -= out_size; + HTTPS_Proxy::write(); + return; + } + m_out.pack(buf, size); + QByteArray line; + if (m_state == WaitHeader){ + if (!m_out.scan("\r\n", line)) + return; + bOut + << getToken(line, ' ', false).data() + << " http://" + << qPrintable(m_host); + if (m_port != 80) + bOut << ":" << QByteArray::number(m_port).data(); + bOut << getToken(line, ' ', false).data(); + bOut << " HTTP/1.1\r\n"; + m_state = Headers; + } + if (m_state == Headers){ + for (;;){ + if (!m_out.scan("\r\n", line)){ + HTTPS_Proxy::write(); + return; + } + if (line.isEmpty()) + break; + QByteArray param = getToken(line, ':'); + if (param == "Content-Length"){ + QByteArray p = line.trimmed(); + m_size = p.toUInt(); + } + bOut << param.data() << ":" << line.data() << "\r\n"; + } + send_auth(); + bOut << "\r\n"; + if (m_out.readPos() < m_out.writePos()){ + unsigned out_size = m_out.writePos() - m_out.readPos(); + if (out_size > m_size) + out_size = m_size; + bOut.pack(m_out.data(m_out.readPos()), out_size); + m_size -= out_size; + } + m_out.init(0); + m_state = Data; + HTTPS_Proxy::write(); + } +} + +// ______________________________________________________________________________________ + + +Plugin *createProxyPlugin(unsigned base, bool, Buffer *config) +{ + Plugin *plugin = new ProxyPlugin(base, config); + return plugin; +} + +static PluginInfo info = + { + I18N_NOOP("Proxy"), + I18N_NOOP("Plugin provides proxy support (SOCKS4, SOCKS5, HTTPS/HTTP)"), + VERSION, + createProxyPlugin, + PLUGIN_DEFAULT + }; + +EXPORT_PROC PluginInfo* GetPluginInfo() +{ + return &info; +} + +ProxyPlugin::ProxyPlugin(unsigned base, Buffer *config) + : Plugin(base) +{ + data = config; + ProxyPacket = registerType(); + ProxyErr = registerType(); + getContacts()->addPacketType(ProxyPacket, info.title); +} + +ProxyPlugin::~ProxyPlugin() +{ + while (proxies.size()){ + delete proxies.front(); + } + getContacts()->removePacketType(ProxyPacket); +} + +QString ProxyPlugin::clientName(TCPClient *client) +{ + if (client == (TCPClient*)(-1)) + return "HTTP"; + return static_cast(client)->name(); +} + +void ProxyPlugin::clientData(TCPClient *client, ProxyData &cdata) +{ + for(unsigned i = 1;; i++) + { + const QString proxyCfg = getClients(i); + if (proxyCfg.isEmpty()) + break; + ProxyData wdata(qPrintable(proxyCfg)); + if (clientName(client) == wdata.Client.str()) + { + cdata = wdata; + cdata.Default.asBool() = false; + cdata.Client.str() = clientName(client); + return; + } + } + cdata = data; + cdata.Client.str() = clientName(client); + cdata.Default.asBool() = true; + cdata.Clients.clear(); +} + +bool ProxyPlugin::processEvent(Event *e) +{ + switch (e->type()) { + case eEventSocketConnect: { + EventSocketConnect *esc = static_cast(e); + list::iterator it; + for (it = proxies.begin(); it != proxies.end(); ++it){ + if ((*it)->getNotify() == esc->socket()) + return false; + } + ProxyData data; + clientData(esc->client(), data); + Proxy *proxy = NULL; + switch (data.Type.toULong()){ + case PROXY_SOCKS4: + proxy = new SOCKS4_Proxy(this, &data, esc->client()); + break; + case PROXY_SOCKS5: + proxy = new SOCKS5_Proxy(this, &data, esc->client()); + break; + case PROXY_HTTPS: + if (esc->client() == (TCPClient*)(-1)){ + proxy = new HTTP_Proxy(this, &data, esc->client()); + }else{ + proxy = new HTTPS_Proxy(this, &data, esc->client()); + } + break; + } + if (proxy){ + proxy->setSocket(esc->socket()); + return true; + } + break; + } + case eEventSocketListen: { + EventSocketListen *esl = static_cast(e); + ProxyData data; + clientData(esl->client(), data); + Listener *listener = NULL; + switch (data.Type.toULong()) + { + case PROXY_SOCKS4: + listener = new SOCKS4_Listener(this, &data, esl->notify(), esl->client()->ip()); + break; + case PROXY_SOCKS5: + listener = new SOCKS5_Listener(this, &data, esl->notify(), esl->client()->ip()); + break; + } + if (listener) + return true; + break; + } + case eEventRaiseWindow: { + EventRaiseWindow *win = static_cast(e); + QWidget *w = win->widget(); + if (!w || !w->inherits("NewProtocol")) + return false; + NewProtocol *p = static_cast(w); + if (p->m_client->protocol()->description()->flags & PROTOCOL_NOPROXY) + return false; + ProxyConfig *cfg = w->findChild(); + if (cfg) + return false; + QTabWidget *tab = w->findChild(); + if (tab){ + cfg = new ProxyConfig(tab, this, tab, p->m_client); + QObject::connect(tab->topLevelWidget(), SIGNAL(apply()), cfg, SLOT(apply())); + } + break; + } + case eEventClientNotification: { + EventClientNotification *ee = static_cast(e); + const EventNotification::ClientNotificationData &data = ee->data(); + if (data.code == ProxyErr){ + QString msg; + if (!data.text.isEmpty()) + msg = i18n(data.text).arg(data.args); + ProxyError *err = new ProxyError(this, static_cast(data.client), msg); + raiseWindow(err); + return true; + } + break; + } + default: + break; + } + return false; +} + +QByteArray ProxyPlugin::getConfig() +{ + return save_data(_proxyData, &data); +} + +QWidget *ProxyPlugin::createConfigWindow(QWidget *parent) +{ + return new ProxyConfig(parent, this, NULL, static_cast (NULL)); +} + +const DataDef *ProxyPlugin::proxyData = _proxyData; diff --git a/plugins/proxy/proxy.h b/plugins/proxy/proxy.h new file mode 100644 index 0000000..6c73172 --- /dev/null +++ b/plugins/proxy/proxy.h @@ -0,0 +1,87 @@ +/*************************************************************************** + proxy.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _PROXY_H +#define _PROXY_H + +#include + +#include "cfg.h" +#include "event.h" +#include "plugins.h" +#include + +using namespace std; + +const unsigned PROXY_NONE = 0; +const unsigned PROXY_SOCKS4 = 1; +const unsigned PROXY_SOCKS5 = 2; +const unsigned PROXY_HTTPS = 3; + +struct ProxyData +{ + SIM::Data Client; + SIM::Data Clients; + SIM::Data Type; + SIM::Data Host; + SIM::Data Port; + SIM::Data Auth; + SIM::Data User; + SIM::Data Password; + SIM::Data Default; + SIM::Data NoShow; + bool bInit; + ProxyData(); + ProxyData(const ProxyData&); + ProxyData(const char *cfg); + ~ProxyData(); + bool operator == (const ProxyData&) const; + ProxyData& operator = (const ProxyData&); + ProxyData& operator = (Buffer *cfg); +}; + +class Proxy; +class Listener; + +class ProxyPlugin : public SIM::Plugin, public SIM::EventReceiver +{ +public: + ProxyPlugin(unsigned, Buffer*); + virtual ~ProxyPlugin(); + PROP_STRLIST(Clients); + PROP_ULONG(Type); + PROP_STR(Host); + PROP_USHORT(Port); + PROP_BOOL(Auth); + PROP_BOOL(NoShow); + PROP_STR(User); + PROP_STR(Password); + unsigned ProxyPacket; + list proxies; + ProxyData data; + void clientData(SIM::TCPClient*, ProxyData &data); + static const SIM::DataDef *proxyData; + unsigned ProxyErr; + QString clientName(SIM::TCPClient *client); +protected: + virtual bool processEvent(SIM::Event *e); + virtual QWidget *createConfigWindow(QWidget *parent); + virtual QByteArray getConfig(); +}; + +#endif + diff --git a/plugins/proxy/proxy.rc b/plugins/proxy/proxy.rc new file mode 100644 index 0000000..5081022 --- /dev/null +++ b/plugins/proxy/proxy.rc @@ -0,0 +1,97 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,9,6,0 + PRODUCTVERSION 0,9,6,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Vladimir Shutoff\0" + VALUE "FileDescription", "Proxy plugin\0" + VALUE "FileVersion", "0, 9, 6, 0\0" + VALUE "InternalName", "proxy\0" + VALUE "LegalCopyright", "Copyright © 2002-2003\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "proxy.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "SIM\0" + VALUE "ProductVersion", "0, 9, 6, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/proxy/proxy.vcproj b/plugins/proxy/proxy.vcproj new file mode 100644 index 0000000..d430bea --- /dev/null +++ b/plugins/proxy/proxy.vcproj @@ -0,0 +1,451 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/proxy/proxycfg.cpp b/plugins/proxy/proxycfg.cpp new file mode 100644 index 0000000..fe62e1a --- /dev/null +++ b/plugins/proxy/proxycfg.cpp @@ -0,0 +1,245 @@ +/*************************************************************************** + proxycfg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "icons.h" +#include "misc.h" +#include "socket/socket.h" +#include "socket/tcpclient.h" +#include "fetch.h" + +#include "proxycfg.h" +#include "proxy.h" + +using namespace SIM; + +ProxyConfig::ProxyConfig(QWidget *parent, ProxyPlugin *plugin, QTabWidget *tab, ClientPtr client) + : QWidget(parent) + , m_client(client) + , m_plugin(plugin) + , m_current(~0U) +{ + setupUi(this); + cmbType->addItem(i18n("None")); + cmbType->addItem("SOCKS4"); + cmbType->addItem("SOCKS5"); + cmbType->addItem("HTTP/HTTPS"); + if (tab){ + tab->addTab(this, i18n("&Proxy")); + for (QWidget *p = this; p; p = p->parentWidget()){ + QSize s = p->sizeHint(); + QSize s1 = QSize(p->width(), p->height()); + p->setMinimumSize(s); + p->resize(qMax(s.width(), s1.width()), qMax(s.height(), s1.height())); + if (p->layout()) + p->layout()->invalidate(); + if (p == topLevelWidget()) + break; + } + } + connect(cmbType, SIGNAL(activated(int)), this, SLOT(typeChanged(int))); + connect(chkAuth, SIGNAL(toggled(bool)), this, SLOT(authToggled(bool))); + if (m_client){ + lblClient->hide(); + cmbClient->hide(); + ProxyData data; + plugin->clientData(static_cast(m_client.data()), data); + fill(&data); + }else{ + fillClients(); + connect(cmbClient, SIGNAL(activated(int)), this, SLOT(clientChanged(int))); + clientChanged(0); + } +} + +void ProxyConfig::apply() +{ + if (m_client){ + ProxyData nd(NULL); + get(&nd); + nd.Client.str() = QString::null; + if (getContacts()->nClients() <= 1){ + m_plugin->clearClients(); + m_plugin->data = nd; + return; + } + ProxyData d; + m_plugin->clientData(static_cast(m_client.data()), d); + m_data.clear(); + if (d.Default.toBool()){ + d = nd; + }else{ + d = m_plugin->data; + } + m_data.push_back(d); + for (unsigned i = 0; i < getContacts()->nClients(); i++){ + Client *client = getContacts()->getClient(i); + if (client == m_client){ + nd.Client.str() = m_client->name(); + m_data.push_back(nd); + }else{ + ProxyData d; + m_plugin->clientData(static_cast(client), d); + m_data.push_back(d); + } + } + }else{ + clientChanged(0); + } + m_plugin->data = m_data[0]; + m_plugin->clearClients(); + unsigned nClient = 1; + for (unsigned i = 1; i < m_data.size(); i++){ + if (m_data[i] == m_data[0]) + continue; + m_plugin->setClients(nClient++, save_data(ProxyPlugin::proxyData, &m_data[i])); + } +} + +void ProxyConfig::typeChanged(int type) +{ + if (type){ + edtHost->show(); + edtPort->show(); + lblHost->show(); + lblPort->show(); + }else{ + edtHost->hide(); + edtPort->hide(); + lblHost->hide(); + lblPort->hide(); + } + if (type > 1){ + chkAuth->show(); + edtUser->show(); + edtPswd->show(); + lblUser->show(); + lblPswd->show(); + }else{ + chkAuth->hide(); + edtUser->hide(); + edtPswd->hide(); + lblUser->hide(); + lblPswd->hide(); + } + authToggled(chkAuth->isChecked()); +} + +void ProxyConfig::authToggled(bool bState) +{ + edtUser->setEnabled(bState); + edtPswd->setEnabled(bState); + lblUser->setEnabled(bState); + lblPswd->setEnabled(bState); +} + +void ProxyConfig::clientChanged(int) +{ + if (m_current < m_data.size()){ + get(&m_data[m_current]); + if (m_current == 0){ + for (unsigned i = 1; i < m_data.size(); i++){ + if (m_data[i].Default.toBool()){ + QString client = m_data[i].Client.str(); + m_data[i] = m_data[0]; + m_data[i].Default.asBool() = true; + m_data[i].Client.str() = client; + }else{ + if (m_data[i] == m_data[0]) + m_data[i].Default.asBool() = true; + } + } + }else{ + ProxyData &d = m_data[m_current]; + d.Default.asBool() = (d == m_data[0]); + } + } + m_current = cmbClient->currentIndex(); + if (m_current < m_data.size()) + fill(&m_data[m_current]); +} + +bool ProxyConfig::processEvent(Event *e) +{ + if ((m_client == NULL) && (e->type() == eEventClientsChanged)) + fillClients(); + return false; +} + +void ProxyConfig::fillClients() +{ + m_current = (unsigned)(-1); + m_data.clear(); + cmbClient->clear(); + cmbClient->insertItem(INT_MAX,i18n("Default")); + ProxyData d(m_plugin->data); + d.Clients.clear(); + m_data.push_back(d); + for (unsigned i = 0; i < getContacts()->nClients(); i++){ + Client *client = getContacts()->getClient(i); + if (client->protocol()->description()->flags & PROTOCOL_NOPROXY) + continue; + QString name = client->name(); + int pos = name.indexOf("."); + if (pos > 0) + name = name.replace(pos, 1, " "); + cmbClient->addItem(Icon(client->protocol()->description()->icon), name); + ProxyData d; + m_plugin->clientData(static_cast(client), d); + m_data.push_back(d); + } + bool bState; + if (!get_connection_state(bState)){ + cmbClient->insertItem(INT_MAX,i18n("HTTP requests"));; + ProxyData d; + m_plugin->clientData((TCPClient*)(-1), d); + m_data.push_back(d); + } + clientChanged(0); +} + +void ProxyConfig::fill(ProxyData *data) +{ + cmbType->setCurrentIndex(data->Type.toULong()); + edtHost->setText(data->Host.str()); + edtPort->setValue(data->Port.toULong()); + chkAuth->setChecked(data->Auth.toBool()); + edtUser->setText(data->User.str()); + edtPswd->setText(data->Password.str()); + typeChanged(data->Type.toULong()); + chkNoShow->setChecked(data->NoShow.toBool()); +} + +void ProxyConfig::get(ProxyData *data) +{ + data->Type.asULong() = cmbType->currentIndex(); + data->Host.str() = edtHost->text(); + data->Port.asULong() = edtPort->text().toULong(); + data->Auth.asBool() = chkAuth->isChecked(); + data->User.str() = edtUser->text(); + data->Password.str() = edtPswd->text(); + data->NoShow.asBool()= chkNoShow->isChecked(); + data->bInit = true; +} diff --git a/plugins/proxy/proxycfg.h b/plugins/proxy/proxycfg.h new file mode 100644 index 0000000..517105d --- /dev/null +++ b/plugins/proxy/proxycfg.h @@ -0,0 +1,53 @@ +/*************************************************************************** + proxycfg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _PROXYCFG_H +#define _PROXYCFG_H + +#include "contacts/client.h" +#include "proxy.h" +#include "ui_proxycfgbase.h" + +#include + +class ProxyPlugin; +class QTabWidget; + +class ProxyConfig : public QWidget, public Ui::ProxyConfigBase, public SIM::EventReceiver +{ + Q_OBJECT +public: + ProxyConfig(QWidget *parent, ProxyPlugin *plugin, QTabWidget *tab, SIM::ClientPtr client); +public slots: + void apply(); +protected slots: + void clientChanged(int client); + void typeChanged(int type); + void authToggled(bool auth); +protected: + virtual bool processEvent(SIM::Event *e); + void fillClients(); + void fill(ProxyData*); + void get(ProxyData*); + std::vector m_data; + SIM::ClientPtr m_client; + ProxyPlugin *m_plugin; + unsigned m_current; +}; + +#endif + diff --git a/plugins/proxy/proxycfgbase.ui b/plugins/proxy/proxycfgbase.ui new file mode 100644 index 0000000..ede61b3 --- /dev/null +++ b/plugins/proxy/proxycfgbase.ui @@ -0,0 +1,189 @@ + + + ProxyConfigBase + + + + 0 + 0 + 331 + 267 + + + + Form1 + + + + 11 + + + 6 + + + + + Host: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Port: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + 1 + + + 65535 + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + Proxy require &authorization + + + + + + + User: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Password: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + QLineEdit::Password + + + + + + + Proxy type: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Client: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + Do not show error dialog (automatically reconnect) + + + + + + + cmbClient + cmbType + edtHost + edtPort + chkAuth + edtUser + edtPswd + + + + diff --git a/plugins/proxy/proxyerror.cpp b/plugins/proxy/proxyerror.cpp new file mode 100644 index 0000000..8f896c7 --- /dev/null +++ b/plugins/proxy/proxyerror.cpp @@ -0,0 +1,79 @@ +/*************************************************************************** + proxyerror.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include +#include + +#include "icons.h" +#include "misc.h" + +#include "proxyerror.h" +#include "proxycfg.h" +#include "socket/tcpclient.h" + +using namespace SIM; + +ProxyError::ProxyError(ProxyPlugin *plugin, TCPClient *client, const QString& msg) + : QDialog(NULL) + , m_plugin(plugin) + , m_client(client) +{ + setupUi(this); + setModal(false); + setAttribute(Qt::WA_DeleteOnClose); + setWindowIcon(Icon("error")); + setButtonsPict(this); + lblMessage->setText(msg); + if (layout() && layout()->inherits("QBoxLayout")){ + QBoxLayout *lay = static_cast(layout()); + ProxyConfig *cfg = new ProxyConfig(this, m_plugin, NULL, static_cast (m_client)); + lay->insertWidget(1, cfg); + cfg->show(); + setMinimumSize(sizeHint()); + connect(this, SIGNAL(apply()), cfg, SLOT(apply())); + } +} + +ProxyError::~ProxyError() +{ + if (m_client && (m_client->getState() == Client::Error)) + m_client->setStatus(STATUS_OFFLINE, false); +} + +bool ProxyError::processEvent(Event *e) +{ + if (e->type() == eEventClientsChanged){ + for (unsigned i = 0; i < getContacts()->nClients(); i++){ + if (getContacts()->getClient(i) == m_client) + return false; + } + m_client = NULL; + close(); + } + return false; +} + +void ProxyError::accept() +{ + if (m_client){ + emit apply(); + m_client->setStatus(m_client->getManualStatus(), m_client->getCommonStatus()); + } + QDialog::accept(); +} diff --git a/plugins/proxy/proxyerror.h b/plugins/proxy/proxyerror.h new file mode 100644 index 0000000..6f28ded --- /dev/null +++ b/plugins/proxy/proxyerror.h @@ -0,0 +1,43 @@ +/*************************************************************************** + proxyerror.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _PROXYERROR_H +#define _PROXYERROR_H + +#include "socket/socket.h" +#include "ui_proxyerrorbase.h" + +class ProxyConfig; +class ProxyPlugin; + +class ProxyError : public QDialog, public Ui::ProxyErrorBase, public SIM::EventReceiver +{ + Q_OBJECT +public: + ProxyError(ProxyPlugin *plugin, SIM::TCPClient *client, const QString& msg); + ~ProxyError(); +signals: + void apply(); +protected: + virtual bool processEvent(SIM::Event *e); + virtual void accept(); + ProxyPlugin *m_plugin; + SIM::TCPClient *m_client; +}; + +#endif + diff --git a/plugins/proxy/proxyerrorbase.ui b/plugins/proxy/proxyerrorbase.ui new file mode 100644 index 0000000..1248085 --- /dev/null +++ b/plugins/proxy/proxyerrorbase.ui @@ -0,0 +1,129 @@ + + + ProxyErrorBase + + + + 0 + 0 + 450 + 87 + + + + Proxy error + + + true + + + + + + + 0 + 0 + + + + + 75 + true + + + + + + + false + + + + + + + 6 + + + 0 + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + &OK + + + true + + + true + + + + + + + &Cancel + + + true + + + + + + + + qPixmapFromMimeSource + + + + buttonOk + clicked() + ProxyErrorBase + accept() + + + 20 + 20 + + + 20 + 20 + + + + + buttonCancel + clicked() + ProxyErrorBase + reject() + + + 20 + 20 + + + 20 + 20 + + + + + diff --git a/plugins/remote/CMakeLists.txt b/plugins/remote/CMakeLists.txt new file mode 100644 index 0000000..da4d2d0 --- /dev/null +++ b/plugins/remote/CMakeLists.txt @@ -0,0 +1,78 @@ +################## +# remote library # +################## +IF(BUILD_DROPPED) +PROJECT(remote) + +SET(remote_LIB_SRCS + remote.cpp + remotecfg.cpp +) + +SET(remote_LIB_HDRS + remote.h + remotecfg.h +) + +SET(remote_UI_FILES + remotecfgbase.ui +) + +# moc, if needed +QT4_WRAP_CPP(remote_mocs ${remote_LIB_HDRS}) + +# don't forget our ui's +QT4_WRAP_UI(remote_uis ${remote_UI_FILES}) + +ADD_LIBRARY(remote SHARED ${remote_LIB_SRCS} ${remote_mocs} ${remote_uis}) + +# some needed include dirs +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) + +TARGET_LINK_LIBRARIES(remote simlib _core) + +SET_TARGET_PROPERTIES(remote PROPERTIES PREFIX "") + +# install target +INSTALL(TARGETS remote LIBRARY DESTINATION ${SIM_PLUGIN_DIR} RUNTIME DESTINATION ${SIM_PLUGIN_DIR}) + +######################### +# next target - simctrl # +######################### + +IF(0) +ADD_EXECUTABLE(simctrl simctrl.cpp) +IF(SIM_ENABLE_FPIE) + SET_TARGET_PROPERTIES(simctrl PROPERTIES COMPILE_FLAGS "${SIM_CXX_FPIE_FLAGS}") + SET_TARGET_PROPERTIES(simctrl PROPERTIES LINK_FLAGS "${SIM_PIE_LDFLAGS}") +ENDIF(SIM_ENABLE_FPIE) +TARGET_LINK_LIBRARIES(simctrl simlib) +INSTALL(TARGETS simctrl RUNTIME DESTINATION ${BINDIR}) +IF(NOT WIN32) + INSTALL(FILES simctrl.desktop DESTINATION ${SERVICES_INSTALL_DIR}) +ENDIF(NOT WIN32) + +#doesn't work yet +######################## +# next target - simext # +######################## + +ADD_EXECUTABLE(simext simext.idl SIM_ext.cpp simext.cpp simext.rc) +INSTALL(TARGETS simext RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}) + +######################## +# next target - simipc # +######################## + +ADD_EXECUTABLE(simipc simipc.cpp) +INSTALL(TARGETS simipc RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}) + +########################### +# next target - simremote # +########################### + +ADD_EXECUTABLE(simremote simremote.idl sim_remote.cpp simControl.cpp simremote.rc) +INSTALL(TARGETS simremote RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}) + +ENDIF(0) +ENDIF(BUILD_DROPPED) diff --git a/plugins/remote/IContextMenuImpl.h b/plugins/remote/IContextMenuImpl.h new file mode 100644 index 0000000..96de6a4 --- /dev/null +++ b/plugins/remote/IContextMenuImpl.h @@ -0,0 +1,49 @@ +// IContextMenuImpl.h +// +////////////////////////////////////////////////////////////////////// +#include +#include + + +class ATL_NO_VTABLE IContextMenuImpl : public IContextMenu3 +{ +public: + + // IUnknown + // + STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject) = 0; + _ATL_DEBUG_ADDREF_RELEASE_IMPL( IContextMenuImpl ) + + + // IContextMenu + // + STDMETHOD(GetCommandString)(UINT, UINT, UINT*, LPSTR, UINT) + { + return S_FALSE; + } + + STDMETHOD(InvokeCommand)(LPCMINVOKECOMMANDINFO) + { + return S_FALSE; + } + + STDMETHOD(QueryContextMenu)(HMENU, UINT, UINT , UINT, UINT) + { + return S_FALSE; + } + + // IContextMenu2 + // + STDMETHOD(HandleMenuMsg)(UINT, WPARAM, LPARAM) + { + return S_FALSE; + } + + // IContextMenu3 + // + STDMETHOD(HandleMenuMsg2)(UINT, WPARAM, LPARAM, LRESULT *) + { + return S_FALSE; + } +}; + diff --git a/plugins/remote/IShellExtInitImpl.h b/plugins/remote/IShellExtInitImpl.h new file mode 100644 index 0000000..3d56e8e --- /dev/null +++ b/plugins/remote/IShellExtInitImpl.h @@ -0,0 +1,26 @@ +// IShellExtInitImpl.h +// +////////////////////////////////////////////////////////////////////// +#include +#include + + +class ATL_NO_VTABLE IShellExtInitImpl : public IShellExtInit +{ +public: + + // IUnknown + // + STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject) = 0; + _ATL_DEBUG_ADDREF_RELEASE_IMPL( IShellExtInitImpl ) + + + // IShellExtInit + // + STDMETHOD(Initialize)(LPCITEMIDLIST, LPDATAOBJECT, HKEY) + { + return S_FALSE; + }; + +}; + diff --git a/plugins/remote/SIM_ext.cpp b/plugins/remote/SIM_ext.cpp new file mode 100644 index 0000000..05940b3 --- /dev/null +++ b/plugins/remote/SIM_ext.cpp @@ -0,0 +1,391 @@ +// SIM_ext.cpp : Implementation of CSIM_ext +#include +extern CComModule _Module; +#include +#include "Simext.h" +#include "SIM_ext.h" +#include + +using namespace std; + +static bool (*ProcessStr)(BSTR in_str, BSTR *out_str) = NULL; + +static string getToken(string &from, char c) +{ + string res; + unsigned i; + for (i = 0; i < from.length(); i++){ + if (from[i] == c) + break; + if (from[i] == '\\'){ + i++; + if (i >= from.length()) + break; + res += from[i]; + continue; + } + res += from[i]; + } + if (i < from.length()){ + from = from.substr(i + 1); + }else{ + from = ""; + } + return res; +} + +HINSTANCE CSIM_ext::hInstance; + +///////////////////////////////////////////////////////////////////////////// +// CSIM_ext + +CSIM_ext::CSIM_ext() +{ + lpData = NULL; + if (ProcessStr == NULL){ + WCHAR name[512]; + GetModuleFileName(hInstance, name, sizeof(name)); + + char* namestr=(char *)malloc( 512 ); + size_t i; + wcstombs_s(&i, namestr, (size_t)512, name, (size_t)512 ); + + char *r = strrchr(namestr, '\\'); + if (r){ + r++; + }else{ + r = namestr; + } + strcpy(r, "simremote.dll"); + HINSTANCE hLib = LoadLibrary(name); + (DWORD&)ProcessStr = (DWORD)GetProcAddress(hLib, "ProcessStr"); + } +} + +CSIM_ext::~CSIM_ext() +{ + for (ICON_MAP::iterator it = m_icons.begin(); it != m_icons.end(); ++it) + DestroyIcon((*it).second); + if (lpData) + lpData->Release(); +} + +HRESULT CSIM_ext::QueryContextMenu(HMENU hmenu, + UINT indexMenu, + UINT idCmdFirst, + UINT idCmdLast, + UINT uFlags) +{ + if ((lpData == NULL) || (uFlags & CMF_DEFAULTONLY)) + return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 0); + + CmdBase = idCmdFirst; + + if (((uFlags & 0x0000000F) == CMF_NORMAL) || (uFlags & CMF_EXPLORE)){ + STGMEDIUM stgmedium = { TYMED_HGLOBAL, NULL }; + FORMATETC formatetc = { CF_HDROP, + NULL, + DVASPECT_CONTENT, + -1, + TYMED_HGLOBAL + }; + HRESULT hr = lpData->GetData(&formatetc, &stgmedium); + if (!SUCCEEDED(hr)) + return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 0); + //char *drop_files = (char*)GlobalLock(stgmedium.hGlobal); + GlobalUnlock(stgmedium.hGlobal); + + CComBSTR in("CONTACTS 3"); + CComBSTR out; + unsigned cmd_id = idCmdFirst; + if (ProcessStr && ProcessStr(in, &out)){ + HMENU hMain = NULL; + HMENU hSub = NULL; + size_t size = WideCharToMultiByte(CP_ACP, 0, out, wcslen(out), 0, 0, NULL, NULL); + char *res = new char[size + 1]; + size = WideCharToMultiByte(CP_ACP, 0, out, wcslen(out), res, size, NULL, NULL); + res[size] = 0; + if (res[0] == '>'){ + string r = res + 1; + string line = getToken(r, '\n'); + unsigned nContacts = atol(getToken(line, ' ').c_str()); + unsigned nGroups = atol(line.c_str()); + bool bSubMenu = false; + if ((nContacts > 20) && (nGroups > 1)){ + hMain = CreatePopupMenu(); + bSubMenu = true; + } + unsigned old_grp = (unsigned)(-1); + while (!r.empty()){ + line = getToken(r, '\n'); + if (line.empty()) + continue; + unsigned id = atol(getToken(line, ' ').c_str()); + unsigned grp = atol(getToken(line, ' ').c_str()); + string icon = getToken(line, ' '); + if (!line.empty()){ + if (hMain){ + if (grp != old_grp){ + old_grp = grp; + if (bSubMenu){ + char *res = NULL; + hSub = CreatePopupMenu(); + char *grp = "Group"; + char cmd[64]; + sprintf(cmd, "GROUP %u", old_grp); + CComBSTR in(cmd); + CComBSTR out; + if (ProcessStr && ProcessStr(in, &out)){ + size_t size = WideCharToMultiByte(CP_ACP, 0, out, wcslen(out), 0, 0, NULL, NULL); + char *res = new char[size + 1]; + size = WideCharToMultiByte(CP_ACP, 0, out, wcslen(out), res, size, NULL, NULL); + res[size] = 0; + if (res[0] == '>') + grp = res + 1; + } + + wchar_t *grpLPCWSTR = (wchar_t *)malloc( sizeof( wchar_t )); + wcstombs( grp, grpLPCWSTR, size + 1 ); + AppendMenu(hMain, MF_POPUP | MF_STRING, (unsigned)hSub, grpLPCWSTR); + if (res) + delete[] res; + }else{ + AppendMenu(hSub, MF_SEPARATOR, 0, NULL); + } + } + }else{ + hMain = CreatePopupMenu(); + hSub = hMain; + } + ItemInfo info; + info.text = line.c_str(); + info.icon = createIcon(icon.c_str()); + info.id = id; + m_items.insert(ITEM_MAP::value_type(cmd_id, info)); + + const char* linestr = line.c_str(); + + AppendMenuA(hSub, MF_STRING | MF_OWNERDRAW, cmd_id, linestr); + cmd_id++; + } + } + } + delete[] res; + if (hMain != NULL) + InsertMenu(hmenu, indexMenu++, MF_POPUP|MF_BYPOSITION, + (UINT)hMain, L"Send to SIM contact"); + } + return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, cmd_id - idCmdFirst); + } + return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 0); +} + +static char fromHex(char c) +{ + if ((c >= '0') && (c <= '9')) return (char)(c - '0'); + if ((c >= 'A') && (c <= 'F')) return (char)(c + 10 - 'A'); + if ((c >= 'a') && (c <= 'f')) return (char)(c + 10 - 'a'); + return (char)0; +} + +static void *unpackData(const char *p) +{ + char *res = (char*)malloc(strlen(p) / 2); + char *t = res; + for (; p[0] && p[1]; p += 2) + *(t++) = (fromHex(p[0]) << 4) + fromHex(p[1]); + return res; +} + +HBITMAP CSIM_ext::createBitmap(string &info) +{ + BITMAPINFO *bmp = (BITMAPINFO*)unpackData(getToken(info, '\n').c_str()); + void *bits = unpackData(getToken(info, '\n').c_str()); + HDC hDC = CreateCompatibleDC(NULL); + HBITMAP hRes = CreateBitmap(bmp->bmiHeader.biWidth, bmp->bmiHeader.biHeight, bmp->bmiHeader.biPlanes, bmp->bmiHeader.biBitCount, NULL); + SetDIBits(hDC, hRes, 0, bmp->bmiHeader.biHeight, bits, bmp, DIB_RGB_COLORS); + DeleteDC(hDC); + free(bmp); + free(bits); + return hRes; +} + +HICON CSIM_ext::createIcon(const char *name) +{ + ICON_MAP::iterator it = m_icons.find(name); + if (it != m_icons.end()) + return (*it).second; + string cmd = "ICON "; + cmd += name; + CComBSTR in(cmd.c_str()); + CComBSTR out; + if (!ProcessStr || !ProcessStr(in, &out)) + return NULL; + size_t size = WideCharToMultiByte(CP_ACP, 0, out, wcslen(out), 0, 0, NULL, NULL); + char *res = new char[size + 1]; + size = WideCharToMultiByte(CP_ACP, 0, out, wcslen(out), res, size, NULL, NULL); + res[size] = 0; + if (res[0] != '>') + return NULL; + string r = res + 1; + ICONINFO info; + info.fIcon = TRUE; + info.xHotspot = 8; + info.yHotspot = 8; + info.hbmMask = createBitmap(r); + info.hbmColor = createBitmap(r); + HICON hIcon = CreateIconIndirect(&info); + m_icons.insert(ICON_MAP::value_type(name, hIcon)); + DeleteObject(info.hbmMask); + DeleteObject(info.hbmColor); + return hIcon; +} + +#ifndef CF_HDROP +#define CF_HDROP 15 +#endif + +HRESULT CSIM_ext::InvokeCommand(LPCMINVOKECOMMANDINFO lpici) +{ + if (lpData == NULL) + return S_OK; + STGMEDIUM stgmedium = { TYMED_HGLOBAL, NULL }; + FORMATETC formatetc = { CF_HDROP, + NULL, + DVASPECT_CONTENT, + -1, + TYMED_HGLOBAL + }; + HRESULT hr = lpData->GetData(&formatetc, &stgmedium); + if (SUCCEEDED(hr)){ + char *drop_files = (char*)GlobalLock(stgmedium.hGlobal); + DROPFILES *files = (DROPFILES*)drop_files; + drop_files += files->pFiles; + CComBSTR in("SENDFILE \""); + if (files->fWide){ + in += CComBSTR(drop_files); + }else{ + in += drop_files; + } + in += "\" "; + ItemInfo info = getItemInfo(LOWORD(lpici->lpVerb) + CmdBase); + char b[12]; + sprintf(b, "%u", info.id); + in += b; + GlobalUnlock(stgmedium.hGlobal); + CComBSTR out; + if (ProcessStr) + ProcessStr(in, &out); + } + GlobalFree(stgmedium.hGlobal); + if (lpData){ + lpData->Release(); + lpData = NULL; + } + return S_OK; +} + +HRESULT CSIM_ext::HandleMenuMsg(UINT uMsg,WPARAM wParam, LPARAM lParam) +{ + return HandleMenuMsg2(uMsg, wParam, lParam, NULL); +} + +HRESULT CSIM_ext::HandleMenuMsg2(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plResult) +{ + switch(uMsg) + { + case WM_DRAWITEM: + DrawMenuItem((LPDRAWITEMSTRUCT) lParam); + break; + + case WM_MEASUREITEM: + MeasureItem((LPMEASUREITEMSTRUCT) lParam); + break; + } + + return S_OK; +} + + +HRESULT CSIM_ext::GetCommandString(UINT idCmd, + UINT uType, + UINT * pwReserved, + LPSTR pszName, + UINT cchMax) +{ + return S_OK; +} + +HRESULT CSIM_ext::Initialize(LPCITEMIDLIST pidlFolder, LPDATAOBJECT lpdobj, HKEY hkeyProgID) +{ + if (lpData) + lpData->Release(); + lpData = lpdobj; + lpData->AddRef(); + return S_OK; +} + +ItemInfo CSIM_ext::getItemInfo(unsigned id) +{ + ITEM_MAP::iterator it = m_items.find(id); + if (it != m_items.end()) + return (*it).second; + ItemInfo info; + info.icon = NULL; + return info; +} + +void CSIM_ext::MeasureItem(LPMEASUREITEMSTRUCT lpmis) +{ + if (lpmis->CtlType != ODT_MENU) + return; + ItemInfo info = getItemInfo(lpmis->itemID); + if (info.icon == NULL) + return; + HDC hDC = CreateCompatibleDC(NULL); + SelectObject(hDC, GetStockObject(DEFAULT_GUI_FONT)); + SIZE s; + GetTextExtentPoint32A(hDC, info.text.c_str(), info.text.length(), &s); + lpmis->itemWidth = s.cx + GetSystemMetrics(SM_CXMENUCHECK) + GetSystemMetrics(SM_CXFRAME) * 2; + lpmis->itemHeight = GetSystemMetrics(SM_CYMENU); + DeleteDC(hDC); +} + +void CSIM_ext::DrawMenuItem(LPDRAWITEMSTRUCT lpdis) +{ + if (lpdis->CtlType != ODT_MENU) + return; + ItemInfo info = getItemInfo(lpdis->itemID); + if (info.icon == NULL) + return; + if (lpdis->itemAction & (ODA_DRAWENTIRE|ODA_SELECT)){ + COLORREF crText = 0, crBack = 0; + int bgColor; + if (lpdis->itemState & ODS_SELECTED) + { + bgColor = COLOR_HIGHLIGHT; + crText = SetTextColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT)); + crBack = SetBkColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHT)); + }else{ + bgColor = COLOR_MENU; + } + FillRect(lpdis->hDC, &lpdis->rcItem, GetSysColorBrush(bgColor)); + ICONINFO icon_info; + GetIconInfo(info.icon, &icon_info); + BITMAP bmp; + GetObject(icon_info.hbmColor, sizeof(BITMAP), (LPSTR)&bmp); + DrawIconEx(lpdis->hDC, + lpdis->rcItem.left + (GetSystemMetrics(SM_CXMENUCHECK) - bmp.bmWidth) / 2, + lpdis->rcItem.top + (lpdis->rcItem.bottom - lpdis->rcItem.top - bmp.bmHeight) / 2, + info.icon, bmp.bmWidth, bmp.bmHeight, 0, 0, DI_NORMAL); + RECT rt = lpdis->rcItem; + rt.left += GetSystemMetrics(SM_CXMENUCHECK) + GetSystemMetrics(SM_CXFRAME); + DrawTextA(lpdis->hDC, info.text.c_str(), info.text.length(), &rt, DT_LEFT | DT_EXPANDTABS | DT_VCENTER | DT_SINGLELINE); + if (lpdis->itemState & ODS_SELECTED) + { + SetTextColor(lpdis->hDC, crText); + SetBkColor(lpdis->hDC, crBack); + } + } +} + diff --git a/plugins/remote/SIM_ext.h b/plugins/remote/SIM_ext.h new file mode 100644 index 0000000..db90ed5 --- /dev/null +++ b/plugins/remote/SIM_ext.h @@ -0,0 +1,129 @@ +// SIM_ext.h : Declaration of the CSIM_ext + +#ifndef __SIM_EXT_H_ +#define __SIM_EXT_H_ + +#include "resource.h" // main symbols +#include "comdef.h" +#include "shlobj.h" +#include "IShellExtInitImpl.h" // IShellExtInit +#include "IContextMenuImpl.h" // IContextMenu +#include +#include +#include + +#if _MSC_VER > 1020 +#include +#pragma warning(disable: 4097) +#pragma warning(disable: 4244) +#pragma warning(disable: 4275) +#pragma warning(disable: 4514) +#pragma warning(disable: 4710) +#pragma warning(disable: 4786) +#pragma warning(push) +#pragma warning(disable: 4018) +#pragma warning(disable: 4100) +#pragma warning(disable: 4146) +#pragma warning(disable: 4511) +#pragma warning(disable: 4512) +#pragma warning(disable: 4530) +#pragma warning(disable: 4663) +#endif + +#include +#include +#include + +struct ItemInfo +{ + std::string text; + HICON icon; + unsigned id; +}; + +typedef std::map ICON_MAP; +typedef std::map ITEM_MAP; + +struct __declspec(uuid("000214e4-0000-0000-c000-000000000047")) +IContextMenu; + +_COM_SMARTPTR_TYPEDEF(IContextMenu, __uuidof(IContextMenu)); + +struct __declspec(uuid("000214e4-0000-0000-c000-000000000048")) +IContextMenu2; + +_COM_SMARTPTR_TYPEDEF(IContextMenu2, __uuidof(IContextMenu2)); + +struct __declspec(uuid("000214e4-0000-0000-c000-000000000049")) +IContextMenu3; + +_COM_SMARTPTR_TYPEDEF(IContextMenu3, __uuidof(IContextMenu3)); + +///////////////////////////////////////////////////////////////////////////// +// CSIM_ext +class ATL_NO_VTABLE CSIM_ext : + public CComObjectRootEx, + public CComCoClass, + public ISIM_ext, + public IObjectWithSiteImpl, + public IShellExtInitImpl, + public IContextMenuImpl +{ +public: + CSIM_ext(); + ~CSIM_ext(); + LPDATAOBJECT lpData; + static HINSTANCE hInstance; + + DECLARE_REGISTRY_RESOURCEID(IDR_SIM_EXT) + DECLARE_NOT_AGGREGATABLE(CSIM_ext) + + DECLARE_PROTECT_FINAL_CONSTRUCT() + + BEGIN_COM_MAP(CSIM_ext) + COM_INTERFACE_ENTRY(ISIM_ext) + COM_INTERFACE_ENTRY(IShellExtInit) + COM_INTERFACE_ENTRY(IContextMenu) + COM_INTERFACE_ENTRY(IContextMenu2) + COM_INTERFACE_ENTRY(IContextMenu3) + COM_INTERFACE_ENTRY(IObjectWithSite) + END_COM_MAP() + + ICON_MAP m_icons; + ITEM_MAP m_items; + ItemInfo getItemInfo(unsigned id); + HICON createIcon(const char *name); + HBITMAP createBitmap(std::string &info); + unsigned CmdBase; + + // ISIM_ext +public: + STDMETHOD(QueryContextMenu)(THIS_ + HMENU hmenu, + UINT indexMenu, + UINT idCmdFirst, + UINT idCmdLast, + UINT uFlags); + + STDMETHOD(InvokeCommand)(THIS_ + LPCMINVOKECOMMANDINFO lpici); + + STDMETHOD(HandleMenuMsg)(UINT, WPARAM, LPARAM); + + STDMETHOD(HandleMenuMsg2)(UINT, WPARAM, LPARAM, LRESULT *); + + STDMETHOD(GetCommandString)(THIS_ + UINT idCmd, + UINT uType, + UINT * pwReserved, + LPSTR pszName, + UINT cchMax); + + STDMETHOD(Initialize)(THIS_ LPCITEMIDLIST pidlFolder, + LPDATAOBJECT lpdobj, HKEY hkeyProgID); +private: + void MeasureItem(LPMEASUREITEMSTRUCT); + void DrawMenuItem(LPDRAWITEMSTRUCT); +}; + +#endif //__SIM_EXT_H_ diff --git a/plugins/remote/SIM_ext.rgs b/plugins/remote/SIM_ext.rgs new file mode 100644 index 0000000..c8d0eed --- /dev/null +++ b/plugins/remote/SIM_ext.rgs @@ -0,0 +1,45 @@ +HKCR +{ + Simext.SIM_ext.1 = s 'SIM_ext Class' + { + CLSID = s '{8DD848D4-81E7-490E-9A3D-CE9058956208}' + } + Simext.SIM_ext = s 'SIM_ext Class' + { + CLSID = s '{8DD848D4-81E7-490E-9A3D-CE9058956208}' + CurVer = s 'Simext.SIM_ext.1' + } + NoRemove * + { + NoRemove shellex + { + NoRemove ContextMenuHandlers + { + ForceRemove SIMMenu = s '{8DD848D4-81E7-490E-9A3D-CE9058956208}' + } + } + } + NoRemove Folder + { + NoRemove shellex + { + NoRemove ContextMenuHandlers + { + ForceRemove SIMMenu = s '{8DD848D4-81E7-490E-9A3D-CE9058956208}' + } + } + } + NoRemove CLSID + { + ForceRemove {8DD848D4-81E7-490E-9A3D-CE9058956208} = s 'SIM_ext Class' + { + ProgID = s 'Simext.SIM_ext.1' + VersionIndependentProgID = s 'Simext.SIM_ext' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + 'TypeLib' = s '{F67751E0-1470-447C-8B3E-000D155711A2}' + } + } +} diff --git a/plugins/remote/SimControl.cpp b/plugins/remote/SimControl.cpp new file mode 100644 index 0000000..56a455c --- /dev/null +++ b/plugins/remote/SimControl.cpp @@ -0,0 +1,184 @@ +/*************************************************************************** + SimControl.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +extern CComModule _Module; +#include +#include "Simremote.h" +#include "SimControl.h" + +#include "remote.h" + +using namespace std; + +class IPC +{ +public: + IPC(); + ~IPC(); + string prefix(); + bool isInit(); + bool process(const BSTR &in_str, BSTR *out_str); +protected: + unsigned *s; + HANDLE hMem; + HANDLE hMutex; + HANDLE hEventIn; + HANDLE hEventOut; + friend class IPCLock; +}; + +class IPCLock +{ +public: + IPCLock(IPC *ipc); + ~IPCLock(); +protected: + IPC *m_ipc; +}; + +IPC::IPC() +{ + s = NULL; + string name = prefix() + "mem"; + hMem = OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE, name.c_str()); + if (hMem) + s = (unsigned*)MapViewOfFile(hMem, FILE_MAP_ALL_ACCESS, 0, 0, 0); + if (s) + memset(s, 0, N_SLOTS * sizeof(unsigned)); + name = prefix() + "mutex"; + hMutex = OpenMutexA(MUTEX_ALL_ACCESS, FALSE, name.c_str()); + name = prefix() + "in"; + hEventIn = OpenEventA(EVENT_ALL_ACCESS, FALSE, name.c_str()); + name = prefix() + "out"; + hEventOut = OpenEventA(EVENT_ALL_ACCESS, FALSE, name.c_str()); +} + +IPC::~IPC() +{ + if (s) + UnmapViewOfFile(s); + if (hMem) + CloseHandle(hMem); + if (hMutex) + CloseHandle(hMutex); + if (hEventIn) + CloseHandle(hEventIn); + if (hEventOut) + CloseHandle(hEventOut); +} + +#ifndef SM_REMOTECONTROL +#define SM_REMOTECONTROL 0x2001 +#endif +#ifndef SM_REMOTESESSION +#define SM_REMOTESESSION 0x1000 +#endif + +string IPC::prefix() +{ + string res; + if (GetSystemMetrics(SM_REMOTECONTROL) || GetSystemMetrics(SM_REMOTESESSION)) + res = "Global/"; + res += SIM_SHARED; + return res; +} + +bool IPC::isInit() +{ + return hMem && hMutex && hEventIn && hEventOut; +} + +bool IPC::process(const BSTR &in_str, BSTR *out_str) +{ + unsigned i = 0; + HANDLE hMem = NULL; + unsigned short *mem; + { + IPCLock lock(this); + for (i = 0; i < N_SLOTS; i++){ + if (s[i] != SLOT_NONE) + continue; + string name = prefix(); + char b[5]; + sprintf(b, "%u", i); + name += b; + hMem = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 0x8000, name.c_str()); + if (hMem == NULL) + return false; + mem = (unsigned short*)MapViewOfFile(hMem, FILE_MAP_ALL_ACCESS, 0, 0, 0); + if (mem == NULL) + return false; + memcpy(mem, in_str, (wcslen(in_str) + 1) * 2); + s[i] = SLOT_IN; + break; + } + if (i >= N_SLOTS) + return false; + } + SetEvent(hEventIn); + for (;;){ + WaitForSingleObject(hEventOut, INFINITE); + IPCLock lock(this); + if (s[i] == SLOT_IN) + continue; + if (s[i] == SLOT_OUT){ + CComBSTR res((int)mem); + *out_str = res.Copy(); + } + UnmapViewOfFile(mem); + CloseHandle(hMem); + break; + } + return true; +} + +IPCLock::IPCLock(IPC *ipc) +{ + m_ipc = ipc; + WaitForSingleObject(m_ipc->hMutex, INFINITE); +} + +IPCLock::~IPCLock() +{ + ReleaseMutex(m_ipc->hMutex); +} + +extern "C" __declspec(dllexport) bool ProcessStr(BSTR in_str, BSTR *out_str) +{ + IPC ipc; + if (!ipc.isInit()) + return false; + if (!ipc.process(in_str, out_str)) + return false; + return true; +} + +STDMETHODIMP CSimControl::get_Running(BOOL *pVal) +{ + IPC ipc; + *pVal = ipc.isInit(); + return S_OK; +} + +STDMETHODIMP CSimControl::Process(BSTR in_str, BSTR *out_str) +{ + if (ProcessStr(in_str, out_str)) + return S_OK; + return S_FALSE; +} + diff --git a/plugins/remote/SimControl.h b/plugins/remote/SimControl.h new file mode 100644 index 0000000..6d48c64 --- /dev/null +++ b/plugins/remote/SimControl.h @@ -0,0 +1,35 @@ +// SimControl.h : Declaration of the CSimControl + +#ifndef __SIMCONTROL_H_ +#define __SIMCONTROL_H_ + +#include "resource.h" // main symbols + +///////////////////////////////////////////////////////////////////////////// +// CSimControl +class ATL_NO_VTABLE CSimControl : + public CComObjectRootEx, + public CComCoClass, + public IDispatchImpl +{ +public: + CSimControl() + { + } + + DECLARE_REGISTRY_RESOURCEID(IDR_SIMCONTROL) + + DECLARE_PROTECT_FINAL_CONSTRUCT() + + BEGIN_COM_MAP(CSimControl) + COM_INTERFACE_ENTRY(ISimControl) + COM_INTERFACE_ENTRY(IDispatch) + END_COM_MAP() + + // ISimControl +public: + STDMETHOD(Process)(/*[in]*/ BSTR in_str, /*[out, retval]*/ BSTR *out_str); + STDMETHOD(get_Running)(/*[out, retval]*/ BOOL *pVal); +}; + +#endif //__SIMCONTROL_H_ diff --git a/plugins/remote/SimControl.rgs b/plugins/remote/SimControl.rgs new file mode 100644 index 0000000..c8e149c --- /dev/null +++ b/plugins/remote/SimControl.rgs @@ -0,0 +1,26 @@ +HKCR +{ + Simremote.SimControl.1 = s 'SimControl Class' + { + CLSID = s '{0B4C5D94-61D9-41C6-AD05-4750A0E86C2E}' + } + Simremote.SimControl = s 'SimControl Class' + { + CLSID = s '{0B4C5D94-61D9-41C6-AD05-4750A0E86C2E}' + CurVer = s 'Simremote.SimControl.1' + } + NoRemove CLSID + { + ForceRemove {0B4C5D94-61D9-41C6-AD05-4750A0E86C2E} = s 'SimControl Class' + { + ProgID = s 'Simremote.SimControl.1' + VersionIndependentProgID = s 'Simremote.SimControl' + ForceRemove 'Programmable' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + 'TypeLib' = s '{C4826912-0E46-445E-8B03-9683AAF5143F}' + } + } +} diff --git a/plugins/remote/configure.in.in b/plugins/remote/configure.in.in new file mode 100644 index 0000000..7fd49fc --- /dev/null +++ b/plugins/remote/configure.in.in @@ -0,0 +1 @@ +AM_CONDITIONAL(ENABLE_REMOTE, test "$kde_use_qt_win" != "yes") diff --git a/plugins/remote/remote.cpp b/plugins/remote/remote.cpp new file mode 100644 index 0000000..9593401 --- /dev/null +++ b/plugins/remote/remote.cpp @@ -0,0 +1,1080 @@ +/*************************************************************************** + remote.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "icons.h" +#include "log.h" + +#include "profile.h" +#include "profilemanager.h" + +#include "socket/clientsocket.h" +#include "contacts/contact.h" +#include "contacts/group.h" +#include "contacts/client.h" +#include "remote.h" +#include "remotecfg.h" +#include "core.h" + +using namespace std; +using namespace SIM; + +Plugin *createRemotePlugin(unsigned base, bool, Buffer *config) +{ + Plugin *plugin = new RemotePlugin(base, config); + return plugin; +} + +static PluginInfo info = + { + I18N_NOOP("Remote control"), + I18N_NOOP("Plugin provides remote control"), + VERSION, + createRemotePlugin, + PLUGIN_DEFAULT + }; + +EXPORT_PROC PluginInfo* GetPluginInfo() +{ + return &info; +} + +//static DataDef remoteData[] = +// { +//#ifdef WIN32 +// { "Path", DATA_STRING, 1, "auto:" }, +// { "EnableMenu", DATA_BOOL, 1, DATA(1) }, +//#else +// { "Path", DATA_STRING, 1, "/tmp/sim.%user%" }, +//#endif +// { NULL, DATA_UNKNOWN, 0, 0 } +// }; + +#ifdef WIN32 + +#include + +static RemotePlugin *remote = NULL; + +class IPC : public QThread +{ +public: + IPC(); + ~IPC(); + QString prefix(); + void process(); +protected: + unsigned *s; + Qt::HANDLE hMem; + Qt::HANDLE hMutex; + Qt::HANDLE hEventIn; + Qt::HANDLE hEventOut; + bool bExit; + virtual void run(); + friend class IPCLock; +}; + +class IPCLock +{ +public: + IPCLock(IPC *ipc); + ~IPCLock(); +protected: + IPC *m_ipc; +}; + +IPC::IPC() +{ + s = NULL; + QString name = prefix() + "mem"; + hMem = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, N_SLOTS * sizeof(unsigned), name.toLatin1()); + if (hMem) + s = (unsigned*)MapViewOfFile(hMem, FILE_MAP_ALL_ACCESS, 0, 0, 0); + if (s) + memset(s, 0, N_SLOTS * sizeof(unsigned)); + name = prefix() + "mutex"; + hMutex = CreateMutexA(NULL, FALSE, name.toLatin1()); + name = prefix() + "in"; + hEventIn = CreateEventA(NULL, TRUE, FALSE, name.toLatin1()); + name = prefix() + "out"; + hEventOut = CreateEventA(NULL, TRUE, FALSE, name.toLatin1()); + bExit = false; + start(); +} + +IPC::~IPC() +{ + bExit = true; + SetEvent(hEventIn); + if (s) + UnmapViewOfFile(s); + if (hMem) + CloseHandle(hMem); + if (hMutex) + CloseHandle(hMutex); + if (hEventIn) + CloseHandle(hEventIn); + if (hEventOut) + CloseHandle(hEventOut); + wait(2000); +} + +void IPC::run() +{ + for (;;){ + ResetEvent(hEventIn); + WaitForSingleObject(hEventIn, INFINITE); + if (bExit) + break; + QTimer::singleShot(0, remote, SLOT(command())); + } +} + +void IPC::process() +{ + IPCLock(this); + for (unsigned i = 0; i < N_SLOTS; i++){ + if (s[i] != SLOT_IN) + continue; + QString in; + QString out; + QString name = prefix() + QString::number(i); + Qt::HANDLE hMem = OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE, name.toLatin1()); + if (hMem == NULL){ + s[i] = SLOT_NONE; + PulseEvent(hEventOut); + continue; + } + unsigned short *mem = (unsigned short*)MapViewOfFile(hMem, FILE_MAP_ALL_ACCESS, 0, 0, 0); + if (mem == NULL){ + log(L_WARN, "Map error"); + s[i] = SLOT_NONE; + PulseEvent(hEventOut); + continue; + } + unsigned short *p; + for (p = mem; *p; p++) + in += QChar(*p); + + bool bError = false; + bool bRes = remote->command(in, out, bError); + p = mem; + unsigned size = 0; + if (!bError){ + if (bRes){ + *(p++) = QChar('>').unicode(); + }else{ + *(p++) = QChar('?').unicode(); + } + size = out.length(); + if (size > 0x3F00) + size = 0x3F00; + memcpy(p, out.unicode(), size * sizeof(unsigned short)); + size++; + } + p[size] = 0; + UnmapViewOfFile(mem); + CloseHandle(hMem); + s[i] = SLOT_OUT; + PulseEvent(hEventOut); + } +} + +#ifndef SM_REMOTECONTROL +#define SM_REMOTECONTROL 0x2001 +#endif +#ifndef SM_REMOTESESSION +#define SM_REMOTESESSION 0x1000 +#endif + +QString IPC::prefix() +{ + QString res; + if (GetSystemMetrics(SM_REMOTECONTROL) || GetSystemMetrics(SM_REMOTESESSION)) + res = "Global/"; + res += SIM_SHARED; + return res; +} + +IPCLock::IPCLock(IPC *ipc) +{ + m_ipc = ipc; + WaitForSingleObject(m_ipc->hMutex, INFINITE); +} + +IPCLock::~IPCLock() +{ + ReleaseMutex(m_ipc->hMutex); +} + +#endif + +RemotePlugin::RemotePlugin() + : Plugin(NULL) +{ +} + +RemotePlugin::RemotePlugin(unsigned base, Buffer *config) + : QObject(), Plugin(base) +{ + m_propertyHub = SIM::PropertyHub::create("remote"); + bind(); +#ifdef WIN32 + remote = this; + ipc = new IPC; +#endif +} + +RemotePlugin::~RemotePlugin() +{ +#ifdef WIN32 + delete ipc; +#endif + while (!m_sockets.empty()) + delete m_sockets.front(); +} + +QByteArray RemotePlugin::getConfig() +{ + return QByteArray(); //Fixmeee +} + +QWidget *RemotePlugin::createConfigWindow(QWidget *parent) +{ + return new RemoteConfig(parent, this); +} + +bool RemotePlugin::processEvent(Event* e) +{ + if(e->type() == eEventPluginLoadConfig) + { + PropertyHubPtr hub = ProfileManager::instance()->getPropertyHub("remote"); + if(!hub.isNull()) + setPropertyHub(hub); + } + return false; +} + +static char TCP[] = "tcp:"; + +void RemotePlugin::bind() +{ + QString path = value("Path").toString(); + if (path.startsWith(TCP)){ + unsigned short port = path.mid(strlen(TCP)).toUShort(); + ServerSocketNotify::bind(port, port, NULL); +// ToDo: Restore this +//#ifndef WIN32 +// }else{ +// ServerSocketNotify::bind(path.toLatin1()); +//#endif + } +} + +bool RemotePlugin::accept(Socket *s, unsigned long) +{ + log(L_DEBUG, "Accept remote control"); + new ControlSocket(this, s); + return false; +} + +void RemotePlugin::bind_ready(unsigned short) +{ +} + +bool RemotePlugin::error(const QString &err) +{ + if (!err.isEmpty()) + log(L_DEBUG, "Remote: %s", qPrintable(err)); + return true; +} + +void RemotePlugin::command() +{ +#ifdef WIN32 + ipc->process(); +#endif +} + +const unsigned CMD_STATUS = 0; +const unsigned CMD_INVISIBLE = 1; +const unsigned CMD_MAINWND = 2; +const unsigned CMD_SEARCHWND = 3; +const unsigned CMD_QUIT = 4; +const unsigned CMD_CLOSE = 5; +const unsigned CMD_HELP = 6; +const unsigned CMD_ADD = 7; +const unsigned CMD_DELETE = 8; +const unsigned CMD_OPEN = 9; +const unsigned CMD_FILE = 10; +const unsigned CMD_CONTACTS = 11; +const unsigned CMD_SENDFILE = 12; +const unsigned CMD_GROUP = 13; +const unsigned CMD_SHOW = 14; +const unsigned CMD_SMS = 15; +#ifdef WIN32 +const unsigned CMD_ICON = 16; +#endif + +struct cmdDef +{ + const char *cmd; + const char *shortDescr; + const char *longDescr; + unsigned minArgs; + unsigned maxArgs; +}; + +static cmdDef cmds[] = + { + { "STATUS", "set status", "STATUS [status]", 0, 1 }, + { "INVISIBLE", "set invisible mode", "INVISIBLE [on|off]", 0, 1 }, + { "MAINWINDOW", "show/hide main window", "MAINWINDOW [on|off|toggle]", 0, 1 }, + { "SEARCHWINDOW", "show/hide search window", "SEARCHWINDOW [on|off]", 0, 1 }, + { "QUIT", "quit SIM", "QUIT", 0, 0 }, + { "CLOSE", "close session", "CLOSE", 0, 0 }, + { "HELP", "command help information", "HELP []", 0, 1 }, + { "ADD", "add contact", "ADD
[] []", 2, 4 }, + { "DELETE", "delete contact", "DELETE [
| ]", 1, 1 }, + { "OPEN", "open contact", "OPEN
[] []", 2, 4 }, + { "FILE", "process UIN file", "FILE ", 1, 1 }, + { "CONTACTS", "print contact list", "CONTACTS []", 0, 1 }, + { "SENDFILE", "send file", "SENDFILE ", 2, 2 }, + { "GROUP", "get group name", "GROUP id", 1, 1 }, + { "SHOW", "open unread message", "SHOW", 0, 0 }, + { "SMS", "send SMS", "SMS ", 2, 2 }, +#ifdef WIN32 + { "ICON", "get used icon", "ICON name", 1, 1 }, +#endif + { NULL, NULL, NULL, 0, 0 } + }; + +#if 0 +{ "MESSAGE", "send message", "MESSAGE ", 2, 2 }, +{ "SMS", "send SMS", "SMS ", 2, 2 }, +{ "DOCK", "show/hide dock", "DOCK [on|off]", 0, 1 }, +{ "NOTIFY", "set notify mode", "NOTIFY [on|off]", 0, 1 }, +{ "ICON", "get icon in xpm format", "ICON nIcon", 1, 1 }, +{ "POPUP", "show popup", "POPUP x y", 2, 2 }, +#endif + +static bool isOn(const QString &s) +{ + return (s == "1") || (s == "on") || (s == "ON"); +} + +static bool cmpStatus(const QString &s1, const QString &s2) +{ + QString ss1 = s1; + QString ss2 = s2; + ss1 = ss1.remove('&'); + ss2 = ss2.remove('&'); + return ss1.toLower() == ss2.toLower(); +} + +static QWidget *findWidget(const char *className) +{ + QWidgetList list = QApplication::topLevelWidgets(); + QWidget* w; + foreach (w,list) + { + if (w->inherits(className)) + return w; + } + return NULL; +} + +struct ContactInfo +{ + QString name; + unsigned id; + unsigned group; + QString key; + QString icon; +}; + +static bool cmp_info(const ContactInfo &p1, const ContactInfo &p2) +{ + return p1.key < p2.key; +} + +#ifdef WIN32 + +void packData(QString &out, void *data, unsigned size) +{ + unsigned char *p = (unsigned char*)data; + for (unsigned i = 0; i < size; i++, p++){ + char b[3]; + sprintf(b, "%02X", *p); + out += b; + } +} + +void packBitmap(QString &out, HBITMAP hBmp) +{ + BITMAP bmp; + BITMAPINFO *pbmi; + WORD cClrBits; + if (!GetObjectA(hBmp, sizeof(BITMAP), (LPSTR)&bmp)) + return; + + cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel); + if (cClrBits == 1) + cClrBits = 1; + else if (cClrBits <= 4) + cClrBits = 4; + else if (cClrBits <= 8) + cClrBits = 8; + else if (cClrBits <= 16) + cClrBits = 16; + else if (cClrBits <= 24) + cClrBits = 24; + else cClrBits = 32; + + unsigned size = sizeof(BITMAPINFOHEADER); + if (cClrBits != 24) + size += sizeof(RGBQUAD) * (1<< cClrBits); + pbmi = (BITMAPINFO*)malloc(size); + + pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + pbmi->bmiHeader.biWidth = bmp.bmWidth; + pbmi->bmiHeader.biHeight = bmp.bmHeight; + pbmi->bmiHeader.biPlanes = bmp.bmPlanes; + pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel; + if (cClrBits < 24) + pbmi->bmiHeader.biClrUsed = (1<bmiHeader.biCompression = BI_RGB; + pbmi->bmiHeader.biSizeImage = ((pbmi->bmiHeader.biWidth * cClrBits +31) & ~31) /8 + * pbmi->bmiHeader.biHeight; + + HDC hDC = CreateCompatibleDC(NULL); + void *bits = malloc(pbmi->bmiHeader.biSizeImage); + GetDIBits(hDC, hBmp, 0, (WORD) pbmi->bmiHeader.biHeight, bits, pbmi, DIB_RGB_COLORS); + + packData(out, pbmi, size); + out += "\n"; + packData(out, bits, pbmi->bmiHeader.biSizeImage); + + DeleteDC(hDC); + free(bits); + free(pbmi); +} + +class IconWidget : public QWidget +{ +public: + IconWidget(const QPixmap &p); + HICON icon(); +}; + +IconWidget::IconWidget(const QPixmap &p) +{ + setWindowIcon(p); +} + +HICON IconWidget::icon() +{ + HWND hWnd = (HWND)effectiveWinId(); + if(NULL == hWnd) + return NULL; + return (HICON)::SendMessage( hWnd, WM_GETICON, ICON_SMALL, 0 ); +} + +#endif + +bool RemotePlugin::command(const QString &in, QString &out, bool &bError) +{ + QString cmd; + vector args; + int i = 0; + for (; i < (int)(in.length()); i++) + if (in[i] != ' ') + break; + for (; i < (int)(in.length()); i++){ + if (in[i] == ' ') + break; + cmd += in[i].toUpper(); + } + for (; i < (int)(in.length()); ){ + for (; i < (int)(in.length()); i++) + if (in[i] != ' ') + break; + if (i >= (int)(in.length())) + break; + QString arg; + if ((in[i] == '\'') || (in[i] == '\"')){ + QChar c = in[i]; + for (i++; i < (int)(in.length()); i++){ + if (in[i] == c){ + i++; + break; + } + arg += in[i]; + } + }else{ + for (; i < (int)(in.length()); i++){ + if (in[i] == '\\'){ + i++; + if (i >= (int)(in.length())) + break; + arg += in[i]; + continue; + } + if (in[i] == ' ') + break; + arg += in[i]; + } + } + args.push_back(arg); + } + unsigned nCmd = 0; + const cmdDef *c; + for (c = cmds; c->cmd; c++, nCmd++) + if (QString(cmd) == QString(c->cmd)) + break; + + if (c->cmd == NULL){ + out = "Unknown command "; + out += cmd; + return false; + } + if ((args.size() < c->minArgs) || (args.size() > c->maxArgs)){ + out = "Bad arguments number. Try help "; + out += cmd; + return false; + } + QWidget *w; + unsigned n; + CorePlugin *core = GET_CorePlugin(); + switch (nCmd){ +#ifdef WIN32 + case CMD_ICON:{ + IconWidget w(Pict(args[0].toUtf8())); + HICON icon = w.icon(); + ICONINFO info; + if (!GetIconInfo(icon, &info)) + return false; + packBitmap(out, info.hbmMask); + out += "\n"; + packBitmap(out, info.hbmColor); + return true; + } +#endif + case CMD_SENDFILE:{ //fix me, concepted only for ICQ-Proto + FileMessage *msg = new FileMessage; + msg->setContact(args[1].toUInt()); //anyhow + msg->setFile(args[0]); //this should + EventOpenMessage(msg).process(); //be tested, or be rewritten + delete msg; + return true; + } + case CMD_GROUP:{ + Group *grp = getContacts()->group(args[0].toUInt()); + if (grp == NULL) + return false; + if (grp->id() == 0){ + out += i18n("Not in list"); + }else{ + out += grp->getName(); + } + return true; + } + case CMD_CONTACTS:{ +#ifdef WIN32 + if (value("EnableMenu").toBool()){ +#endif + unsigned type = 0; + if (args.size()) + type = args[0].toUInt(); + ContactList::ContactIterator it; + Contact *contact; + vector contacts; + list groups; + while ((contact = ++it) != NULL){ + if ((contact->getFlags() & CONTACT_TEMPORARY) || contact->getIgnore()) + continue; + if (type){ + Command cmd; + cmd->id = type; + cmd->menu_id = MenuMessage; + cmd->param = (void*)(contact->id()); + if (!EventCheckCommandState(cmd).process()) + continue; + } + unsigned style = 0; + QString statusIcon; + unsigned status = contact->contactInfo(style, statusIcon); + if ((status == STATUS_OFFLINE) && core->value("ShowOnLine").toBool()) + continue; + unsigned mode = core->value("SortMode").toUInt(); + ContactInfo info; + QString active; + active.sprintf("%08lX", (long unsigned int)(0xFFFFFFFF - contact->getLastActive())); + if (core->value("GroupMode").toUInt()){ + unsigned index = 0xFFFFFFFF; + if (contact->getGroup()){ + Group *grp = getContacts()->group(contact->getGroup()); + if (grp) + index = getContacts()->groupIndex(grp->id()); + } + QString grpIndex; + grpIndex.sprintf("%08X", index); + info.key += grpIndex; + } + for (;;){ + if ((mode & 0xFF) == 0) + break; + switch (mode & 0xFF){ + case SORT_STATUS: + info.key += QString::number(9 - status); + break; + case SORT_ACTIVE: + info.key += active.toLower(); + break; + case SORT_NAME: + info.key += contact->getName().toLower(); + break; + } + mode = mode >> 8; + } + info.name = contact->getName(); + info.id = contact->id(); + info.icon = statusIcon; + info.group = contact->getGroup(); + if (core->value("GroupMode").toUInt()){ + info.group = contact->getGroup(); + list::iterator it; + for (it = groups.begin(); it != groups.end(); ++it) + if ((*it) == (unsigned)contact->getGroup()) + break; + groups.push_back(contact->getGroup()); + } + contacts.push_back(info); + } + sort(contacts.begin(), contacts.end(), cmp_info); + out += QString::number(contacts.size()); + out += " "; + out += QString::number(groups.size()); + out += "\n"; + for (vector::iterator itl = contacts.begin(); itl != contacts.end(); ++itl){ + out += "\n"; + out += QString::number((*itl).id); + out += " "; + out += QString::number((*itl).group); + out += " "; + out += (*itl).icon; + out += " "; + out += (*itl).name; + } +#ifdef WIN32 + } +#endif + return true; + } + case CMD_FILE:{ + QFile f(args[0]); + if (!f.open(QIODevice::ReadOnly)){ + out = "Can't open "; + out += args[0]; + return false; + } + bool bOpen = false; + unsigned uin = 0; + Buffer sf; + sf = f.readAll(); + while (sf.readPos() < (unsigned)sf.size()){ + QByteArray line; + sf.scan("\n", line); + if (!line.isEmpty() && (line[(int)line.length() - 1] == '\r')) + line = line.left(line.length() - 1); + if (line == "[ICQ Message User]") + bOpen = true; + if (line.left(4) == "UIN=") + uin = line.mid(4).toUInt(); + } + if (uin == 0){ + out = "Bad file "; + out += args[0]; + return false; + } + EventAddContact::AddContact ac; + ac.proto = "ICQ"; + ac.addr = QString::number(uin); + ac.nick = QString::null; + ac.group = 0; + EventAddContact e(&ac); + e.process(); + Contact *contact = e.contact(); + if (contact == NULL){ + out = "Can't add user"; + return false; + } + if (bOpen){ + Message *m = new Message(MessageGeneric); + m->setContact(contact->id()); + EventOpenMessage(m).process(); + delete m; + } + return true; + } + case CMD_STATUS: + if (args.size()){ + unsigned status = STATUS_UNKNOWN; + for (n = 0; n < getContacts()->nClients(); n++){ + Client *client = getContacts()->getClient(n); + for (const CommandDef *d = client->protocol()->statusList(); !d->text.isEmpty(); d++){ + if (cmpStatus(d->text, args[0])){ + status = d->id; + break; + } + } + if (status != STATUS_UNKNOWN) + break; + } + if (status == STATUS_UNKNOWN){ + out = "Unknown status "; + out += args[0]; + return false; + } + for (n = 0; n < getContacts()->nClients(); n++){ + Client *client = getContacts()->getClient(n); + if (client->getCommonStatus()) + client->setStatus(status, true); + } + if (core->getManualStatus() == status) + return true; + //core->data.ManualStatus.asULong() = status; + core->setValue("ManualStatus", (unsigned int)status); + core->setValue("StatusTime", (unsigned int)time(NULL)); + EventClientStatus().process(); + return true; + } + for (n = 0; n < getContacts()->nClients(); n++){ + Client *client = getContacts()->getClient(n); + if (client->getCommonStatus()){ + const CommandDef *d = NULL; + for (d = client->protocol()->statusList(); !d->text.isEmpty(); d++){ + if (d->id == core->getManualStatus()) + break; + } + if (d){ + out = "STATUS "; + QString tmp = d->text; + tmp = tmp.remove('&'); + out += tmp; + break; + } + } + } + return true; + + case CMD_INVISIBLE: + if (args.size()){ + bool bInvisible = isOn(args[0]); + if (core->value("Invisible").toBool() != bInvisible){ + core->setValue("Invisible", bInvisible); + for (unsigned i = 0; i < getContacts()->nClients(); i++) + getContacts()->getClient(i)->setInvisible(bInvisible); + } + }else{ + out = "INVISIBLE "; + out += core->value("Invisible").toBool() ? "on" : "off"; + } + return true; + case CMD_MAINWND: + w = findWidget("MainWindow"); + if (args.size()){ + if (args[0].toLower() == "toggle"){ + if (w){ + if (w->isVisible()){ + w->hide(); + }else{ + w->show(); + } + } + }else if (isOn(args[0])){ + if (w) + raiseWindow(w); + }else{ + if (w) + w->hide(); + } + }else{ + out += "MAINWINDOW "; + out += (w ? "on" : "off"); + } + return true; + case CMD_SEARCHWND: + w = findWidget("SearchDialog"); + if (args.size()){ + if (isOn(args[0])){ + if (w){ + raiseWindow(w); + }else{ + Command cc; + cc->id = CmdSearch; + EventCommandExec(cc).process(); + } + }else{ + if (w) + w->close(); + } + }else{ + out = "SEARCHWINDOW "; + out += (w ? "on" : "off"); + } + return true; + case CMD_QUIT:{ + Command cc; + cc->id = CmdQuit; + EventCommandExec(cc).process(); + break; + } + case CMD_CLOSE: + bError = true; + return false; + case CMD_OPEN: + case CMD_ADD:{ + Group *grp = NULL; + bool bNewGrp = false; + if (args.size() > 3){ + ContactList::GroupIterator it; + while ((grp = ++it) != NULL){ + if (grp->getName() == args[3]) + break; + } + if (grp == NULL){ + grp = getContacts()->group(0, true); + grp->setName(args[3]); + bNewGrp = true; + } + } + EventAddContact::AddContact ac; + ac.proto = args[0]; + ac.addr = args[1]; + if (args.size() > 2) + ac.nick = args[2]; + ac.group = grp ? grp->id() : 0; + EventAddContact e(&ac); + e.process(); + Contact *contact = e.contact(); + if (contact){ + if (bNewGrp){ + EventGroup e(grp, EventGroup::eChanged); + e.process(); + } + if (nCmd == CMD_OPEN){ + Message *m = new Message(MessageGeneric); + m->setContact(contact->id()); + EventOpenMessage(m).process(); + delete m; + } + return true; + } + if (bNewGrp) + delete grp; + out += "Can't create "; + out += args[1]; + return false; + } + case CMD_DELETE:{ + ContactList::ContactIterator it; + Contact *contact; + while ((contact = ++it) != NULL){ + if (contact->getName() == args[0]){ + delete contact; + return true; + } + } + EventDeleteContact e(args[0]); + if (e.process()) + return true; + out = "Contact "; + out += args[0]; + out += " not found"; + return false; + } + case CMD_SHOW:{ + Command cmd; + if (core->unread.size()) + cmd->id = CmdUnread; + else + return false; + EventCommandExec(cmd).process(); + return true; + } + case CMD_SMS:{ + SMSMessage *m = new SMSMessage; + m->setPhone(args[0]); + m->setText(args[1]); + unsigned i; + for (i = 0; i < getContacts()->nClients(); i++){ + Client *client = getContacts()->getClient(i); + if (client->send(m, NULL)) + return true; + } + return false; + } + case CMD_HELP: + if (args.size() == 0){ + for (c = cmds; c->cmd; c++){ + out += c->cmd; + out += "\t"; + out += c->shortDescr; + out += "\r\n"; + } + }else{ + args[0] = args[0].toUpper(); + for (c = cmds; c->cmd; c++) + if (args[0] == c->cmd) + break; + if (c->cmd == NULL){ + out = "Unknown command "; + out += args[0]; + return false; + } + out = c->cmd; + out += "\t"; + out += c->shortDescr; + out += "\r\n"; //Fixme WIN32 + out += c->longDescr; + } + return true; + } + return false; +} + +void RemotePlugin::setPropertyHub(SIM::PropertyHubPtr hub) +{ + m_propertyHub = hub; +} + +SIM::PropertyHubPtr RemotePlugin::propertyHub() +{ + return m_propertyHub; +} + +QVariant RemotePlugin::value(const QString& key) +{ + return m_propertyHub->value(key); +} + +void RemotePlugin::setValue(const QString& key, const QVariant& v) +{ + m_propertyHub->setValue(key, v); +} + +static char Prompt[] = "\r\n>"; + +ControlSocket::ControlSocket(RemotePlugin *plugin, Socket *socket) +{ + m_plugin = plugin; + m_plugin->m_sockets.push_back(this); + m_socket = new ClientSocket(this); + m_socket->setSocket(socket); + m_socket->setRaw(true); + m_socket->readBuffer().init(0); + m_socket->readBuffer().packetStart(); + write(Prompt); +} + +ControlSocket::~ControlSocket() +{ + for (list::iterator it = m_plugin->m_sockets.begin(); it != m_plugin->m_sockets.end(); ++it){ + if ((*it) == this){ + m_plugin->m_sockets.erase(it); + break; + } + } + delete m_socket; +} + +void ControlSocket::write(const char *msg) +{ + log(L_DEBUG, "Remote write %s", msg); + m_socket->writeBuffer().packetStart(); + m_socket->writeBuffer().pack(msg, strlen(msg)); + m_socket->write(); +} + +bool ControlSocket::error_state(const QString &err, unsigned) +{ + if (!err.isEmpty()) + log(L_WARN, "ControlSocket error %s", qPrintable(err)); + return true; +} + +void ControlSocket::connect_ready() +{ +} + +void ControlSocket::packet_ready() +{ + QByteArray line; + if (!m_socket->readBuffer().scan("\n", line)) + return; + if (line.isEmpty()) + return; + QString strLine=QString(line.data()).trimmed(); + /*if (line[(int)line.length() - 1] == '\r') + line = line.left(line.size() - 1);*/ + log(L_DEBUG, "Remote read: %s", qPrintable(strLine)); + QString out; + bool bError = false; + bool bRes = m_plugin->command(strLine.toLatin1(), out, bError); + if (bError){ + m_socket->error_state(""); + return; + } + if (!bRes) + write("? "); + QByteArray s; + if (!out.isEmpty()) + s = out.toLocal8Bit(); + QByteArray res; + strLine=QString(s).trimmed(); + + //if (!strLine.contains('\n')) + strLine += "\r\n"; + if (strLine.trimmed().isEmpty()) return; + res=strLine.toLocal8Bit(); + + /*for (const char *p = s.data(); *p ; p++){ + if (*p == '\r') + continue; + if (*p == '\n') + res += '\r'; + res += *p; + }*/ + write(res); + write(Prompt); +} + diff --git a/plugins/remote/remote.h b/plugins/remote/remote.h new file mode 100644 index 0000000..fd31ab9 --- /dev/null +++ b/plugins/remote/remote.h @@ -0,0 +1,89 @@ +/*************************************************************************** + remote.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _REMOTE_H +#define _REMOTE_H + +#include "socket/socket.h" +#include "socket/serversocketnotify.h" +#include "propertyhub.h" +#include + +class ControlSocket; + +#ifdef WIN32 + +const unsigned N_SLOTS = 16; + +class IPC; +#define SIM_SHARED "SIMremote." + +const unsigned SLOT_NONE = 0; +const unsigned SLOT_IN = 1; +const unsigned SLOT_OUT = 2; + +#endif + +class RemotePlugin : public QObject, public SIM::Plugin, public SIM::EventReceiver, public SIM::ServerSocketNotify +{ + Q_OBJECT +public: + RemotePlugin(); + RemotePlugin(unsigned, Buffer*); + ~RemotePlugin(); + void bind(); + std::list m_sockets; + + void setPropertyHub(SIM::PropertyHubPtr hub); + SIM::PropertyHubPtr propertyHub(); + QVariant value(const QString& key); + void setValue(const QString& key, const QVariant& v); +public slots: + void command(); + bool command(const QString&, QString&, bool &bError); +protected: + virtual bool accept(SIM::Socket*, unsigned long ip); + virtual void bind_ready(unsigned short port); + virtual bool error(const QString &err); + + virtual bool processEvent(SIM::Event *e); + virtual QByteArray getConfig(); + virtual QWidget *createConfigWindow(QWidget *parent); +#ifdef WIN32 + IPC *ipc; +#endif +// RemoteData data; +private: + SIM::PropertyHubPtr m_propertyHub; +}; + +class ControlSocket : public SIM::ClientSocketNotify +{ +public: + ControlSocket(RemotePlugin *plugin, SIM::Socket *s); + ~ControlSocket(); +protected: + SIM::ClientSocket *m_socket; + RemotePlugin *m_plugin; + void write(const char*); + virtual bool error_state(const QString &err, unsigned code = 0); + virtual void connect_ready(); + virtual void packet_ready(); +}; + +#endif + diff --git a/plugins/remote/remote.rc b/plugins/remote/remote.rc new file mode 100644 index 0000000..722df8f --- /dev/null +++ b/plugins/remote/remote.rc @@ -0,0 +1,97 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,9,6,0 + PRODUCTVERSION 0,9,6,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Vladimir Shutoff\0" + VALUE "FileDescription", "Remote control plugin\0" + VALUE "FileVersion", "0, 9, 6, 0\0" + VALUE "InternalName", "remote\0" + VALUE "LegalCopyright", "Copyright © 2002-2003\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "remote.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "SIM\0" + VALUE "ProductVersion", "0, 9, 6, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/remote/remote.vcproj b/plugins/remote/remote.vcproj new file mode 100644 index 0000000..6a03751 --- /dev/null +++ b/plugins/remote/remote.vcproj @@ -0,0 +1,407 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/remote/remotecfg.cpp b/plugins/remote/remotecfg.cpp new file mode 100644 index 0000000..5466970 --- /dev/null +++ b/plugins/remote/remotecfg.cpp @@ -0,0 +1,113 @@ +/*************************************************************************** + remotecfg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "remotecfg.h" +#include "remote.h" + +#include +#include +#include +#include +#include + +static char TCP[] = "tcp:"; + +RemoteConfig::RemoteConfig(QWidget *parent, RemotePlugin *plugin) : QWidget(parent) +{ + setupUi(this); + m_plugin = plugin; + QString path = m_plugin->value("Path").toString(); + edtPort->setValue(3000); +#ifdef WIN32 + if (path.startsWith(TCP)){ + edtPort->setValue(path.mid(strlen(TCP)).toUShort()); + chkTCP->setChecked(true); + }else{ + edtPort->setValue(3000); + chkTCP->setChecked(false); + } + btnUNIX->hide(); + btnTCP->hide(); + edtPath->hide(); + connect(chkTCP, SIGNAL(toggled(bool)), this, SLOT(toggled(bool))); + toggled(chkTCP->isChecked()); +#else + chkTCP->hide(); + edtPath->setText("/tmp/sim.%user%"); + if (path.startsWith(TCP)){ + btnTCP->setChecked(true); + + edtPort->setValue(path.mid(strlen(TCP)).toUShort()); + edtPath->setEnabled(false); + }else{ + btnUNIX->setChecked(true); + edtPath->setText(path); + edtPort->setEnabled(false); + } + connect(grpRemote, SIGNAL(clicked(int)), this, SLOT(selected(int))); +#endif +#ifdef WIN32 + chkIE->setChecked(m_plugin->value("EnableMenu").toBool()); +#else + chkIE->hide(); +#endif +} + +void RemoteConfig::apply() +{ + QString path; +#ifdef WIN32 + if (chkTCP->isChecked()){ + path = TCP; + path += edtPort->text(); + }else{ + path = "auto:"; + } + m_plugin->setValue("EnableMenu", chkIE->isChecked()); +#else + if (btnTCP->isChecked()){ + path = TCP; + path += edtPort->text(); + }else{ + path = edtPath->text(); + } +#endif + if (path != m_plugin->value("Path").toString()){ + m_plugin->setValue("Path", path); + m_plugin->bind(); + } +} + +void RemoteConfig::selected(int id) +{ + switch (id){ + case 1: + edtPath->setEnabled(true); + edtPort->setEnabled(false); + break; + case 2: + edtPath->setEnabled(false); + edtPort->setEnabled(true); + break; + } +} + +void RemoteConfig::toggled(bool state) +{ + edtPort->setEnabled(state); +} + diff --git a/plugins/remote/remotecfg.h b/plugins/remote/remotecfg.h new file mode 100644 index 0000000..746ca04 --- /dev/null +++ b/plugins/remote/remotecfg.h @@ -0,0 +1,39 @@ +/*************************************************************************** + remotecfg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _REMOTECFG_H +#define _REMOTECFG_H + +#include "ui_remotecfgbase.h" + +class RemotePlugin; + +class RemoteConfig : public QWidget, public Ui::RemoteCfg +{ + Q_OBJECT +public: + RemoteConfig(QWidget *parent, RemotePlugin*); +public slots: + void apply(); + void selected(int); + void toggled(bool); +protected: + RemotePlugin *m_plugin; +}; + +#endif + diff --git a/plugins/remote/remotecfgbase.ui b/plugins/remote/remotecfgbase.ui new file mode 100644 index 0000000..1dfdcd9 --- /dev/null +++ b/plugins/remote/remotecfgbase.ui @@ -0,0 +1,128 @@ + + + RemoteCfg + + + + 0 + 0 + 367 + 216 + + + + Form1 + + + + 6 + + + 11 + + + + + + + + + + + Use &UNIX socket + + + 1 + + + + + + + + + + Use &TCP socket + + + + + + + Use &TCP socket + + + 2 + + + + + + + Port: + + + false + + + + + + + 1 + + + 65535 + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 220 + 20 + + + + + + + + + + + + + + Enable IE context menu extension + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + diff --git a/plugins/remote/resource.h b/plugins/remote/resource.h new file mode 100644 index 0000000..7eaaebd --- /dev/null +++ b/plugins/remote/resource.h @@ -0,0 +1,21 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by sim.rc +#include + +#define IDI_ICON1 1 +#define IDS_PROJNAME 100 +#define IDR_SIMCTRL 101 +#define IDR_SIMCONTROL 102 +#define IDR_SIM_EXT 103 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 200 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 201 +#endif +#endif diff --git a/plugins/remote/sim_remote.cpp b/plugins/remote/sim_remote.cpp new file mode 100644 index 0000000..e0a897f --- /dev/null +++ b/plugins/remote/sim_remote.cpp @@ -0,0 +1,83 @@ +// simremote.cpp : Implementation of DLL Exports. + + +// Note: Proxy/Stub Information +// To build a separate proxy/stub DLL, +// run nmake -f simremoteps.mk in the project directory. + +#define STRICT +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0400 +#endif +#define _ATL_APARTMENT_THREADED + +#include +//You may derive a class from CComModule and use it if you want to override +//something, but do not change the name of _Module +extern CComModule _Module; +#include + +#include "resource.h" +#include +#include "simremote.h" + +#include "simremote_i.c" +#include "SimControl.h" + + +CComModule _Module; + +BEGIN_OBJECT_MAP(ObjectMap) +OBJECT_ENTRY(CLSID_SimControl, CSimControl) +END_OBJECT_MAP() + +///////////////////////////////////////////////////////////////////////////// +// DLL Entry Point + +extern "C" + BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/) +{ + if (dwReason == DLL_PROCESS_ATTACH) + { + _Module.Init(ObjectMap, hInstance, &LIBID_SIMREMOTELib); + DisableThreadLibraryCalls(hInstance); + } + else if (dwReason == DLL_PROCESS_DETACH) + _Module.Term(); + return TRUE; // ok +} + +///////////////////////////////////////////////////////////////////////////// +// Used to determine whether the DLL can be unloaded by OLE + +STDAPI DllCanUnloadNow(void) +{ + return (_Module.GetLockCount()==0) ? S_OK : S_FALSE; +} + +///////////////////////////////////////////////////////////////////////////// +// Returns a class factory to create an object of the requested type + +STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) +{ + return _Module.GetClassObject(rclsid, riid, ppv); +} + +///////////////////////////////////////////////////////////////////////////// +// DllRegisterServer - Adds entries to the system registry + +STDAPI DllRegisterServer(void) +{ + // registers object, typelib and all interfaces in typelib + return _Module.RegisterServer(TRUE); +} + +///////////////////////////////////////////////////////////////////////////// +// DllUnregisterServer - Removes entries from the system registry + +STDAPI DllUnregisterServer(void) +{ + return _Module.UnregisterServer(TRUE); +} + + diff --git a/plugins/remote/simctrl.cpp b/plugins/remote/simctrl.cpp new file mode 100644 index 0000000..c99306e --- /dev/null +++ b/plugins/remote/simctrl.cpp @@ -0,0 +1,477 @@ +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#ifdef HAVE_STDLIB_H + #include +#endif +#ifdef HAVE_STDDEF_H + #include +#endif +#ifdef HAVE_INTTYPES_H + #include +#else +#ifdef HAVE_STDINT_H +#include +#endif +#endif +#ifdef HAVE_UNISTD_H + #include +#endif + +#include +#include + +#ifndef WIN32 + #include + #include + #include + #include + #include + #include + #include + #include +#endif + +#include +#include +#include + +#ifdef WIN32 + #include + #define socklen_t int + #define in_addr_t int +#endif + +#ifndef INADDR_NONE + #define INADDR_NONE 0xFFFFFFFF +#endif + +using namespace std; + +class Processor +{ +public: + Processor() { bInit = false; }; + virtual ~Processor() {}; + virtual bool process(const char *in_str, string &out_str) = 0; + bool bInit; +}; + +class SocketProcessor : public Processor +{ +public: + SocketProcessor(int s); + ~SocketProcessor(); + virtual bool process(const char *in_str, string &out_str); +protected: + int m_s; +}; + +SocketProcessor::SocketProcessor(int s) +{ + m_s = s; + if (s == -1) + return; + bool bCR = false; + for (;;){ + char c; + int rs = recv(m_s, &c, 1, 0); + if (rs <= 0) + return; + if (bCR && (c == '>')) + break; + bCR = (c == '\n'); + } + bInit = true; +} + +SocketProcessor::~SocketProcessor() +{ + if (m_s != -1) +#ifdef WIN32 + closesocket(m_s); +#else + close(m_s); +#endif +} + +bool SocketProcessor::process(const char *in_str, string &out_str) +{ + if (m_s == -1) + return false; + string ss; + ss = in_str; + ss += "\n"; + unsigned size = ss.length(); + const char *p = ss.c_str(); + while (size){ + int ws = send(m_s, p, size, 0); + if (ws <= 0) + return false; + size -= ws; + } + string out; + bool bCR = false; + for (;;){ + char c; + int rs = recv(m_s, &c, 1, 0); + if (rs <= 0) + return false; + if (c == '\r') + continue; + if (bCR && (c == '>')) + break; + out += c; + bCR = (c == '\n'); + } + out = out.substr(0, out.length() - 1); + if ((out.length() >= 2) && (out.substr(0, 2) == "? ")){ + out_str = "?"; + out_str += out.substr(2); + }else{ + out_str += ">"; + out_str += out; + } + return true; +} + +#ifdef WIN32 +#define WS_VERSION_REQD 0x0101 +#endif + +Processor *createTCPProcessor(const char *addr_str) +{ + string addr; + if (addr_str) + addr = addr_str; + if (addr.length() <= 4) + return NULL; + if (addr.substr(0, 4) != "tcp:") + return NULL; +#ifdef WIN32 + WSADATA wsaData; + WSAStartup(WS_VERSION_REQD, &wsaData); +#endif + int s = socket(AF_INET, SOCK_STREAM, 0); + if (s != -1){ + sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_port = 0; + socklen_t addr_len = sizeof(addr); + if (bind(s, (sockaddr*)&addr, addr_len) == -1){ +#ifdef WIN32 + closesocket(s); +#else + close(s); +#endif + s = -1; + } + } + if (s != -1){ + addr = addr.substr(4); + string host; + unsigned port; + int n = addr.find(':'); + if (n > 0){ + host = addr.substr(0, n); + port = atol(addr.substr(n + 1).c_str()); + }else{ + port = atol(addr.c_str()); + } + in_addr_t ip = INADDR_NONE; + if (port){ + if (!host.empty()){ + ip = inet_addr(host.c_str()); + hostent *h = gethostbyname(host.c_str()); + if (h) + ip = *((int*)(*(h->h_addr_list))); + }else{ + ip = inet_addr("127.0.0.1"); + } + } + if (ip == INADDR_NONE){ +#ifdef WIN32 + closesocket(s); +#else + close(s); +#endif + s = -1; + }else{ + sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = ip; + addr.sin_port = htons((u_short)port); + socklen_t addr_len = sizeof(addr); + if (connect(s, (sockaddr*)&addr, addr_len) == -1){ +#ifdef WIN32 + closesocket(s); +#else + close(s); +#endif + s = -1; + } + } + } + return new SocketProcessor(s); +} + +#ifdef WIN32 + +#include +#include +extern CComModule _Module; +#include +#include + +class AutoProcessor : public Processor +{ +public: + AutoProcessor(); + virtual bool process(const char *in_str, string &out_str); +protected: + CComDispatchDriver disp; +}; + +AutoProcessor::AutoProcessor() +{ + CoInitialize(NULL); + + CLSID clsid; + HRESULT hResult; + hResult = CLSIDFromProgID(L"Simremote.SimControl", &clsid); + if (FAILED(hResult)) + return; + + CComPtr pUnk; + hResult = pUnk.CoCreateInstance(clsid); + if (FAILED(hResult)) + return; + disp = pUnk; + bInit = true; +} + +bool AutoProcessor::process(const char *in_str, string &out_str) +{ + if (!bInit) + return false; + CComBSTR str(in_str); + CComVariant vArg(str); + CComVariant vRes; + HRESULT hResult = disp.Invoke1(L"Process", &vArg, &vRes); + if (FAILED(hResult)) + return false; + CComBSTR out(vRes.bstrVal); + if (out.Length()){ + size_t size = WideCharToMultiByte(CP_ACP, 0, out, wcslen(out), 0, 0, NULL, NULL); + char *res = new char[size + 1]; + size = WideCharToMultiByte(CP_ACP, 0, out, wcslen(out), res, size, NULL, NULL); + res[size] = 0; + out_str = res; + delete[] res; + }else{ + return false; + } + return true; +} + +Processor *createProcessor(const char *addr_str) +{ + Processor *processor = createTCPProcessor(addr_str); + if (processor) + return processor; + string addr; + if (addr_str) + addr = addr_str; + if (addr.empty()) + addr = "auto:"; + int n = addr.find(':'); + if (n < 0) + return NULL; + string proto = addr.substr(0, n); + addr = addr.substr(n + 1); + if (proto == "auto") + return new AutoProcessor; + return NULL; +} + +#else + +Processor *createProcessor(const char *addr_str) +{ + Processor *processor = createTCPProcessor(addr_str); + if (processor != NULL) + return processor; + string addr = "/tmp/sim.%user%"; + if (addr_str) + addr = addr_str; + int n = addr.find("%user%"); + if (n >= 0){ + uid_t uid = getuid(); + struct passwd *pwd = getpwuid(uid); + string user; + if (pwd){ + user = pwd->pw_name; + }else{ + char b[32]; + sprintf(b, "%u", uid); + user = b; + } + addr = addr.substr(0, n) + user + addr.substr(n + 6); + } + int s = socket(PF_UNIX, SOCK_STREAM, 0); + if (s < 0){ + fprintf(stderr, "Can't create socket: %s\n", strerror(errno)); + return NULL; + } + + char local_name[256]; + int tmpfd; + strcpy(local_name, "/tmp/sim.XXXXXX"); + if ((tmpfd = mkstemp(local_name)) == -1) + return NULL; + close(tmpfd); + + struct sockaddr_un sun_local; + sun_local.sun_family = AF_UNIX; + strcpy(sun_local.sun_path, local_name); + unlink(local_name); + if (bind(s, (struct sockaddr*)&sun_local, sizeof(sun_local)) < 0){ + fprintf(stderr, "Can't bind socket %s: %s\n", local_name, strerror(errno)); + return NULL; + } + + struct sockaddr_un sun_remote; + sun_remote.sun_family = AF_UNIX; + strcpy(sun_remote.sun_path, addr.c_str()); + if (connect(s, (struct sockaddr*)&sun_remote, sizeof(sun_remote)) < 0){ + fprintf(stderr, "Can't connect to %s: %s\n", addr.c_str(), strerror(errno)); + unlink(local_name); + return NULL; + } + unlink(local_name); + return new SocketProcessor(s); +} + +#endif + +static void usage(char *s) +{ +#ifndef WIN32 + uid_t uid = getuid(); + struct passwd *pwd = getpwuid(uid); + char uid_buf[256]; + char *name = NULL; + if (pwd){ + name = pwd->pw_name; + }else{ + snprintf(uid_buf, sizeof(uid_buf), "%u", uid); + name = uid_buf; + } +#endif + fprintf(stderr, + "usage: %s [options] [uin files]\n" + "Options are: [followed by default value]:\n" +#ifndef WIN32 + " -s socket [/tmp/sim.%s] Control socket\n" +#endif + // " -d Debug mode\n" + " -c command Command\n" + " -h Show this help\n" + "\n", + s +#ifndef WIN32 + ,name +#endif + ); +} + +int main(int, char **argv) +{ + list uins; + const char *cmd = NULL; + const char *addr = NULL; + for (char **p = argv + 1; *p; p++){ + if (!strcmp(*p, "-h")){ + usage(argv[0]); + return 0; + } + if (!strcmp(*p, "-s")){ + p++; + if (*p == NULL){ + usage(argv[0]); + return 1; + } + addr = *p; + continue; + } + if (!strcmp(*p, "-c")){ + p++; + if (*p == NULL){ + usage(argv[0]); + return 1; + } + cmd = *p; + continue; + } + uins.push_back(*p); + } + auto_ptr processor(createProcessor(addr)); + if ((processor.get() == NULL) || !processor->bInit){ + fprintf(stderr, "Can't create processor\n"); + return 1; + } + if (uins.size()){ + for (list::iterator it = uins.begin(); it != uins.end(); ++it){ + string in_str; + in_str = "FILE \""; + in_str += *it; + in_str += "\""; + string out_str; + if (!processor->process(in_str.c_str(), out_str)) + break; + } + return 0; + } + if (cmd){ + string out_str; + if (!processor->process(cmd, out_str)){ + fprintf(stderr, "Can't execute %s\n", cmd); + exit(1); + } + if (out_str.empty()){ + fprintf(stderr, "No answer\n"); + exit(1); + } + if (out_str[0] != '>'){ + fprintf(stderr, "Execute %s fail\n", cmd); + exit(1); + } + printf("%s\n", out_str.c_str() + 1); + exit(0); + } + FILE *f = stdin; + while (!feof(f) && !ferror(f)){ + printf(">"); + char buf[4096]; + char *line = fgets(buf, sizeof(buf), f); + if (line == NULL) + break; + if (strlen(line) && (line[strlen(line) - 1] == '\n')) + line[strlen(line) - 1] = 0; + if (strlen(line) && (line[strlen(line) - 1] == '\r')) + line[strlen(line) - 1] = 0; + string out_str; + if (!processor->process(line, out_str)) + break; + if (out_str.empty()) + break; + bool bBad = (out_str[0] == '?'); + out_str = out_str.substr(1); + if (bBad) + printf("? "); + printf("%s\n", out_str.c_str()); + } + return 0; +} diff --git a/plugins/remote/simctrl.desktop b/plugins/remote/simctrl.desktop new file mode 100644 index 0000000..659b447 --- /dev/null +++ b/plugins/remote/simctrl.desktop @@ -0,0 +1,11 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=simctrl +Icon=licq +Type=Service +MimeType=application/x-icq; +GenericName=SIM remote control +Terminal=false +Exec=simctrl +X-KDE-StartupNotify=true +X-DCOP-ServiceType=Unique diff --git a/plugins/remote/simctrl.vcproj b/plugins/remote/simctrl.vcproj new file mode 100644 index 0000000..40b3fe9 --- /dev/null +++ b/plugins/remote/simctrl.vcproj @@ -0,0 +1,232 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/remote/simext.cpp b/plugins/remote/simext.cpp new file mode 100644 index 0000000..afb6977 --- /dev/null +++ b/plugins/remote/simext.cpp @@ -0,0 +1,76 @@ +// simext.cpp : Implementation of DLL Exports. + + +// Note: Proxy/Stub Information +// To build a separate proxy/stub DLL, +// run nmake -f simextps.mk in the project directory. + +#include +extern CComModule _Module; +#include + +#include "resource.h" +#include +#include "simext.h" + +#include "simext_i.c" +#include "SIM_ext.h" + + +CComModule _Module; + +BEGIN_OBJECT_MAP(ObjectMap) +OBJECT_ENTRY(CLSID_SIM_ext, CSIM_ext) +END_OBJECT_MAP() + +///////////////////////////////////////////////////////////////////////////// +// DLL Entry Point + +extern "C" + BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/) +{ + CSIM_ext::hInstance = hInstance; + if (dwReason == DLL_PROCESS_ATTACH) + { + _Module.Init(ObjectMap, hInstance, &LIBID_SIMEXTLib); + DisableThreadLibraryCalls(hInstance); + } + else if (dwReason == DLL_PROCESS_DETACH) + _Module.Term(); + return TRUE; // ok +} + +///////////////////////////////////////////////////////////////////////////// +// Used to determine whether the DLL can be unloaded by OLE + +STDAPI DllCanUnloadNow(void) +{ + return (_Module.GetLockCount()==0) ? S_OK : S_FALSE; +} + +///////////////////////////////////////////////////////////////////////////// +// Returns a class factory to create an object of the requested type + +STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) +{ + return _Module.GetClassObject(rclsid, riid, ppv); +} + +///////////////////////////////////////////////////////////////////////////// +// DllRegisterServer - Adds entries to the system registry + +STDAPI DllRegisterServer(void) +{ + // registers object, typelib and all interfaces in typelib + return _Module.RegisterServer(TRUE); +} + +///////////////////////////////////////////////////////////////////////////// +// DllUnregisterServer - Removes entries from the system registry + +STDAPI DllUnregisterServer(void) +{ + return _Module.UnregisterServer(TRUE); +} + + diff --git a/plugins/remote/simext.def b/plugins/remote/simext.def new file mode 100644 index 0000000..61d74b0 --- /dev/null +++ b/plugins/remote/simext.def @@ -0,0 +1,9 @@ +; simext.def : Declares the module parameters. + +LIBRARY "simext.DLL" + +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE diff --git a/plugins/remote/simext.idl b/plugins/remote/simext.idl new file mode 100644 index 0000000..ff32f0c --- /dev/null +++ b/plugins/remote/simext.idl @@ -0,0 +1,38 @@ +// simext.idl : IDL source for simext.dll +// + +// This file will be processed by the MIDL tool to +// produce the type library (simext.tlb) and marshalling code. + +import "oaidl.idl"; +import "ocidl.idl"; + [ + object, + uuid(7A6FBB28-B284-4731-97AF-9AE32EA0BB89), + + helpstring("ISIM_ext Interface"), + pointer_default(unique) + ] + interface ISIM_ext : IUnknown + { + }; + +[ + uuid(F67751E0-1470-447C-8B3E-000D155711A2), + version(1.0), + helpstring("simext 1.0 Type Library") +] +library SIMEXTLib +{ + importlib("stdole32.tlb"); + importlib("stdole2.tlb"); + + [ + uuid(8DD848D4-81E7-490E-9A3D-CE9058956208), + helpstring("SIM_ext Class") + ] + coclass SIM_ext + { + [default] interface ISIM_ext; + }; +}; diff --git a/plugins/remote/simext.rc b/plugins/remote/simext.rc new file mode 100644 index 0000000..d196c84 --- /dev/null +++ b/plugins/remote/simext.rc @@ -0,0 +1,140 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Russian resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS) +#ifdef _WIN32 +LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT +#pragma code_page(1251) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// REGISTRY +// + +IDR_SIM_EXT REGISTRY DISCARDABLE "SIM_ext.rgs" +#endif // Russian resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "1 TYPELIB ""simext.tlb""\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,9 + PRODUCTVERSION 1,0,0,9 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "\0" + VALUE "FileDescription", "simext Module\0" + VALUE "FileVersion", "1, 0, 0, 9\0" + VALUE "InternalName", "simext\0" + VALUE "LegalCopyright", "Copyright 2003\0" + VALUE "LegalTrademarks", "\0" + VALUE "OLESelfRegister", "\0" + VALUE "OriginalFilename", "simext.DLL\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "simext Module\0" + VALUE "ProductVersion", "1, 0, 0, 9\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + IDS_PROJNAME "simext" +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +1 TYPELIB "simext.tlb" + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/remote/simext.vcproj b/plugins/remote/simext.vcproj new file mode 100644 index 0000000..80db281 --- /dev/null +++ b/plugins/remote/simext.vcproj @@ -0,0 +1,331 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/remote/simipc.cpp b/plugins/remote/simipc.cpp new file mode 100644 index 0000000..9da8dbf --- /dev/null +++ b/plugins/remote/simipc.cpp @@ -0,0 +1,29 @@ +/*************************************************************************** + simipc.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include + +extern "C" bool ProcessStr(BSTR in_str, BSTR *out_str); + +int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR cmdLine, int) +{ + CComBSTR in("FILE "); + in.Append(cmdLine); + CComBSTR out; + ProcessStr(in, &out); + return 0; +} diff --git a/plugins/remote/simipc.vcproj b/plugins/remote/simipc.vcproj new file mode 100644 index 0000000..cf35b82 --- /dev/null +++ b/plugins/remote/simipc.vcproj @@ -0,0 +1,240 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/remote/simremote.def b/plugins/remote/simremote.def new file mode 100644 index 0000000..0e0218a --- /dev/null +++ b/plugins/remote/simremote.def @@ -0,0 +1,9 @@ +; simremote.def : Declares the module parameters. + +LIBRARY "simremote.DLL" + +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE diff --git a/plugins/remote/simremote.idl b/plugins/remote/simremote.idl new file mode 100644 index 0000000..2b52c01 --- /dev/null +++ b/plugins/remote/simremote.idl @@ -0,0 +1,38 @@ +// simremote.idl : IDL source for simremote.dll +// + +// This file will be processed by the MIDL tool to +// produce the type library (simremote.tlb) and marshalling code. + +import "oaidl.idl"; +import "ocidl.idl"; + [ + object, + uuid(1FE1EEB0-0BC8-4D7F-B0E4-B57AC5DC5E52), + dual, + helpstring("ISimControl Interface"), + pointer_default(unique) + ] + interface ISimControl : IDispatch + { + [propget, id(1), helpstring("property Running")] HRESULT Running([out, retval] BOOL *pVal); + [id(2), helpstring("method Process")] HRESULT Process([in] BSTR in_str, [out, retval] BSTR *out_str); + }; +[ + uuid(C4826912-0E46-445E-8B03-9683AAF5143F), + version(1.0), + helpstring("simremote 1.0 Type Library") +] +library SIMREMOTELib +{ + importlib("stdole32.tlb"); + importlib("stdole2.tlb"); + [ + uuid(0B4C5D94-61D9-41C6-AD05-4750A0E86C2E), + helpstring("SimControl Class") + ] + coclass SimControl + { + [default] interface ISimControl; + }; +}; diff --git a/plugins/remote/simremote.rc b/plugins/remote/simremote.rc new file mode 100644 index 0000000..e74e1a7 --- /dev/null +++ b/plugins/remote/simremote.rc @@ -0,0 +1,140 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Russian resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS) +#ifdef _WIN32 +LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT +#pragma code_page(1251) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// REGISTRY +// + +IDR_SIMCONTROL REGISTRY DISCARDABLE "SimControl.rgs" +#endif // Russian resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "1 TYPELIB ""simremote.tlb""\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,6 + PRODUCTVERSION 1,0,0,6 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "\0" + VALUE "FileDescription", "simremote Module\0" + VALUE "FileVersion", "1, 0, 0, 6\0" + VALUE "InternalName", "simremote\0" + VALUE "LegalCopyright", "Copyright 2003\0" + VALUE "LegalTrademarks", "\0" + VALUE "OLESelfRegister", "\0" + VALUE "OriginalFilename", "simremote.DLL\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "simremote Module\0" + VALUE "ProductVersion", "1, 0, 0, 6\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + IDS_PROJNAME "simremote" +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +1 TYPELIB "simremote.tlb" + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/remote/simremote.vcproj b/plugins/remote/simremote.vcproj new file mode 100644 index 0000000..9ea545e --- /dev/null +++ b/plugins/remote/simremote.vcproj @@ -0,0 +1,333 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/remote/x-icq.desktop b/plugins/remote/x-icq.desktop new file mode 100644 index 0000000..697acec --- /dev/null +++ b/plugins/remote/x-icq.desktop @@ -0,0 +1,51 @@ +[Desktop Entry] +Encoding=UTF-8 +Comment=ICQ Contact +Comment[ar]=جهة اتصال على ICQ +Comment[be]=Кантакт ICQ +Comment[bg]=Връзка Ñ ICQ Contact +Comment[br]=Darempred ICQ +Comment[bs]=ICQ kontakt +Comment[ca]=Contacte ICQ +Comment[cs]=ICQ kontakt +Comment[cy]=Cysylltiad ICQ +Comment[da]=ICQ-Kontakt +Comment[de]=ICQ-Kontakt +Comment[el]=Επαφή ICQ +Comment[es]=Contacto de ICQ +Comment[et]=ICQ kontakt +Comment[eu]=ICQ kontaktua +Comment[fi]=ICQ-kontakti +Comment[fr]=Contact ICQ +Comment[gl]=Contacto ICQ +Comment[he]=×יש-קשר ICQ +Comment[hi]=आईसीकà¥à¤¯à¥‚ समà¥à¤ªà¤°à¥à¤• +Comment[hr]=ICQ kontakt +Comment[hu]=ICQ-kapcsolat +Comment[is]=ICQ tengiliður +Comment[it]=Contatto ICQ +Comment[ja]=ICQコンタクト +Comment[mk]=Контакт на ICQ +Comment[nb]=ICQ kontakt +Comment[nl]=ICQ contact +Comment[nn]=ICQ-kontakt +Comment[pl]=Kontakt ICQ +Comment[pt]=Contacto de ICQ +Comment[pt_BR]=Contato ICQ +Comment[ru]=Контакт ICQ +Comment[se]=ICQ-oktavuohta +Comment[sk]=Kontakt ICQ +Comment[sl]=Stik ICQ +Comment[sr]=ICQ контакт +Comment[sr@Latn]=ICQ kontakt +Comment[sv]=ICQ-kontakt +Comment[ta]=ICQ தொடரà¯à®ªà¯ +Comment[tg]=ПайваÑтшавии ICQ +Comment[tr]=ICQ BaÄŸlantısı +Comment[uk]=Контакт ICQ +Comment[xx]=xxICQ Contactxx +Comment[zh_CN]=ICQ è”系人 +Type=MimeType +MimeType=application/x-icq +Patterns=*.uin;*.icq +Icon=licq diff --git a/plugins/replace/CMakeLists.txt b/plugins/replace/CMakeLists.txt new file mode 100644 index 0000000..238d67a --- /dev/null +++ b/plugins/replace/CMakeLists.txt @@ -0,0 +1,20 @@ +################### +# replace library # +################### +IF(BUILD_DROPPED) +SET(replace_SRCS + replace.cpp + replacecfg.cpp +) + +SET(replace_HDRS + replace.h + replacecfg.h +) + +SET(replace_UICS + replacecfgbase.ui +) + +SIM_ADD_PLUGIN(replace) +ENDIF(BUILD_DROPPED) diff --git a/plugins/replace/replace.cpp b/plugins/replace/replace.cpp new file mode 100644 index 0000000..3ca15cf --- /dev/null +++ b/plugins/replace/replace.cpp @@ -0,0 +1,172 @@ +/*************************************************************************** + replace.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "replace.h" +#include "replacecfg.h" +#include "simgui/textshow.h" +#include "html.h" +#include "misc.h" + +#include "profile.h" +#include "profilemanager.h" + +#include +#include + +using namespace std; +using namespace SIM; + +Plugin *createReplacePlugin(unsigned base, bool, Buffer *cfg) +{ + Plugin *plugin = new ReplacePlugin(base, cfg); + return plugin; +} + +static PluginInfo info = + { + I18N_NOOP("Replace text"), + I18N_NOOP("Plugin provides text replacing in message edit window"), + VERSION, + createReplacePlugin, + PLUGIN_DEFAULT + }; + +EXPORT_PROC PluginInfo* GetPluginInfo() +{ + return &info; +} + + +ReplacePlugin::ReplacePlugin(unsigned base, Buffer *cfg) + : QObject(), Plugin(base) + , EventReceiver() +{ + m_propertyHub = SIM::PropertyHub::create("replace"); + qApp->installEventFilter(this); +} + +ReplacePlugin::~ReplacePlugin() +{ + +} + +QByteArray ReplacePlugin::getConfig() +{ + return QByteArray(); +} + +QWidget *ReplacePlugin::createConfigWindow(QWidget *parent) +{ + return new ReplaceCfg(parent, this); +} + +class _UnquoteParser : public HTMLParser +{ +public: + _UnquoteParser(const QString &text); + QString m_text; +protected: + virtual void text(const QString &text); + virtual void tag_start(const QString &tag, const list &options); + virtual void tag_end(const QString &tag); +}; + +_UnquoteParser::_UnquoteParser(const QString &text) +{ + parse(text); +} + +void _UnquoteParser::text(const QString &text) +{ + m_text += text; +} + +void _UnquoteParser::tag_start(const QString &tag, const list&) +{ + if (tag == "img") + m_text += ' '; + if (tag == "br") + m_text += '\n'; +} + +void _UnquoteParser::tag_end(const QString&) +{ +} + +bool ReplacePlugin::eventFilter(QObject *o, QEvent *e) +{ + if ((e->type() == QEvent::KeyPress) && o->inherits("MsgTextEdit")){ + QKeyEvent *ke = (QKeyEvent*)e; + if ((ke->key() == Qt::Key_Enter) || (ke->key() == Qt::Key_Return) || (ke->key() == Qt::Key_Space)){ +/* + TextEdit *edit = (TextEdit*)o; + int paraFrom, paraTo, indexFrom, indexTo; + edit->getSelection(¶From, &indexFrom, ¶To, &indexTo); + if ((paraFrom == paraTo) && (indexFrom == indexTo)){ + int parag, index; + edit->getCursorPosition(¶g, &index); + _UnquoteParser p(edit->text(parag)); + QString text = p.m_text.left(index); + for (unsigned i = 1; i <= value("Keys").toUInt(); i++){ + QString key = value("Key").toStringList().value(i); + if (key.length() > text.length()) + continue; + if (key != text.mid(text.length() - key.length())) + continue; + if ((key.length() < text.length()) && !text[(int)(text.length() - key.length() - 1)].isSpace()) + continue; + edit->setSelection(parag, index - key.length(), parag, index, 0); + edit->insert(value("Value").toStringList().value(i), false, false); + break; + } + } +*/ + } + } + return QObject::eventFilter(o, e); +} + +bool ReplacePlugin::processEvent(SIM::Event *e) +{ + if(e->type() == eEventPluginLoadConfig) + { + PropertyHubPtr hub = ProfileManager::instance()->getPropertyHub("replace"); + if(!hub.isNull()) + setPropertyHub(hub); + } + return false; +} + +void ReplacePlugin::setPropertyHub(SIM::PropertyHubPtr hub) +{ + m_propertyHub = hub; +} + +SIM::PropertyHubPtr ReplacePlugin::propertyHub() +{ + return m_propertyHub; +} + +QVariant ReplacePlugin::value(const QString& key) +{ + return m_propertyHub->value(key); +} + +void ReplacePlugin::setValue(const QString& key, const QVariant& v) +{ + m_propertyHub->setValue(key, v); +} diff --git a/plugins/replace/replace.h b/plugins/replace/replace.h new file mode 100644 index 0000000..6ea74d8 --- /dev/null +++ b/plugins/replace/replace.h @@ -0,0 +1,50 @@ +/*************************************************************************** + replace.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _REPLACE_H +#define _REPLACE_H + +#include + +#include "cfg.h" +#include "plugins.h" +#include "propertyhub.h" +#include "event.h" + +class ReplacePlugin : public QObject, public SIM::Plugin, public SIM::EventReceiver +{ + Q_OBJECT +public: + ReplacePlugin(unsigned, Buffer *cfg); + virtual ~ReplacePlugin(); + void setPropertyHub(SIM::PropertyHubPtr hub); + SIM::PropertyHubPtr propertyHub(); + QVariant value(const QString& key); + void setValue(const QString& key, const QVariant& v); + +protected: + virtual bool processEvent(SIM::Event *e); + virtual QByteArray getConfig(); + virtual QWidget *createConfigWindow(QWidget *parent); + bool eventFilter(QObject *o, QEvent *e); + +private: + SIM::PropertyHubPtr m_propertyHub; +}; + +#endif + diff --git a/plugins/replace/replace.rc b/plugins/replace/replace.rc new file mode 100644 index 0000000..1cd33cb --- /dev/null +++ b/plugins/replace/replace.rc @@ -0,0 +1,97 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,9,6,0 + PRODUCTVERSION 0,9,6,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Vladimir Shutoff\0" + VALUE "FileDescription", "Replace text plugin\0" + VALUE "FileVersion", "0, 9, 6, 0\0" + VALUE "InternalName", "replace\0" + VALUE "LegalCopyright", "Copyright © 2002-2003\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "replace.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "SIM\0" + VALUE "ProductVersion", "0, 9, 6, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/replace/replace.vcproj b/plugins/replace/replace.vcproj new file mode 100644 index 0000000..14887cc --- /dev/null +++ b/plugins/replace/replace.vcproj @@ -0,0 +1,412 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/replace/replacecfg.cpp b/plugins/replace/replacecfg.cpp new file mode 100644 index 0000000..c4e9e86 --- /dev/null +++ b/plugins/replace/replacecfg.cpp @@ -0,0 +1,111 @@ +/*************************************************************************** + replacecfg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "replacecfg.h" + +#include "replace.h" + +ReplaceCfg::ReplaceCfg(QWidget *parent, ReplacePlugin *plugin) + : QWidget(parent) + , m_plugin( plugin ) +{ + setupUi(this); + unsigned uCount = m_plugin->value("Keys").toUInt(); + for (unsigned i = 0; i < uCount; i++){ + QString sKey = m_plugin->value("Key").toStringList().value(i); + QString sValue = m_plugin->value("Value").toStringList().value(i); + if (!sKey.isEmpty()) { + addString( sKey, sValue ); + } + } + addString( QString(), QString() ); + connect(lstKeys,SIGNAL(cellChanged(int,int)),SLOT(cellChanged(int,int))); + autosizeColumns(); +} + +ReplaceCfg::~ReplaceCfg() +{ +} + +void ReplaceCfg::apply() +{ + QStringList keys; + QStringList values; + for( int row = 0 ; row < lstKeys->rowCount() ; row++ ){ + QString sKey; + QString sValue; + if( string( row, sKey, sValue ) && !sKey.isEmpty() ) { + keys.push_back(sKey); + values.push_back(sValue); + } + } + m_plugin->setValue("Key", keys); + m_plugin->setValue("Value", values); + m_plugin->setValue("Keys", keys.count()); +} + +bool ReplaceCfg::string( int row, QString &sKey, QString &sValue ) { + QTableWidgetItem *item = lstKeys->item( row, 0 ); + if( NULL == item ) + sKey.clear(); + else + sKey = item->data( Qt::DisplayRole ).toString(); + item = lstKeys->item( row, 1 ); + if( NULL == item ) + sValue.clear(); + else + sValue = item->data( Qt::DisplayRole ).toString(); + + return true; +} + +void ReplaceCfg::addString( QString sKey, QString sValue ) { + int row = lstKeys->rowCount(); + lstKeys->insertRow( row ); + if( !sKey.isEmpty() ) + lstKeys->setItem( row, 0, new QTableWidgetItem( sKey ) ); + if( !sValue.isEmpty() ) + lstKeys->setItem( row, 1, new QTableWidgetItem( sValue ) ); +} + +void ReplaceCfg::cellChanged( int row, int column ) { + autosizeColumns(); + QString sKey; + QString sValue; + if( !string( row, sKey, sValue ) ) + return; + if( sKey.isEmpty() && sValue.isEmpty() ) { + lstKeys->removeRow( row ); + } + if( lstKeys->rowCount() == 0 ) { + addString( QString(), QString() ); + return; + } + if( !string( lstKeys->rowCount()-1, sKey, sValue ) ) + return; + if( !sKey.isEmpty() || !sValue.isEmpty() ) { + addString( QString(), QString() ); + } +} + +void ReplaceCfg::autosizeColumns() { + lstKeys->resizeColumnToContents( 0 ); + int width = lstKeys->columnWidth( 0 ); + if( width < 100 ) { + lstKeys->setColumnWidth( 0, 100 ); + } +} diff --git a/plugins/replace/replacecfg.h b/plugins/replace/replacecfg.h new file mode 100644 index 0000000..bb62d42 --- /dev/null +++ b/plugins/replace/replacecfg.h @@ -0,0 +1,46 @@ +/*************************************************************************** + replacecfg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _REPLACECFG_H +#define _REPLACECFG_H + +#include "ui_replacecfgbase.h" + +class ReplacePlugin; + +class ReplaceCfg : public QWidget, public Ui::ReplaceCfgBase +{ + Q_OBJECT + +public: + ReplaceCfg(QWidget *parent, ReplacePlugin *plugin); + virtual ~ReplaceCfg(); + +public slots: + void apply(); + void cellChanged( int row, int column ); + +protected: + bool string( int row, QString &sKey, QString &sValue ); + void addString( QString sKey, QString sValue ); + void autosizeColumns(); + + ReplacePlugin *m_plugin; +}; + +#endif + diff --git a/plugins/replace/replacecfgbase.ui b/plugins/replace/replacecfgbase.ui new file mode 100644 index 0000000..6fe8477 --- /dev/null +++ b/plugins/replace/replacecfgbase.ui @@ -0,0 +1,68 @@ + + + ReplaceCfgBase + + + + 0 + 0 + 301 + 226 + + + + Form1 + + + + 6 + + + 11 + + + + + 2 + + + 100 + + + 100 + + + true + + + false + + + 18 + + + 18 + + + true + + + 100 + + + + You type + + + + + You send + + + + + + + + + diff --git a/plugins/shortcuts/CMakeLists.txt b/plugins/shortcuts/CMakeLists.txt new file mode 100644 index 0000000..7d5e7cf --- /dev/null +++ b/plugins/shortcuts/CMakeLists.txt @@ -0,0 +1,23 @@ +##################### +# shortcuts library # +##################### +IF(BUILD_DROPPED) +SET(shortcuts_SRCS + mousecfg.cpp + shortcutcfg.cpp + shortcuts.cpp +) + +SET(shortcuts_HDRS + mousecfg.h + shortcutcfg.h + shortcuts.h +) + +SET(shortcuts_UICS + mousecfgbase.ui + shortcutcfgbase.ui +) + +SIM_ADD_PLUGIN(shortcuts) +ENDIF(BUILD_DROPPED) diff --git a/plugins/shortcuts/configure.in.in b/plugins/shortcuts/configure.in.in new file mode 100644 index 0000000..f247526 --- /dev/null +++ b/plugins/shortcuts/configure.in.in @@ -0,0 +1 @@ +AM_CONDITIONAL(ENABLE_SHORTCUTS, test "$kde_use_qt_mac" != "yes") diff --git a/plugins/shortcuts/mousecfg.cpp b/plugins/shortcuts/mousecfg.cpp new file mode 100644 index 0000000..b4e9ab5 --- /dev/null +++ b/plugins/shortcuts/mousecfg.cpp @@ -0,0 +1,184 @@ +/*************************************************************************** + mousecfg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "cmddef.h" +#include "misc.h" +#include "core_consts.h" + +#include "mousecfg.h" +#include "shortcuts.h" + +using namespace SIM; + +MouseConfig::MouseConfig(QWidget *parent, ShortcutsPlugin *plugin) : QWidget(parent) +{ + setupUi(this); + m_plugin = plugin; + //lstCmd->setSorting(0); + loadMenu(MenuMain); + loadMenu(MenuGroup); + loadMenu(MenuContact); + adjustColumns(); + cmbButton->insertItem(INT_MAX,""); + cmbButton->insertItem(INT_MAX,i18n("Left click")); + cmbButton->insertItem(INT_MAX,i18n("Right click")); + cmbButton->insertItem(INT_MAX,i18n("Middle click")); + cmbButton->insertItem(INT_MAX,i18n("Left dblclick")); + cmbButton->insertItem(INT_MAX,i18n("Right dblclick")); + cmbButton->insertItem(INT_MAX,i18n("Middle dblclick")); + selectionChanged(); + connect(lstCmd, SIGNAL(itemSelectionChanged()), this, SLOT(selectionChanged())); + connect(cmbButton, SIGNAL(activated(int)), this, SLOT(buttonChanged(int))); + connect(chkAlt, SIGNAL(toggled(bool)), this, SLOT(changed(bool))); + connect(chkCtrl, SIGNAL(toggled(bool)), this, SLOT(changed(bool))); + connect(chkShift, SIGNAL(toggled(bool)), this, SLOT(changed(bool))); +} + +MouseConfig::~MouseConfig() +{ +} + +void MouseConfig::apply() +{ + QMap map; + for(int i = 0; i < lstCmd->topLevelItemCount(); i++) + { + QTreeWidgetItem* item = lstCmd->topLevelItem(i); + map.insert(item->text(2), item->text(1).toLatin1()); + } + m_plugin->setValue("Mouse", map); +} + +void MouseConfig::resizeEvent(QResizeEvent *e) +{ + QWidget::resizeEvent(e); + adjustColumns(); +} + +void MouseConfig::adjustColumns() +{ + QScrollBar *bar = lstCmd->verticalScrollBar(); + int wScroll = 0; + if (bar && bar->isVisible()) + wScroll = bar->width(); + lstCmd->setColumnWidth(0, lstCmd->width() - + lstCmd->columnWidth(1) - 4 - wScroll); +} + +void MouseConfig::loadMenu(unsigned long id) +{ + EventMenuGetDef eMenu(id); + eMenu.process(); + CommandsDef *def = eMenu.defs(); + if (def){ + CommandsList list(*def, true); + CommandDef *s; + while ((s = ++list) != NULL){ + if ((s->id == 0) || (s->popup_id == 0)) + continue; + QString title = i18n(s->text); + if (title == "_") + continue; + QTreeWidgetItem *item = NULL; + for(int i = 0; i < lstCmd->topLevelItemCount(); i++) + { + item = lstCmd->topLevelItem(i); + if (QString::number(s->popup_id) == item->text(3)) + break; + } + if ( NULL != item) + continue; + title = title.remove('&'); + QTreeWidgetItem* it = new QTreeWidgetItem(lstCmd, QStringList(title)); + it->setText(1, m_plugin->value("Mouse").toMap().value(QString::number(s->id)).toString()); + it->setText(2, QString::number(s->id)); + it->setText(3, QString::number(s->popup_id)); + } + } +} + +void MouseConfig::selectionChanged() +{ + QTreeWidgetItem *item = lstCmd->currentItem(); + if (item == NULL){ + lblCmd->setText(""); + cmbButton->setCurrentIndex(0); + cmbButton->setEnabled(false); + return; + } + lblCmd->setText(item->text(0)); + int n = ShortcutsPlugin::stringToButton(item->text(1).toLatin1()); +// ToDo: Restore this +// if (n == 0) +// chkAlt->setChecked((n & Qt::AltButton) != 0); +// chkCtrl->setChecked((n & Qt::ControlButton) != 0); +// chkShift->setChecked((n & Qt::ShiftButton) != 0); + cmbButton->setEnabled(true); + cmbButton->setCurrentIndex(n); + buttonChanged(0); +} + +void MouseConfig::buttonChanged(int) +{ + if (cmbButton->currentIndex()){ + chkAlt->setEnabled(true); + chkCtrl->setEnabled(true); + chkShift->setEnabled(true); + }else{ + chkAlt->setChecked(false); + chkAlt->setEnabled(false); + chkCtrl->setChecked(false); + chkCtrl->setEnabled(false); + chkShift->setChecked(false); + chkShift->setEnabled(false); + } + changed(false); +} + +void MouseConfig::changed(bool) +{ + QString res; +// ToDo: Restore this +/* + int n = cmbButton->currentIndex(); + if (n){ + if (chkAlt->isChecked()) + n |= Qt::AltButton; + if (chkCtrl->isChecked()) + n |= Qt::ControlButton; + if (chkShift->isChecked()) + n |= Qt::ShiftButton; + res = ShortcutsPlugin::buttonToString(n); + } +*/ + QTreeWidgetItem *item = lstCmd->currentItem(); + if (item == NULL) + return; + item->setText(1, res); + adjustColumns(); +} + +// vim: set expandtab: diff --git a/plugins/shortcuts/mousecfg.h b/plugins/shortcuts/mousecfg.h new file mode 100644 index 0000000..493a863 --- /dev/null +++ b/plugins/shortcuts/mousecfg.h @@ -0,0 +1,45 @@ +/*************************************************************************** + mousecfg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _MOUSECFG_H +#define _MOUSECFG_H + +#include "ui_mousecfgbase.h" + +class ShortcutsPlugin; + +class MouseConfig : public QWidget, public Ui::MouseCfg +{ + Q_OBJECT +public: + MouseConfig(QWidget *parent, ShortcutsPlugin *plugin); + ~MouseConfig(); +public slots: + void apply(); +protected slots: + void selectionChanged(); + void buttonChanged(int); + void changed(bool); +protected: + ShortcutsPlugin *m_plugin; + void resizeEvent(QResizeEvent *e); + void adjustColumns(); + void loadMenu(unsigned long id); +}; + +#endif + diff --git a/plugins/shortcuts/mousecfgbase.ui b/plugins/shortcuts/mousecfgbase.ui new file mode 100644 index 0000000..60e5d86 --- /dev/null +++ b/plugins/shortcuts/mousecfgbase.ui @@ -0,0 +1,95 @@ + + + MouseCfg + + + + 0 + 0 + 354 + 265 + + + + Form1 + + + + 6 + + + 11 + + + + + 2 + + + + Command + + + + + Button + + + + + + + + + + + false + + + + + + + 6 + + + 0 + + + + + + 0 + 0 + + + + + + + + Alt + + + + + + + Ctrl + + + + + + + Shift + + + + + + + + + + diff --git a/plugins/shortcuts/shortcutcfg.cpp b/plugins/shortcuts/shortcutcfg.cpp new file mode 100644 index 0000000..d605ddf --- /dev/null +++ b/plugins/shortcuts/shortcutcfg.cpp @@ -0,0 +1,259 @@ +/*************************************************************************** + shortcutcfg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "shortcutcfg.h" +#include "shortcuts.h" +#include "simgui/qkeybutton.h" + +#include "mousecfg.h" +#include "core.h" +#include "core_consts.h" +#include "cmddef.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace SIM; + +ShortcutsConfig::ShortcutsConfig(QWidget *parent, ShortcutsPlugin *plugin) : QWidget(parent) +{ + setupUi(this); + m_plugin = plugin; + //lstKeys->setSorting(0); + loadMenu(MenuMain, true); + loadMenu(MenuGroup, false); + loadMenu(MenuContact, false); + loadMenu(MenuStatus, true); + adjustColumns(); + selectionChanged(); + connect(lstKeys, SIGNAL(itemSelectionChanged()), this, SLOT(selectionChanged())); + connect(edtKey, SIGNAL(changed()), this, SLOT(keyChanged())); + connect(btnClear, SIGNAL(clicked()), this, SLOT(keyClear())); + connect(chkGlobal, SIGNAL(toggled(bool)), this, SLOT(globalChanged(bool))); + for (QObject *p = parent; p != NULL; p = p->parent()){ + if (!p->inherits("QTabWidget")) + continue; + QTabWidget *tab = static_cast(p); + mouse_cfg = new MouseConfig(tab, plugin); + tab->addTab(mouse_cfg, i18n("Mouse")); + break; + } +} + +ShortcutsConfig::~ShortcutsConfig() +{ +} + +void ShortcutsConfig::loadMenu(unsigned long id, bool bCanGlobal) +{ + EventMenuGetDef eMenu(id); + eMenu.process(); + CommandsDef *def = eMenu.defs(); + if (def) + { + CommandsList list(*def, true); + CommandDef *s; + while ((s = ++list) != NULL){ + if ((s->id == 0) || s->popup_id || (s->flags & COMMAND_TITLE)) + continue; + QString title = i18n(s->text); + if (title == "_") + continue; + title = title.remove('&'); + QString accel; + int key = 0; + const QString cfg_accel = m_plugin->value("Key").toMap().value(QString::number(s->id)).toString(); + if (!cfg_accel.isEmpty()) + key = QKeySequence::fromString(cfg_accel); + if ((key == 0) && !s->accel.isEmpty()) + key = QKeySequence::fromString(i18n(s->accel)); + if (key) + accel = QKeySequence(key).toString(); + QString global; + bool bGlobal = m_plugin->getOldGlobal(s); + const QString cfg_global = m_plugin->value("Global").toMap().value(QString::number(s->id)).toString(); + if (!cfg_global.isEmpty()) + bGlobal = !bGlobal; + if (bGlobal) + global = i18n("Global"); + QTreeWidgetItem *item = NULL; + for(int i = 0; i < lstKeys->topLevelItemCount(); i++) + { + item = lstKeys->topLevelItem(i); + if (item->text(3).toUInt() == s->id) + break; + } + if (item == NULL) + { + QTreeWidgetItem* it = new QTreeWidgetItem(lstKeys, + QStringList(title)); + it->setText(1, accel); + it->setText(2, global); + it->setText(3, QString::number(s->id)); + it->setText(4, bCanGlobal ? "1" : ""); + } + } + } +} + +void ShortcutsConfig::apply() +{ + mouse_cfg->apply(); + saveMenu(MenuMain); + saveMenu(MenuGroup); + saveMenu(MenuContact); + saveMenu(MenuStatus); + m_plugin->releaseKeys(); + m_plugin->applyKeys(); +} + +void ShortcutsConfig::saveMenu(unsigned long id) +{ + EventMenuGetDef eMenu(id); + eMenu.process(); + CommandsDef *def = eMenu.defs(); + if (def){ + CommandsList list(*def, true); + CommandDef *s; + while ((s = ++list) != NULL){ + if ((s->id == 0) || s->popup_id) + continue; + QTreeWidgetItem *item; + for(int i = 0; i < lstKeys->topLevelItemCount(); i++) + { + item = lstKeys->topLevelItem(i); + if (item->text(3).toUInt() != s->id) continue; + int key = QKeySequence::fromString(item->text(1)); + const QString cfg_key = m_plugin->getOldKey(s); + if (key == QKeySequence::fromString(cfg_key)){ + QVariantMap map; + map = m_plugin->value("Key").toMap(); + map.remove(QString::number(s->id)); + m_plugin->setValue("Key", map); + }else{ + QString t = item->text(1); + if (t.isEmpty()) + t = "-"; + QVariantMap map; + map = m_plugin->value("Key").toMap(); + map.insert(QString::number(s->id), t); + m_plugin->setValue("Key", map); + } + bool bGlobal = !item->text(2).isEmpty(); + bool bCfgGlobal = m_plugin->getOldGlobal(s); + if (item->text(1).isEmpty()){ + bGlobal = false; + bCfgGlobal = false; + } + if (bGlobal == bCfgGlobal){ + QVariantMap map; + map = m_plugin->value("Global").toMap(); + map.remove(QString::number(s->id)); + m_plugin->setValue("Global", map); + }else{ + QVariantMap map; + map = m_plugin->value("Global").toMap(); + map.insert(QString::number(s->id), bGlobal ? "1" : "-1"); + m_plugin->setValue("Global", map); + } + } + } + } +} + +void ShortcutsConfig::resizeEvent(QResizeEvent *e) +{ + QWidget::resizeEvent(e); + adjustColumns(); +} + +void ShortcutsConfig::adjustColumns() +{ + QScrollBar *bar = lstKeys->verticalScrollBar(); + int wScroll = 0; + if (bar && bar->isVisible()) + wScroll = bar->width(); + lstKeys->setColumnWidth(0, lstKeys->width() - + lstKeys->columnWidth(2) - lstKeys->columnWidth(1) - 4 - wScroll); +} + +void ShortcutsConfig::selectionChanged() +{ + QTreeWidgetItem *item = lstKeys->currentItem(); + if (item == NULL){ + lblKey->setText(QString::null); + edtKey->setEnabled(false); + btnClear->setEnabled(false); + chkGlobal->setEnabled(false); + return; + } + lblKey->setText(item->text(0)); + edtKey->setEnabled(true); + btnClear->setEnabled(true); + edtKey->setText(item->text(1)); + if (!item->text(1).isEmpty() && !item->text(4).isEmpty()){ + chkGlobal->setEnabled(true); + chkGlobal->setChecked(!item->text(2).isEmpty()); + }else{ + chkGlobal->setEnabled(false); + chkGlobal->setChecked(false); + } +} + +void ShortcutsConfig::keyClear() +{ + QTreeWidgetItem *item = lstKeys->currentItem(); + if (item == NULL) + return; + item->setText(1, QString::null); + edtKey->setText(QString::null); + edtKey->clearFocus(); +} + +void ShortcutsConfig::keyChanged() +{ + QTreeWidgetItem *item = lstKeys->currentItem(); + if (item == NULL) + return; + QString key = edtKey->text(); + if (key.isEmpty() || item->text(4).isEmpty()){ + chkGlobal->setChecked(false); + chkGlobal->setEnabled(false); + }else{ + chkGlobal->setEnabled(true); + } + item->setText(1, key); + edtKey->clearFocus(); +} + +void ShortcutsConfig::globalChanged(bool) +{ + QTreeWidgetItem *item = lstKeys->currentItem(); + if ((item == NULL) || item->text(4).isEmpty()) + return; + item->setText(2, chkGlobal->isChecked() ? i18n("Global") : QString::null); +} + +// vim: set expandtab: + diff --git a/plugins/shortcuts/shortcutcfg.h b/plugins/shortcuts/shortcutcfg.h new file mode 100644 index 0000000..2abd87e --- /dev/null +++ b/plugins/shortcuts/shortcutcfg.h @@ -0,0 +1,49 @@ +/*************************************************************************** + shortcutcfg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _SHORTCUTCFG_H +#define _SHORTCUTCFG_H + +#include "ui_shortcutcfgbase.h" + +class MouseConfig; +class ShortcutsPlugin; + +class ShortcutsConfig : public QWidget, public Ui::ShortcutCfg +{ + Q_OBJECT +public: + ShortcutsConfig(QWidget *parent, ShortcutsPlugin *plugin); + ~ShortcutsConfig(); +public slots: + void apply(); +protected slots: + void selectionChanged(); + void keyChanged(); + void keyClear(); + void globalChanged(bool); +protected: + virtual void resizeEvent(QResizeEvent*); + void adjustColumns(); + void loadMenu(unsigned long id, bool bCanGlobal); + void saveMenu(unsigned long id); + ShortcutsPlugin *m_plugin; + MouseConfig *mouse_cfg; +}; + +#endif + diff --git a/plugins/shortcuts/shortcutcfgbase.ui b/plugins/shortcuts/shortcutcfgbase.ui new file mode 100644 index 0000000..db47a77 --- /dev/null +++ b/plugins/shortcuts/shortcutcfgbase.ui @@ -0,0 +1,109 @@ + + + ShortcutCfg + + + + 0 + 0 + 309 + 180 + + + + Form1 + + + + 6 + + + 11 + + + + + 3 + + + + Command + + + + + Key + + + + + Global + + + + + + + + + + + false + + + + + + + 6 + + + 0 + + + + + + + + &Clear + + + + + + + Global + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + + + QKeyButton + QWidget +
simgui/qkeybutton.h
+
+
+ + +
diff --git a/plugins/shortcuts/shortcuts.cpp b/plugins/shortcuts/shortcuts.cpp new file mode 100644 index 0000000..7d7400e --- /dev/null +++ b/plugins/shortcuts/shortcuts.cpp @@ -0,0 +1,870 @@ +/*************************************************************************** + shortcuts.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "simapi.h" + +#include "log.h" +#include "cmddef.h" +#include "core.h" + +#include "profile.h" +#include "profilemanager.h" + +#include "shortcuts.h" +#include "shortcutcfg.h" +#include "mainwin.h" + +#include +#include +#include +#include +#include +#include + +#ifdef WIN32 + #include +#else + #if !defined(Q_OS_MAC) + #include + #ifdef USE_KDE + #include + #else + #define XK_MISCELLANY 1 + #include + #include + #include + #include + #endif + #endif +#endif + +using namespace std; +using namespace SIM; + +Plugin *createShortcutsPlugin(unsigned base, bool, Buffer *config) +{ + return new ShortcutsPlugin(base, config); +} + +static PluginInfo info = + { + I18N_NOOP("Shortcuts"), + I18N_NOOP("Plugin provides keyboards shortcuts and global mouse functions"), + VERSION, + createShortcutsPlugin, + PLUGIN_DEFAULT + }; + +EXPORT_PROC PluginInfo* GetPluginInfo() +{ + return &info; +} + +//static DataDef shortcutsData[] = +// { +// { "Key", DATA_STRLIST, 1, 0 }, +// { "Global", DATA_STRLIST, 1, 0 }, +// { "Mouse", DATA_STRLIST, 1, 0 }, +// { NULL, DATA_UNKNOWN, 0, 0 } +// }; + +void GlobalKey::execute() +{ + EventCommandExec(&m_cmd).process();; +} + +list *globalKeys = NULL; + +#ifdef WIN32 + +struct vkCode +{ + int vk; + Qt::Key key; +}; + +static vkCode vkCodes[] = + { + { VK_BACK, Qt::Key_Backspace }, + { VK_TAB, Qt::Key_Tab }, + { VK_RETURN, Qt::Key_Return }, + { VK_SHIFT, Qt::Key_Shift }, + { VK_CONTROL, Qt::Key_Control }, + { VK_MENU, Qt::Key_Menu }, + { VK_PAUSE, Qt::Key_Pause }, + { VK_ESCAPE, Qt::Key_Escape }, + { VK_SPACE, Qt::Key_Space }, + { VK_PRIOR, Qt::Key_PageUp }, + { VK_NEXT, Qt::Key_PageDown }, + { VK_END, Qt::Key_End }, + { VK_HOME, Qt::Key_Home }, + { VK_LEFT, Qt::Key_Left }, + { VK_UP, Qt::Key_Up }, + { VK_RIGHT, Qt::Key_Right }, + { VK_DOWN, Qt::Key_Down }, + { VK_PRINT, Qt::Key_Print }, + { VK_INSERT, Qt::Key_Insert }, + { VK_DELETE, Qt::Key_Delete }, + { VK_HELP, Qt::Key_Help }, + { '0', Qt::Key_0 }, + { '1', Qt::Key_1 }, + { '2', Qt::Key_2 }, + { '3', Qt::Key_3 }, + { '4', Qt::Key_4 }, + { '5', Qt::Key_5 }, + { '6', Qt::Key_6 }, + { '7', Qt::Key_7 }, + { '8', Qt::Key_8 }, + { '9', Qt::Key_9 }, + { 'A', Qt::Key_A }, + { 'B', Qt::Key_B }, + { 'C', Qt::Key_C }, + { 'D', Qt::Key_D }, + { 'E', Qt::Key_E }, + { 'F', Qt::Key_F }, + { 'G', Qt::Key_G }, + { 'H', Qt::Key_H }, + { 'I', Qt::Key_I }, + { 'J', Qt::Key_J }, + { 'K', Qt::Key_K }, + { 'L', Qt::Key_L }, + { 'M', Qt::Key_M }, + { 'N', Qt::Key_N }, + { 'O', Qt::Key_O }, + { 'P', Qt::Key_P }, + { 'Q', Qt::Key_Q }, + { 'R', Qt::Key_R }, + { 'S', Qt::Key_S }, + { 'T', Qt::Key_T }, + { 'U', Qt::Key_U }, + { 'V', Qt::Key_V }, + { 'W', Qt::Key_W }, + { 'X', Qt::Key_X }, + { 'Y', Qt::Key_Y }, + { 'Z', Qt::Key_Z }, + { VK_ADD, Qt::Key_Plus }, + { VK_SUBTRACT, Qt::Key_Minus }, + { VK_DECIMAL, Qt::Key_Period }, + { VK_F1, Qt::Key_F1 }, + { VK_F2, Qt::Key_F2 }, + { VK_F3, Qt::Key_F3 }, + { VK_F4, Qt::Key_F4 }, + { VK_F5, Qt::Key_F5 }, + { VK_F6, Qt::Key_F6 }, + { VK_F7, Qt::Key_F7 }, + { VK_F8, Qt::Key_F8 }, + { VK_F9, Qt::Key_F9 }, + { VK_F10, Qt::Key_F10 }, + { VK_F11, Qt::Key_F11 }, + { VK_F12, Qt::Key_F12 }, + { VK_F13, Qt::Key_F13 }, + { VK_F14, Qt::Key_F14 }, + { VK_F15, Qt::Key_F15 }, + { VK_F16, Qt::Key_F16 }, + { VK_F17, Qt::Key_F17 }, + { VK_F18, Qt::Key_F18 }, + { VK_F19, Qt::Key_F19 }, + { VK_F20, Qt::Key_F20 }, + { VK_F21, Qt::Key_F21 }, + { VK_F22, Qt::Key_F22 }, + { VK_F23, Qt::Key_F23 }, + { VK_F24, Qt::Key_F24 }, + { VK_NUMLOCK, Qt::Key_NumLock }, + { VK_SCROLL, Qt::Key_ScrollLock }, + { 0, (Qt::Key)0 } + }; + +static void getKey(const QString &key_str, int &mod, int &key) +{ + mod = 0; + key = 0; + int kkey = QKeySequence::fromString(key_str); + if (kkey & Qt::ALT) mod |= MOD_ALT; + if (kkey & Qt::CTRL) mod |= MOD_CONTROL; + if (kkey & Qt::SHIFT) mod |= MOD_SHIFT; + kkey &= ~(Qt::MODIFIER_MASK | Qt::UNICODE_ACCEL); + for (const vkCode *k = vkCodes; k->vk; k++){ + if (k->key == kkey){ + key = k->vk; + break; + } + } +} + +GlobalKey::GlobalKey(CommandDef *cmd) +{ + m_cmd = *cmd; + int mod, key; + getKey(cmd->accel, mod, key); + QWidget *main = ShortcutsPlugin::getMainWindow(); + if (key && main){ + QString atom = "sim_" + QString::number(cmd->id); + m_key = GlobalAddAtom((LPCWSTR)atom.utf16()); + RegisterHotKey(main->winId(), m_key, mod, key); + } +} + +GlobalKey::~GlobalKey() +{ + QWidget *main = ShortcutsPlugin::getMainWindow(); + if (m_key && main){ + UnregisterHotKey(main->winId(), m_key); + DeleteAtom((unsigned short)m_key); + } +} + +static WNDPROC oldProc = NULL; + +LRESULT CALLBACK keysWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + if (msg == WM_HOTKEY){ + if (globalKeys){ + for (list::iterator it = globalKeys->begin(); it != globalKeys->end(); ++it){ + if ((UINT)((*it)->key()) == wParam){ + (*it)->execute(); + break; + } + } + } + } + if (oldProc) + return oldProc(hWnd, msg, wParam, lParam); + return 0; +} + +#else // WIN32 +#ifdef USE_KDE + +GlobalKey::GlobalKey(CommandDef *cmd) +{ + m_cmd = *cmd; + QKeySequence keys(cmd->accel); + if (keys != QKeySequence(0)){ + QString shortName = "sim_" + QString::number(cmd->id); + accel = new KGlobalAccel(this); + accel->insert(shortName, + i18n(cmd->text), i18n(cmd->text), + keys, keys, this, SLOT(execute())); + accel->updateConnections(); + } +} + +GlobalKey::~GlobalKey() +{ + if (accel) + delete accel; +} + +#else // USE_KDE +#if !defined(Q_OS_MAC) + +struct TransKey +{ + unsigned qt_key; + unsigned x_key; +}; + +static const TransKey g_rgQtToSymX[] = + { + { Qt::Key_Escape, XK_Escape }, + { Qt::Key_Tab, XK_Tab }, + { Qt::Key_Backspace, XK_BackSpace }, + { Qt::Key_Return, XK_Return }, + { Qt::Key_Enter, XK_KP_Enter }, + { Qt::Key_Insert, XK_Insert }, + { Qt::Key_Delete, XK_Delete }, + { Qt::Key_Pause, XK_Pause }, + { Qt::Key_Print, XK_Print }, + { Qt::Key_SysReq, XK_Sys_Req }, + { Qt::Key_Home, XK_Home }, + { Qt::Key_End, XK_End }, + { Qt::Key_Left, XK_Left }, + { Qt::Key_Up, XK_Up }, + { Qt::Key_Right, XK_Right }, + { Qt::Key_Down, XK_Down }, + { Qt::Key_PageUp, XK_Prior }, + { Qt::Key_PageDown, XK_Next }, + { Qt::Key_CapsLock, XK_Caps_Lock }, + { Qt::Key_NumLock, XK_Num_Lock }, + { Qt::Key_ScrollLock, XK_Scroll_Lock }, + { Qt::Key_F1, XK_F1 }, + { Qt::Key_F2, XK_F2 }, + { Qt::Key_F3, XK_F3 }, + { Qt::Key_F4, XK_F4 }, + { Qt::Key_F5, XK_F5 }, + { Qt::Key_F6, XK_F6 }, + { Qt::Key_F7, XK_F7 }, + { Qt::Key_F8, XK_F8 }, + { Qt::Key_F9, XK_F9 }, + { Qt::Key_F10, XK_F10 }, + { Qt::Key_F11, XK_F11 }, + { Qt::Key_F12, XK_F12 }, + { Qt::Key_F13, XK_F13 }, + { Qt::Key_F14, XK_F14 }, + { Qt::Key_F15, XK_F15 }, + { Qt::Key_F16, XK_F16 }, + { Qt::Key_F17, XK_F17 }, + { Qt::Key_F18, XK_F18 }, + { Qt::Key_F19, XK_F19 }, + { Qt::Key_F20, XK_F20 }, + { Qt::Key_F21, XK_F21 }, + { Qt::Key_F22, XK_F22 }, + { Qt::Key_F23, XK_F23 }, + { Qt::Key_F24, XK_F24 }, + { Qt::Key_F25, XK_F25 }, + { Qt::Key_F26, XK_F26 }, + { Qt::Key_F27, XK_F27 }, + { Qt::Key_F28, XK_F28 }, + { Qt::Key_F29, XK_F29 }, + { Qt::Key_F30, XK_F30 }, + { Qt::Key_F31, XK_F31 }, + { Qt::Key_F32, XK_F32 }, + { Qt::Key_F33, XK_F33 }, + { Qt::Key_F34, XK_F34 }, + { Qt::Key_F35, XK_F35 }, + { Qt::Key_Super_L, XK_Super_L }, + { Qt::Key_Super_R, XK_Super_R }, + { Qt::Key_Menu, XK_Menu }, + { Qt::Key_Hyper_L, XK_Hyper_L }, + { Qt::Key_Hyper_R, XK_Hyper_R }, + { Qt::Key_Help, XK_Help }, + { '/', XK_KP_Divide }, + { '*', XK_KP_Multiply }, + { '-', XK_KP_Subtract }, + { '+', XK_KP_Add }, + { Qt::Key_Return, XK_KP_Enter }, + { 0, 0 } + }; + +extern "C" { + static int XGrabErrorHandler( Display *, XErrorEvent *e ) { + if ( e->error_code != BadAccess ) { + log(L_DEBUG, "grabKey: got X error %u instead of BadAccess", e->type); + } + return 0; + } +} + +// from KGlobalAccel +static uint g_keyModMaskXOnOrOff = 0; +static void initializeMods() +{ + uint g_modXNumLock, g_modXScrollLock, g_modXModeSwitch; + g_modXNumLock = g_modXScrollLock = g_modXModeSwitch = 0; + int min_keycode, max_keycode; + int keysyms_per_keycode = 0; + + XModifierKeymap* xmk = XGetModifierMapping(QX11Info::display() ); + XDisplayKeycodes(QX11Info::display(), &min_keycode, &max_keycode ); + XFree( XGetKeyboardMapping(QX11Info::display(), min_keycode, 1, &keysyms_per_keycode )); + for( int i = Mod2MapIndex; i < 8; i++ ) { + uint mask = (1 << i); + uint keySymX = NoSymbol; + for( int j = 0; j < xmk->max_keypermod && keySymX == NoSymbol; ++j ) + for( int k = 0; k < keysyms_per_keycode && keySymX == NoSymbol; ++k ) + keySymX = XKeycodeToKeysym(QX11Info::display(), xmk->modifiermap[xmk->max_keypermod * i + j], k ); + switch(keySymX) + { + case XK_Num_Lock: g_modXNumLock = mask; break; // Normally Mod2Mask + case XK_Scroll_Lock: g_modXScrollLock = mask; break; // Normally Mod5Mask + case XK_Mode_switch: g_modXModeSwitch = mask; break; + } + } + XFreeModifiermap(xmk); + g_keyModMaskXOnOrOff = LockMask | g_modXNumLock | g_modXScrollLock | g_modXModeSwitch; +} + +GlobalKey::GlobalKey(CommandDef *cmd) +{ + m_cmd = *cmd; + m_key = QKeySequence::fromString(cmd->accel); + m_state = 0; + if (m_key & Qt::SHIFT){ + m_key &= ~Qt::SHIFT; + m_state |= 1; + } + if (m_key & Qt::CTRL){ + m_key &= ~Qt::CTRL; + m_state |= 4; + } + if (m_key & Qt::ALT){ + m_key &= ~Qt::ALT; + m_state |= 8; + } + m_key &= ~Qt::UNICODE_ACCEL; + for (const TransKey *t = g_rgQtToSymX; t->x_key; t++){ + if (t->qt_key == m_key){ + m_key = t->x_key; + break; + } + } + + if(!g_keyModMaskXOnOrOff) + initializeMods(); + + m_key = XKeysymToKeycode(QX11Info::display(), m_key); + XSync(QX11Info::display(), 0 ); + XErrorHandler savedErrorHandler = XSetErrorHandler(XGrabErrorHandler); + + uint keyModMaskX = ~g_keyModMaskXOnOrOff; + /* + for( uint irrelevantBitsMask = 0; irrelevantBitsMask <= 0xff; irrelevantBitsMask++ ) + if( (irrelevantBitsMask & keyModMaskX) == 0 ) + XGrabKey(QX11Info::display(), m_key, m_state | irrelevantBitsMask, qt_xrootwin(), True, GrabModeAsync, GrabModeSync); + */ + + XSync(QX11Info::display(), 0 ); + XSetErrorHandler( savedErrorHandler ); +} + +GlobalKey::~GlobalKey() +{ + uint keyModMaskX = ~g_keyModMaskXOnOrOff; + + /* + for( uint irrelevantBitsMask = 0; irrelevantBitsMask <= 0xff; irrelevantBitsMask++ ) + if( (irrelevantBitsMask & keyModMaskX) == 0 ) + XUngrabKey( qt_xdisplay(), m_key, m_state | irrelevantBitsMask, qt_xrootwin()); + */ +} + +typedef int (*QX11EventFilter) (::XEvent*); +//QX11EventFilter qt_set_x11_event_filter (QX11EventFilter filter); +static QX11EventFilter oldFilter; + +static int X11EventFilter(::XEvent *e) +{ + if ((e->type == KeyPress) && globalKeys){ + if ( !QWidget::keyboardGrabber() && !QApplication::activePopupWidget() ) { + XUngrabKeyboard(QX11Info::display(), e->xkey.time ); + XFlush(QX11Info::display()); + } + unsigned state = e->xkey.state & (ShiftMask | ControlMask | Mod1Mask | Mod4Mask | 0x2000); + + for (list::iterator it = globalKeys->begin(); it != globalKeys->end(); ++it){ + if (((*it)->key() == e->xkey.keycode) && + ((*it)->state() == state)){ + (*it)->execute(); + return true; + } + } + } + if (oldFilter) + return oldFilter(e); + return false; +} + +#else // !Q_OS_MAC + +GlobalKey::GlobalKey(SIM::CommandDef *cmd) +{ +} + +GlobalKey::~GlobalKey() +{ +} + +#endif // !Q_OS_MAC +#endif // USE_KDE +#endif // WIN32 + +ShortcutsPlugin::ShortcutsPlugin(unsigned base, Buffer *config) + : QObject(), Plugin(base) +{ + m_propertyHub = SIM::PropertyHub::create("shortcuts"); +#ifdef WIN32 + m_bInit = false; + init(); +#else + applyKeys(); +#ifndef USE_KDE +// oldFilter = qt_set_x11_event_filter(X11EventFilter); +#endif +#endif +} + +ShortcutsPlugin::~ShortcutsPlugin() +{ +#ifdef WIN32 + QWidget *main = getMainWindow(); + if (main && oldProc){ + if (IsWindowUnicode(main->winId())){ + SetWindowLongW(main->winId(), GWL_WNDPROC, (LONG)oldProc); + }else{ + SetWindowLongA(main->winId(), GWL_WNDPROC, (LONG)oldProc); + } + } +#else +#ifndef USE_KDE + //qt_set_x11_event_filter(oldFilter); +#endif +#endif + releaseKeys(); +} + +QByteArray ShortcutsPlugin::getConfig() +{ + return QByteArray();//Fixmee +} + +QWidget *ShortcutsPlugin::createConfigWindow(QWidget *parent) +{ + return new ShortcutsConfig(parent, this); +} + +#ifdef WIN32 + +void ShortcutsPlugin::init() +{ + if (m_bInit) + return; + QWidget *main = getMainWindow(); + if (main){ + if (IsWindowUnicode(main->winId())){ + oldProc = (WNDPROC)SetWindowLongW(main->winId(), GWL_WNDPROC, (LONG)keysWndProc); + }else{ + oldProc = (WNDPROC)SetWindowLongA(main->winId(), GWL_WNDPROC, (LONG)keysWndProc); + } + m_bInit = true; + applyKeys(); + } +} + +#endif + +bool ShortcutsPlugin::processEvent(Event *e) +{ +#ifdef WIN32 + if (e->type() == eEventInit){ + init(); + return false; + } else +#endif + if (e->type() == eEventCommandCreate){ + EventCommandCreate *ecc = static_cast(e); + CommandDef *cmd = ecc->cmd(); + if ((cmd->menu_id == MenuMain) || + (cmd->menu_id == MenuContact) || + (cmd->menu_id == MenuStatus) || + (cmd->menu_id == MenuGroup)){ + applyKey(cmd); + } + } else + if (e->type() == eEventCommandRemove){ + EventCommandRemove *ecr = static_cast(e); + unsigned long id = ecr->id(); + MAP_STR::iterator it_key = oldKeys.find(id); + if (it_key != oldKeys.end()) + oldKeys.erase(it_key); + MAP_BOOL::iterator it_global = oldGlobals.find(id); + if (it_global != oldGlobals.end()) + oldGlobals.erase(it_global); + if (globalKeys){ + list::iterator it; + for (it = globalKeys->begin(); it != globalKeys->end();){ + if ((*it)->id() != id){ + ++it; + continue; + } + delete *it; + globalKeys->erase(it); + it = globalKeys->begin(); + } + } + for (MAP_CMDS::iterator it = mouseCmds.begin(); it != mouseCmds.end();){ + if (it->second.id != id){ + ++it; + continue; + } + mouseCmds.erase(it); + it = mouseCmds.begin(); + } + if (mouseCmds.size() == 0) + qApp->removeEventFilter(this); + } + if(e->type() == eEventPluginLoadConfig) + { + PropertyHubPtr hub = ProfileManager::instance()->getPropertyHub("shortcut"); + if(!hub.isNull()) + setPropertyHub(hub); + } + return false; +} + +QString ShortcutsPlugin::getOldKey(CommandDef *cmd) +{ + MAP_STR::iterator it = oldKeys.find(cmd->id); + if (it != oldKeys.end()) + return it->second; + return cmd->accel; +} + +bool ShortcutsPlugin::getOldGlobal(CommandDef *cmd) +{ + MAP_BOOL::iterator it = oldGlobals.find(cmd->id); + if (it != oldGlobals.end()) + return it->second; + return ((cmd->flags & COMMAND_GLOBAL_ACCEL) != 0); +} + +void ShortcutsPlugin::applyKeys() +{ + applyKeys(MenuMain); + applyKeys(MenuGroup); + applyKeys(MenuContact); + applyKeys(MenuStatus); +} + +void ShortcutsPlugin::releaseKeys() +{ + releaseKeys(MenuMain); + releaseKeys(MenuGroup); + releaseKeys(MenuContact); + releaseKeys(MenuStatus); + oldKeys.clear(); + oldGlobals.clear(); + if (globalKeys){ + list::iterator it; + for (it = globalKeys->begin(); it != globalKeys->end(); ++it){ + delete *it; + } + delete globalKeys; + globalKeys = NULL; + } + mouseCmds.clear(); + qApp->removeEventFilter(this); +} + +void ShortcutsPlugin::applyKeys(unsigned long id) +{ + EventMenuGetDef eMenu(id); + eMenu.process(); + CommandsDef *def = eMenu.defs(); + if (def){ + CommandsList list(*def, true); + CommandDef *s; + while ((s = ++list) != NULL){ + if (s->id == 0) continue; + applyKey(s); + } + } +} + +static const char *states[] = + { + "Left", + "Right", + "Mid", + "LeftDbl", + "RightDbl", + "MidDbl", + NULL + }; + +unsigned ShortcutsPlugin::stringToButton(const QString &cfg) +{ + Qt::KeyboardModifiers res = Qt::NoModifier; + QStringList config = cfg.split('+'); + Q_FOREACH(const QString &t, config) { + if (t == QLatin1String("Alt")){ + res |= Qt::AltModifier; + continue; + } + if (t == QLatin1String("Ctrl")){ + res |= Qt::ControlModifier; + continue; + } + if (t == QLatin1String("Shift")){ + res |= Qt::ShiftModifier; + continue; + } + unsigned i = 1; + for (const char **p = states; *p; p++, i++) { + if (t == *p){ + res |= (Qt::KeyboardModifier)i; + return res; + } + } + return 0; + } + return 0; +} + +QString ShortcutsPlugin::buttonToString(unsigned n) +{ + QString res; +// ToDo: Restore this +/* + if (n & Qt::AltButton) + res = "Alt+"; + if (n & Qt::ControlButton) + res = "Ctrl+"; + if (n & Qt::ShiftButton) + res = "Shift+"; +*/ + n = n & 7; + if (n == 0) + return QString::null; + n--; + const char **p; + for (p = states; *p && n; p++, n--) {} + if (*p == NULL) + return QString::null; + res += *p; + return res; +} + +void ShortcutsPlugin::applyKey(CommandDef *s) +{ + if (s->popup_id){ + QString cfg = value("Mouse").toMap().value(QString::number(s->id)).toString(); + if (!cfg.isEmpty()){ + unsigned btn = stringToButton(cfg); + if (mouseCmds.size() == 0) + qApp->installEventFilter(this); + mouseCmds.insert(MAP_CMDS::value_type(btn, *s)); + } + return; + } + QString cfg = value("Key").toMap().value(QString::number(s->id)).toString(); + if (!cfg.isEmpty()){ + oldKeys.insert(MAP_STR::value_type(s->id, s->accel)); + if (cfg != "-"){ + s->accel = cfg; + }else{ + s->accel = QString::null; + } + } + cfg = value("Global").toMap().value(QString::number(s->id)).toString(); + if (!cfg.isEmpty()){ + oldGlobals.insert(MAP_BOOL::value_type(s->id, (s->flags & COMMAND_GLOBAL_ACCEL) != 0)); + if (cfg.startsWith("-")){ + s->flags &= ~COMMAND_GLOBAL_ACCEL; + }else{ + s->flags |= COMMAND_GLOBAL_ACCEL; + } + } + if (!s->accel.isEmpty() && (s->flags & COMMAND_GLOBAL_ACCEL)) + { + if (globalKeys == NULL) + globalKeys = new list; + globalKeys->push_back(new GlobalKey(s)); + } +} + +void ShortcutsPlugin::releaseKeys(unsigned long id) +{ + EventMenuGetDef eMenu(id); + eMenu.process(); + CommandsDef *def = eMenu.defs(); + if (def){ + CommandsList list(*def, true); + CommandDef *s; + while ((s = ++list) != NULL){ + if ((s->id == 0) || s->popup_id) + continue; + MAP_STR::iterator it_key = oldKeys.find(s->id); + if (it_key != oldKeys.end()) + s->accel = (*it_key).second; + MAP_BOOL::iterator it_global = oldGlobals.find(s->id); + if (it_global != oldGlobals.end()){ + s->flags &= ~COMMAND_GLOBAL_ACCEL; + if ((*it_global).second) + s->flags |= COMMAND_GLOBAL_ACCEL; + } + } + } +} + +bool ShortcutsPlugin::eventFilter(QObject *o, QEvent *e) +{ + unsigned button = 0; + QMouseEvent *me = NULL; + if (e->type() == QEvent::MouseButtonPress){ + me = static_cast(e); + switch (me->button()){ + case Qt::LeftButton: + button = 1; + break; + case Qt::RightButton: + button = 2; + break; + case Qt::MidButton: + button = 3; + break; + default: + break; + } + } + if (e->type() == QEvent::MouseButtonDblClick){ + me = static_cast(e); + switch (me->button()){ + case Qt::LeftButton: + button = 4; + break; + case Qt::RightButton: + button = 5; + break; + case Qt::MidButton: + button = 6; + break; + default: + break; + } + } + if (me){ + button |= me->modifiers(); + MAP_CMDS::iterator it = mouseCmds.find(button); + if (it != mouseCmds.end()){ + CommandDef *cmd = &it->second; + EventMenuGet e(cmd); + e.process(); + QMenu *popup = e.menu(); + if (popup){ + popup->popup(me->globalPos()); + return true; + } + } + } + return QObject::eventFilter(o, e); +} + +QWidget *ShortcutsPlugin::getMainWindow() +{ + CorePlugin *core = GET_CorePlugin(); + return core->getMainWindow(); +} + +void ShortcutsPlugin::setPropertyHub(SIM::PropertyHubPtr hub) +{ + m_propertyHub = hub; +} + +SIM::PropertyHubPtr ShortcutsPlugin::propertyHub() +{ + return m_propertyHub; +} + +QVariant ShortcutsPlugin::value(const QString& key) +{ + return m_propertyHub->value(key); +} + +void ShortcutsPlugin::setValue(const QString& key, const QVariant& v) +{ + m_propertyHub->setValue(key, v); +} diff --git a/plugins/shortcuts/shortcuts.h b/plugins/shortcuts/shortcuts.h new file mode 100644 index 0000000..6c3fc4e --- /dev/null +++ b/plugins/shortcuts/shortcuts.h @@ -0,0 +1,122 @@ +/*************************************************************************** + shortcuts.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _SHORTCUTS_H +#define _SHORTCUTS_H + +#include +#include "simapi.h" + +#include +#include +#include + +#include "cfg.h" +#include "event.h" +#include "plugins.h" +#include "propertyhub.h" + +using namespace std; + +struct ShortcutsData +{ +// SIM::Data Key; +// SIM::Data Global; +// SIM::Data Mouse; +}; + +typedef map MAP_STR; +typedef map MAP_BOOL; +typedef map MAP_CMDS; + +class KGlobalAccel; + +class GlobalKey : public QObject +{ + Q_OBJECT +public: + GlobalKey(SIM::CommandDef *cmd); + ~GlobalKey(); + unsigned id() { return m_cmd.id; } +#ifdef WIN32 + int key() { return m_key; } +#else +#ifndef USE_KDE + unsigned key() { return m_key; } + unsigned state() { return m_state; } +#endif +#endif +public slots: + void execute(); +protected: + SIM::CommandDef m_cmd; +#ifdef WIN32 + int m_key; +#else +#ifdef USE_KDE + KGlobalAccel *accel; +#else + unsigned m_key; + unsigned m_state; +#endif +#endif +}; + +class ShortcutsPlugin : public QObject, public SIM::Plugin, public SIM::EventReceiver +{ + Q_OBJECT +public: + ShortcutsPlugin(unsigned, Buffer*); + virtual ~ShortcutsPlugin(); +// PROP_STRLIST(Key); +// PROP_STRLIST(Global); +// PROP_STRLIST(Mouse); + void applyKeys(); + void releaseKeys(); + QString getOldKey(SIM::CommandDef *cmd); + bool getOldGlobal(SIM::CommandDef *cmd); + static QWidget *getMainWindow(); + static unsigned stringToButton(const QString &cfg); + static QString buttonToString(unsigned button); + + void setPropertyHub(SIM::PropertyHubPtr hub); + SIM::PropertyHubPtr propertyHub(); + QVariant value(const QString& key); + void setValue(const QString& key, const QVariant& v); +protected: + virtual bool eventFilter(QObject*, QEvent*); + virtual bool processEvent(SIM::Event *e); + virtual QByteArray getConfig(); + virtual QWidget *createConfigWindow(QWidget *parent); + void applyKeys(unsigned long); + void applyKey(SIM::CommandDef*); + void releaseKeys(unsigned long); +#ifdef WIN32 + void init(); + bool m_bInit; +#endif + ShortcutsData data; + MAP_STR oldKeys; + MAP_BOOL oldGlobals; + MAP_CMDS mouseCmds; + +private: + SIM::PropertyHubPtr m_propertyHub; +}; + +#endif + diff --git a/plugins/shortcuts/shortcuts.rc b/plugins/shortcuts/shortcuts.rc new file mode 100644 index 0000000..5dd45d0 --- /dev/null +++ b/plugins/shortcuts/shortcuts.rc @@ -0,0 +1,97 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,9,6,0 + PRODUCTVERSION 0,9,6,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Vladimir Shutoff\0" + VALUE "FileDescription", "Shortcuts plugin\0" + VALUE "FileVersion", "0, 9, 6, 0\0" + VALUE "InternalName", "shortcuts\0" + VALUE "LegalCopyright", "Copyright © 2002-2003\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "shortcuts.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "SIM\0" + VALUE "ProductVersion", "0, 9, 6, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/shortcuts/shortcuts.vcproj b/plugins/shortcuts/shortcuts.vcproj new file mode 100644 index 0000000..066924e --- /dev/null +++ b/plugins/shortcuts/shortcuts.vcproj @@ -0,0 +1,499 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/skype/call_end b/plugins/skype/call_end new file mode 100644 index 0000000..a3605ef --- /dev/null +++ b/plugins/skype/call_end @@ -0,0 +1,4 @@ +#!/bin/bash + +kill `ps -A | grep artsd` +artsd & diff --git a/plugins/skype/call_start b/plugins/skype/call_start new file mode 100644 index 0000000..9f75be6 --- /dev/null +++ b/plugins/skype/call_start @@ -0,0 +1,5 @@ +#!/bin/bash + +kill -9 `ps -A | grep artsd` && artsd -a null & +sleep 0.2 + diff --git a/plugins/skype/icons/cr16-action-call.png b/plugins/skype/icons/cr16-action-call.png new file mode 100644 index 0000000..53a25d5 Binary files /dev/null and b/plugins/skype/icons/cr16-action-call.png differ diff --git a/plugins/skype/icons/cr16-action-contact_ffc_overlay.png b/plugins/skype/icons/cr16-action-contact_ffc_overlay.png new file mode 100644 index 0000000..51f5162 Binary files /dev/null and b/plugins/skype/icons/cr16-action-contact_ffc_overlay.png differ diff --git a/plugins/skype/icons/cr16-app-skype_protocol.png b/plugins/skype/icons/cr16-app-skype_protocol.png new file mode 100644 index 0000000..33ff90e Binary files /dev/null and b/plugins/skype/icons/cr16-app-skype_protocol.png differ diff --git a/plugins/skype/icons/cr22-action-call.png b/plugins/skype/icons/cr22-action-call.png new file mode 100644 index 0000000..0fc014c Binary files /dev/null and b/plugins/skype/icons/cr22-action-call.png differ diff --git a/plugins/skype/icons/cr32-action-call.png b/plugins/skype/icons/cr32-action-call.png new file mode 100644 index 0000000..9a610b9 Binary files /dev/null and b/plugins/skype/icons/cr32-action-call.png differ diff --git a/plugins/skype/icons/hi16-action-call.png b/plugins/skype/icons/hi16-action-call.png new file mode 100644 index 0000000..53a25d5 Binary files /dev/null and b/plugins/skype/icons/hi16-action-call.png differ diff --git a/plugins/skype/icons/hi16-action-contact_ffc_overlay.png b/plugins/skype/icons/hi16-action-contact_ffc_overlay.png new file mode 100644 index 0000000..d31ee48 Binary files /dev/null and b/plugins/skype/icons/hi16-action-contact_ffc_overlay.png differ diff --git a/plugins/skype/icons/hi16-action-contact_unknown_overlay.png b/plugins/skype/icons/hi16-action-contact_unknown_overlay.png new file mode 100644 index 0000000..1ad3205 Binary files /dev/null and b/plugins/skype/icons/hi16-action-contact_unknown_overlay.png differ diff --git a/plugins/skype/icons/hi16-action-skype_connect.png b/plugins/skype/icons/hi16-action-skype_connect.png new file mode 100644 index 0000000..7a26aad Binary files /dev/null and b/plugins/skype/icons/hi16-action-skype_connect.png differ diff --git a/plugins/skype/icons/icondef.xml b/plugins/skype/icons/icondef.xml new file mode 100644 index 0000000..2a62479 --- /dev/null +++ b/plugins/skype/icons/icondef.xml @@ -0,0 +1,48 @@ + + + + SIM-Skype Icons + 0.9.6 + SIM icons. + Tobias Franz + 2006-10-31 + http://sim-im.org/ + + + cr16-action-call.png + + + cr16-action-contact_ffc_overlay.png + + + cr16-app-skype_protocol.png + + + cr22-action-call.png + + + cr32-action-call.png + + + hi16-action-call.png + + + hi16-action-contact_ffc_overlay.png + + + hi16-action-contact_unknown_overlay.png + + + hi16-action-skype_connect.png + + + + + + + + + + + + diff --git a/plugins/skype/libskype/skype.cpp b/plugins/skype/libskype/skype.cpp new file mode 100644 index 0000000..d724209 --- /dev/null +++ b/plugins/skype/libskype/skype.cpp @@ -0,0 +1,797 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Michal Vaner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ +#include "skype.h" +#include +#include + +#include +#include +#include +#include +#include +#include + +#define PROTOCOL_MAX 5 +#define PROTOCOL_MIN 5 +#define TEST_QUIT if (!d->connection.connected()) return; + +///This one indicates, weather the Skype is connected (does not mean weather it is marked as online, just if it has connection to the site) +typedef enum { + csOffline, + csConnecting, + csPausing, + csOnline, + csLoggedOut +} connectionStatus; + +///This describes what the user is marked as. If online here and not connected to skype site, he is probably offline +typedef enum { + usUnknown, + usOffline, + usOnline, + usSkypeMe, + usAway, + usNA, + usDND, + usInvisible +} userStatus; + +class SkypePrivate { + public: + ///The connection + SkypeConnection connection; + ///The queue + QValueList messageQueue; + ///How do we start skype? + int launchType; + ///What is our name? + QString appName; + ///Should the skypeconnection start skype automatically if it is not running? + bool start; + ///Is the skype connected? + connectionStatus connStatus; + ///What is the online status for the user? + userStatus onlineStatus; + ///This contains last search request to know, what we were searching for + QString searchFor; + ///Is the hitch-mode enabled? + bool hitch; + ///Is the mark read messages mode enabled? + bool mark; + ///The skype account this connection belongs to + SkypeAccount &account; + ///Should we show the message that Skype died? It if off when going offline, this removes that onnoying message when logging off and skype finishes first. + bool showDeadMessage; + ///Do we automatically scan for unread messages on login? + bool scanForUnread; + ///Constructor + SkypePrivate(SkypeAccount &_account) : account(_account) {};//initialize all that needs it + ///List of known calls, so they are not showed twice + QValueList knownCalls; + ///Are the pings enabled? + bool pings; + ///Pinging timer + QTimer *pingTimer; + ///What bus is used now? + int bus; + ///Do we start DBus as well if needed? + bool startDBus; + ///The launch timeout (after that no connection -> unsuccessfull -> error) + int launchTimeout; + ///By what command is skype started? + QString skypeCommand; + ///Do we wait before connecting? + int waitBeforeConnect; + ///List of alredy received messages (IDs) + QValueList recvMessages; +}; + +Skype::Skype(SkypeAccount &account) : QObject() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + d = new SkypePrivate(account);//create the d-pointer + + //initial values + d->connStatus = csOffline; + d->onlineStatus = usOffline; + d->searchFor = ""; + d->pings = false; + d->pingTimer = new QTimer; + + connect(&d->connection, SIGNAL(connectionClosed(int)), this, SLOT(closed(int)));//tell me if you close/lose the connection + connect(&d->connection, SIGNAL(connectionDone(int, int)), this, SLOT(connectionDone(int, int)));//Do something whe he finishes connecting + connect(&d->connection, SIGNAL(error(const QString&)), this, SLOT(error(const QString&)));//Listen for errors + connect(&d->connection, SIGNAL(received(const QString&)), this, SLOT(skypeMessage(const QString&)));//Take all incoming messages + connect(d->pingTimer, SIGNAL(timeout()), this, SLOT(ping())); +} + + +Skype::~Skype() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + if (d->connection.connected()) + d->connection << QString("SET USERSTATUS OFFLINE"); + + d->pingTimer->stop(); + d->pingTimer->deleteLater(); + + delete d;//release the memory +} + +void Skype::setOnline() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + d->showDeadMessage = true; + + if ((d->onlineStatus == usOnline) && (d->connStatus == csOnline) && (d->connection.connected())) + return;//Already online + + queueSkypeMessage("SET USERSTATUS ONLINE", true);//just send the message +} + +void Skype::setOffline() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + d->showDeadMessage = false; + + d->connection << QString("SET USERSTATUS OFFLINE");//this one special, do not connect to skype because of that + d->connection.disconnectSkype(); +} + +void Skype::setAway() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + d->showDeadMessage = true; + + queueSkypeMessage("SET USERSTATUS AWAY", true); +} + +void Skype::setNotAvailable() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + d->showDeadMessage = true; + + queueSkypeMessage("SET USERSTATUS NA", true); +} + +void Skype::setDND() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + d->showDeadMessage = true; + + queueSkypeMessage("SET USERSTATUS DND", true); +} + +void Skype::setInvisible() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + d->showDeadMessage = true; + + queueSkypeMessage("SET USERSTATUS INVISIBLE", true); +} + +void Skype::setSkypeMe() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + d->showDeadMessage = true; + + queueSkypeMessage("SET USERSTATUS SKYPEME", true); +} + +void Skype::queueSkypeMessage(const QString &message, bool deleteQueue) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + if (d->connection.connected()) {//we are connected, so just send it + d->connection << message;//just send it + } else { + emit statusConnecting();//Started connecting to skype + if (deleteQueue) + d->messageQueue.clear();//delete all old messages + d->messageQueue << message;//add the new one + d->connection.connectSkype((d->start) ? d->skypeCommand : "", d->appName, PROTOCOL_MAX, d->bus, d->startDBus, d->launchTimeout, d->waitBeforeConnect);//try to connect + } +} + +void Skype::setValues(int launchType, const QString &appName) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + d->appName = appName; + if (d->appName.isEmpty()) //The defaut one? + d->appName = "SIM-IM"; + d->launchType = launchType; + switch (launchType) { + case 0: //start the skype if it is needed + d->start = true;//just set autostart + break; + case 1: //do not start + d->start = false;//do not start + break; + } +} + +void Skype::closed(int) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + emit wentOffline();//No longer connected + d->messageQueue.clear();//no messages will wait, it was lost + d->pingTimer->stop(); +} + +void Skype::connectionDone(int error, int protocolVer) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + if (d->pings) { + d->pingTimer->start(1000); + } + + if (error == seSuccess) {//It worked + if (protocolVer < PROTOCOL_MIN) {//The protocol is too old, it is not useable + this->error(i18n("This version of Skype is too old, consider upgrading")); + connectionDone(seUnknown, 0);//So act like there was an error + return;//and it is all fo now + } + + while (d->messageQueue.size()) {//It isn't empty yet? + QValueList::iterator it = d->messageQueue.begin();//take the first one + d->connection << (*it);//send the message + d->messageQueue.remove(it);//remove this one + } + emit updateAllContacts();//let all contacts update their information + search("FRIENDS");//search for friends - to add them all + TEST_QUIT;//if it failed, do not continue + d->connection.send("GET USERSTATUS"); + TEST_QUIT; + d->connection.send("GET CONNSTATUS");// + } else { + closed(crLost);//OK, this is wrong, justclose the connection/atempt and delete the queue + } +} + +void Skype::error(const QString &message) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + disconnect(&d->connection, SIGNAL(error(const QString&)), this, SLOT(error(const QString&)));//One arror at a time is enough, stop flooding the user + + if (d->showDeadMessage)//just skip the error message if we are going offline, none ever cares. + KMessageBox::error(0L, message, i18n("Skype protocol"));//Show the message + + connect(&d->connection, SIGNAL(error(const QString&)), this, SLOT(error(const QString&)));//Continue showing more errors in future +} + +void Skype::skypeMessage(const QString &message) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + QString messageType = message.section(' ', 0, 0).stripWhiteSpace().upper();//get the first part of the message + if (messageType == "CONNSTATUS") {//the connection status + QString value = message.section(' ', 1, 1).stripWhiteSpace().upper();//get the second part of the message + if (value == "OFFLINE") + d->connStatus = csOffline; + else if (value == "CONNECTING") + d->connStatus = csConnecting; + else if (value == "PAUSING") + d->connStatus = csPausing; + else if (value == "ONLINE") + d->connStatus = csOnline; + else if (value == "LOGGEDOUT") + d->connStatus = csLoggedOut; + + resetStatus();//set new status + } else if (messageType == "USERSTATUS") {//Status of this user + QString value = message.section(' ', 1, 1).stripWhiteSpace().upper();//get the second part + if (value == "UNKNOWN") + d->onlineStatus = usUnknown; + else if (value == "OFFLINE") + d->onlineStatus = usOffline; + else if (value == "ONLINE") + d->onlineStatus = usOnline; + else if (value == "SKYPEME") + d->onlineStatus = usSkypeMe; + else if (value == "AWAY") + d->onlineStatus = usAway; + else if (value == "NA") + d->onlineStatus = usNA; + else if (value == "DND") + d->onlineStatus = usDND; + else if (value == "INVISIBLE") + d->onlineStatus = usInvisible; + + resetStatus(); + } else if (messageType == "USERS") {//some user info + QString theRest = message.section(' ', 1).stripWhiteSpace();//take the rest + if (d->searchFor == "FRIENDS") {//it was initial search for al users + QStringList names = QStringList::split(",", theRest);//divide it into names by comas + kdDebug(14311) << "Names: " << names << endl;//write what you have done with that + for (QStringList::iterator it = names.begin(); it != names.end(); ++it) {//run trough the names + QString name = (*it).stripWhiteSpace();//get the name only + if (name.isEmpty()) + continue;//just skip the empty names + emit newUser(name);//add the user to list + } + if (d->scanForUnread) + search("MISSEDMESSAGES"); + } + } else if (messageType == "USER") {//This is for some contact + const QString &contactId = message.section(' ', 1, 1);//take the second part, it is the user name + const QString &type = message.section(' ', 2, 2).stripWhiteSpace().upper();//get what it is + if ((type == "FULLNAME") || (type == "DISPLAYNAME") || (type == "SEX") || + (type == "PHONE_HOME") || (type == "PHONE_OFFICE") || + (type == "PHONE_MOBILE") || + (type == "ONLINESTATUS") || (type == "BUDDYSTATUS") || (type == "HOMEPAGE")) { + const QString &info = message.section(' ', 2);//and the rest is just the message for that contact + emit contactInfo(contactId, info);//and let the contact know + } else kdDebug(14311) << "Unknown message for contact, ignored" << endl; + } else if (messageType == "CHATMESSAGE") {//something with message, maebe incoming/sent + QString messageId = message.section(' ', 1, 1).stripWhiteSpace();//get the second part of message - it is the message ID + QString type = message.section(' ', 2, 2).stripWhiteSpace().upper();//This part significates what about the message are we talking about (status, body, etc..) + QString chatMessageType = (d->connection % QString("GET CHATMESSAGE %1 TYPE").arg(messageId)).section(' ', 3, 3).stripWhiteSpace().upper(); + if (chatMessageType == "ADDEDMEMBERS") { + QString status = message.section(' ', 3, 3).stripWhiteSpace().upper(); + if (d->recvMessages.find(messageId) != d->recvMessages.end()) + return; + d->recvMessages << messageId; + const QString &users = (d->connection % QString("GET CHATMESSAGE %1 USERS").arg(messageId)).section(' ', 3).stripWhiteSpace(); + QStringList splitUsers = QStringList::split(' ', users); + const QString &chatId = (d->connection % QString("GET CHATMESSAGE %1 CHATNAME").arg(messageId)).section(' ', 3, 3).stripWhiteSpace(); + for (QStringList::iterator it = splitUsers.begin(); it != splitUsers.end(); ++it) { + if ((*it).upper() == getMyself().upper()) + continue; + emit joinUser(chatId, *it); + } + return; + } else if (chatMessageType == "LEFT") { + QString status = message.section(' ', 3, 3).stripWhiteSpace().upper(); + if (d->recvMessages.find(messageId) != d->recvMessages.end()) + return; + d->recvMessages << messageId; + const QString &chatId = (d->connection % QString("GET CHATMESSAGE %1 CHATNAME").arg(messageId)).section(' ', 3, 3).stripWhiteSpace(); + const QString &chatType = (d->connection % QString("GET CHAT %1 STATUS").arg(chatId)).section(' ', 3, 3).stripWhiteSpace().upper(); + if ((chatType == "DIALOG") || (chatType == "LEGACY_DIALOG")) + return; + const QString &user = (d->connection % QString("GET CHATMESSAGE %1 FROM_HANDLE").arg(messageId)).section(' ', 3, 3).stripWhiteSpace(); + const QString &reason = (d->connection % QString("GET CHATMESSAGE %1 LEAVEREASON").arg(messageId)).section(' ', 3, 3).stripWhiteSpace().upper(); + QString showReason = i18n("Unknown"); + if (reason == "USER_NOT_FOUND") { + showReason = i18n("User not found"); + } else if (reason == "USER_INCAPABLE") { + showReason = i18n("Does not have multi-user chat capability"); + } else if ((reason == "ADDER_MUST_BE_FRIEND") || ("ADDER_MUST_BE_AUTHORIZED")) { + showReason = i18n("Chat denied"); + } else if (reason == "UNSUBSCRIBE") { + showReason = ""; + } + if (user.upper() == getMyself().upper()) + return; + emit leftUser(chatId, user, showReason); + return; + } + if (type == "STATUS") {//OK, status of some message has changed, check what is it + QString value = message.section(' ', 3, 3).stripWhiteSpace().upper();//get the last part, what status it is + if (value == "RECEIVED") {//OK, received new message, possibly read it + if (chatMessageType == "SAID") {//OK, it is some IM + hitchHike(messageId);//receive the message + } + } else if (value == "SENDING") { + if ((d->connection % QString("GET CHATMESSAGE %1 TYPE").arg(messageId)).section(' ', 3, 3).stripWhiteSpace().upper() == "SAID") { + emit gotMessageId(messageId); + } + } else if (value == "SENT") {//Sendign out some message, that means it is a new one + if ((d->connection % QString("GET CHATMESSAGE %1 TYPE").arg(messageId)).section(' ', 3, 3).stripWhiteSpace().upper() == "SAID")//it is some message I'm interested in + emit gotMessageId(messageId);//Someone may be interested in its ID + if (d->recvMessages.find(messageId) != d->recvMessages.end()) + return;//we already got this one + d->recvMessages << messageId; + const QString &chat = (d->connection % QString("GET CHATMESSAGE %1 CHATNAME").arg(messageId)).section(' ', 3, 3).stripWhiteSpace(); + const QString &body = (d->connection % QString("GET CHATMESSAGE %1 BODY").arg(messageId)).section(' ', 3); + if (!body.isEmpty())//sometimes skype shows empty messages, just ignore them + emit outgoingMessage(body, chat); + } + } + } else if (messageType == "CHATMESSAGES") { + if (d->searchFor == "MISSEDMESSAGES") {//Theese are messages we did not read yet + QStringList messages = QStringList::split(' ', message.section(' ', 1));//get the meassage IDs + for (QStringList::iterator it = messages.begin(); it != messages.end(); ++it) { + QString Id = (*it).stripWhiteSpace(); + if (Id.isEmpty()) + continue; + skypeMessage(QString("CHATMESSAGE %1 STATUS RECEIVED").arg(Id));//simulate incoming message notification + } + } + } else if (messageType == "CALL") { + const QString &callId = message.section(' ', 1, 1).stripWhiteSpace(); + if (message.section(' ', 2, 2).stripWhiteSpace().upper() == "CONF_ID") { + if (d->knownCalls.findIndex(callId) == -1) {//new call + d->knownCalls << callId; + const QString &userId = (d->connection % QString("GET CALL %1 PARTNER_HANDLE").arg(callId)).section(' ', 3, 3).stripWhiteSpace(); + emit newCall(callId, userId); + } + const QString &confId = message.section(' ', 3, 3).stripWhiteSpace().upper(); + if (confId != "0") {//It is an conference + emit groupCall(callId, confId); + } + } + if (message.section(' ', 2, 2).stripWhiteSpace().upper() == "STATUS") { + if (d->knownCalls.findIndex(callId) == -1) {//new call + d->knownCalls << callId; + const QString &userId = (d->connection % QString("GET CALL %1 PARTNER_HANDLE").arg(callId)).section(' ', 3, 3).stripWhiteSpace(); + emit newCall(callId, userId); + } + const QString &status = message.section(' ', 3, 3).stripWhiteSpace().upper(); + if (status == "FAILED") { + int reason = (d->connection % QString("GET CALL %1 FAILUREREASON").arg(callId)).section(' ', 3, 3).stripWhiteSpace().toInt(); + QString errorText = i18n("Unknown error"); + switch (reason) { + case 1: + errorText = i18n("Misc error"); + break; + case 2: + errorText = i18n("User or phone number does not exist"); + break; + case 3: + errorText = i18n("User is offline"); + break; + case 4: + errorText = i18n("No proxy found"); + break; + case 5: + errorText = i18n("Session terminated"); + break; + case 6: + errorText = i18n("No common codec found"); + break; + case 7: + errorText = i18n("Sound I/O error"); + break; + case 8: + errorText = i18n("Problem with remote sound device"); + break; + case 9: + errorText = i18n("Call blocked by recipient"); + break; + case 10: + errorText = i18n("Recipient not a friend"); + break; + case 11: + errorText = i18n("User not authorized by recipient"); + break; + case 12: + errorText = i18n("Sound recording error"); + break; + } + emit callError(callId, errorText); + } + emit callStatus(callId, status); + } + } else if (messageType == "CURRENTUSERHANDLE") { + QString user = message.section(' ', 1, 1).stripWhiteSpace(); + QString name = (d->connection % QString("GET USER %1 DISPLAYNAME").arg(user)).section(' ', 3).stripWhiteSpace(); + if (name.isEmpty()) + name = (d->connection % QString("GET USER %1 FULLNAME").arg(user)).section(' ', 3).stripWhiteSpace(); + if (name.isEmpty()) + name = user; + emit setMyselfName(name); + } +} + +void Skype::getContactBuddy(const QString &contact) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + d->connection << QString("GET USER %1 BUDDYSTATUS").arg(contact);//just make a message asking for the buddystatus of user and send it +} + +void Skype::resetStatus() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + switch (d->connStatus) { + case csOffline: + case csLoggedOut: + emit wentOffline();//Do not care what is the user marked as, this is more importatnt + return; + case csConnecting: + if (d->onlineStatus == usOffline)//not connecting, user wants to be offline + break; + emit statusConnecting();//still connecting, wait a minute + return; + default://just remove the compile-time warning about not handled value + break; + } + + switch (d->onlineStatus) { + case usUnknown: + emit statusConnecting(); + break; + case usOffline: + emit wentOffline(); + break; + case usOnline: + emit wentOnline(); + break; + case usSkypeMe: + emit wentSkypeMe(); + break; + case usAway: + emit wentAway(); + break; + case usNA: + emit wentNotAvailable(); + break; + case usDND: + emit wentDND(); + break; + case usInvisible: + emit wentInvisible(); + break; + } +} + +void Skype::search(const QString &what) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + d->searchFor = what.section(' ', 0, 0).stripWhiteSpace().upper(); + d->connection << QString("SEARCH %1").arg(what.upper());//search for that +} + +void Skype::getContactInfo(const QString &contact) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + d->connection << QString("GET USER %1 FULLNAME").arg(contact)//ask for full name + << QString("GET USER %1 SEX").arg(contact)//ask for sex + << QString("GET USER %1 DISPLAYNAME").arg(contact) + << QString("GET USER %1 PHONE_HOME").arg(contact) + << QString("GET USER %1 PHONE_OFFICE").arg(contact) + << QString("GET USER %1 PHONE_MOBILE").arg(contact) + << QString("GET USER %1 ONLINESTATUS").arg(contact) + << QString("GET USER %1 HOMEPAGE").arg(contact) + << QString("GET USER %1 BUDDYSTATUS").arg(contact);//and the rest of info +} + +bool Skype::canComunicate() { + return d->connection.connected(); +} + +void Skype::setHitchMode(bool value) { + d->hitch = value; +} + +void Skype::setMarkMode(bool value) { + d->mark = value; +} + +void Skype::hitchHike(const QString &messageId) { + kdDebug(14311) << k_funcinfo << "Message: " << messageId << endl;//some debug info + + const QString &chat = (d->connection % QString("GET CHATMESSAGE %1 CHATNAME").arg(messageId)).section(' ', 3, 3).stripWhiteSpace(); + + const QString &chatType = (d->connection % QString("GET CHAT %1 STATUS").arg(chat)).section(' ', 3, 3).stripWhiteSpace().upper(); + + if ((chatType == "LEGACY_DIALOG") || (chatType == "DIALOG")) { + + const QString &user = (d->connection % QString("GET CHATMESSAGE %1 FROM_HANDLE").arg(messageId)).section(' ', 3, 3).stripWhiteSpace();//ask skyp for a sender of that message and filter out the blouat around (like CHATMESSAGE 123...) + + if ((d->hitch) || (d->account.userHasChat(user))) {//it can be read eather if the hitchhiking non-chat messages is enabled or if the user already has opened a chat + emit receivedIM(user, (d->connection % QString("GET CHATMESSAGE %1 BODY").arg(messageId)).section(' ', 3), messageId);//ask skype for the body and filter out the bload, we want only the text and make everyone aware that we received a message + if (d->mark) //We should mark it as read + d->connection << QString("SET CHATMESSAGE %1 SEEN").arg(messageId);//OK, just tell skype it is read + } + } else { + if ((d->hitch) || (d->account.chatExists(chat))) { + const QString &user = (d->connection % QString("GET CHATMESSAGE %1 FROM_HANDLE").arg(messageId)).section(' ', 3, 3).stripWhiteSpace(); + emit receivedMultiIM(chat, (d->connection % QString("GET CHATMESSAGE %1 BODY").arg(messageId)).section(' ', 3), messageId, user); + if (d->mark) + d->connection << QString("SET CHATMESSAGE %1 SEEN").arg(messageId); + } + } +} + +void Skype::send(const QString &user, const QString &message) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + d->connection << QString("MESSAGE %1 %2").arg(user).arg(message);//just ask skype to send it +} + +void Skype::setScanForUnread(bool value) { + d->scanForUnread = value; +} + +void Skype::makeCall(const QString &userId) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + d->connection << QString("CALL %1").arg(userId); +} + +void Skype::acceptCall(const QString &callId) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + d->connection << QString("SET CALL %1 STATUS INPROGRESS").arg(callId); +} + +void Skype::hangUp(const QString &callId) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + d->connection << QString("SET CALL %1 STATUS FINISHED").arg(callId); +} + +void Skype::toggleHoldCall(const QString &callId) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + const QString &status = (d->connection % QString("GET CALL %1 STATUS").arg(callId)).section(' ', 3, 3).stripWhiteSpace().upper(); + if ((status == "ONHOLD") || (status == "LOCALHOLD")) + d->connection << QString("SET CALL %1 STATUS INPROGRESS").arg(callId); + else + d->connection << QString("SET CALL %1 STATUS ONHOLD").arg(callId); +} + +bool Skype::isCallIncoming(const QString &callId) { + const QString &type = (d->connection % QString("GET CALL %1 TYPE").arg(callId)).section(' ', 3, 3).stripWhiteSpace().upper(); + return ((type == "INCOMING_P2P") || (type == "INCOMING_PSTN")); +} + +void Skype::getSkypeOut() { + const QString &curr = (d->connection % QString("GET PROFILE PSTN_BALANCE_CURRENCY")).section(' ', 2, 2).stripWhiteSpace().upper(); + if (curr.isEmpty()) { + emit skypeOutInfo(0, ""); + } else { + int value = (d->connection % QString("GET PROFILE PSTN_BALANCE")).section(' ', 2, 2).stripWhiteSpace().toInt(); + emit skypeOutInfo(value, curr); + } +} + +void Skype::enablePings(bool enabled) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + d->pings = enabled; + + if (!enabled) { + d->pingTimer->stop(); + return; + } + + if (d->connStatus != csOffline) { + d->pingTimer->start(1000); + } +} + +void Skype::ping() { + d->connection << QString("PING"); +} + +void Skype::setBus(int bus) { + d->bus = bus; +} + +void Skype::setStartDBus(bool enabled) { + d->startDBus = enabled; +} + +void Skype::setLaunchTimeout(int seconds) { + d->launchTimeout = seconds; +} + +void Skype::setSkypeCommand(const QString &command) { + d->skypeCommand = command; +} + +void Skype::setWaitConnect(int value) { + d->waitBeforeConnect = value; +} + +void Skype::sendToChat(const QString &chat, const QString &message) { + kdDebug(14311) << k_funcinfo << endl;//some debug info` + + if (d->connection.protocolVer() <= 4) {//Not able to handle it by the API, let Skype do it for me + d->connection << QString("OPEN CHAT %1 %2").arg(chat).arg(message); + emit gotMessageId(""); + } else { + d->connection << QString("CHATMESSAGE %1 %2").arg(chat).arg(message); + } +} + +void Skype::getTopic(const QString &chat) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + emit setTopic(chat, (d->connection % QString("GET CHAT %1 FRIENDLYNAME").arg(chat)).section(' ', 3).stripWhiteSpace()); +} + +QString Skype::getMessageChat(const QString &message) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + return (d->connection % QString("GET CHATMESSAGE %1 CHATNAME").arg(message)).section(' ', 3, 3).stripWhiteSpace(); +} + +QStringList Skype::getChatUsers(const QString &chat) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + const QString &me = getMyself(); + const QString &rawUsers = (d->connection % QString("GET CHAT %1 MEMBERS").arg(chat)).section(' ', 3).stripWhiteSpace(); + const QStringList &users = QStringList::split(' ', rawUsers); + QStringList readyUsers; + for (QStringList::const_iterator it = users.begin(); it != users.end(); ++it) { + const QString &user = (*it).stripWhiteSpace(); + if (user.upper() != me.upper()) + readyUsers.append(user); + } + + return readyUsers; +} + +QString Skype::getMyself() { + return (d->connection % QString("GET CURRENTUSERHANDLE")).section(' ', 1, 1).stripWhiteSpace(); +} + +void Skype::inviteUser(const QString &chatId, const QString &userId) { + kdDebug(14311) << k_funcinfo << " " << chatId << " " << userId << endl;//some debug info + + if (d->connection.protocolVer() <= 4) { + KMessageBox::error(0L, i18n("This version of Skype does not support adding users to chat."), i18n("Skype Protocol")); + return; + } + + d->connection << QString("ALTER CHAT %1 ADDMEMBERS %2").arg(chatId).arg(userId); +} + +QString Skype::createChat(const QString &users) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + const QString &chatDesc = d->connection % QString("CHAT CREATE %1").arg(users); + kdDebug(14311) << "New chat ID: " << chatDesc.section(' ', 1, 1) << endl; + return chatDesc.section(' ', 1, 1); +} + +void Skype::leaveChat(const QString &chatId) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + d->connection << QString("ALTER CHAT %1 LEAVE").arg(chatId); +} + +void Skype::removeContact(const QString &contactId) { + kdDebug(14311) << k_funcinfo << endl; + + d->connection << QString("SET USER %1 BUDDYSTATUS 1").arg(contactId); +} + +void Skype::addContact(const QString &contactId) { + kdDebug(14311) << k_funcinfo << endl; + + d->connection % QString("SET USER %1 BUDDYSTATUS 2").arg(contactId);//do NOT parse this so the contact won't be created automatically +} + +void Skype::setAuthor(const QString &contactId, AuthorType author) { + kdDebug(14311) << k_funcinfo << endl; + + switch (author) { + case Author: + d->connection << QString("SET USER %1 ISBLOCKED FALSE").arg(contactId); + d->connection << QString("SET USER %1 ISAUTHORIZED TRUE").arg(contactId); + break; + case Deny: + d->connection << QString("SET USER %1 ISBLOCKED FALSE").arg(contactId); + d->connection << QString("SET USER %1 ISAUTHORIZED FALSE").arg(contactId); + break; + case Block: + d->connection << QString("SET USER %1 ISBLOCKED TRUE").arg(contactId); + break; + } +} + +Skype::AuthorType Skype::getAuthor(const QString &contactId) { + if ((d->connection % QString("GET USER %1 ISBLOCKED").arg(contactId)).section(' ', 3, 3).stripWhiteSpace().upper() == "TRUE") + return Block; + else if ((d->connection % QString("GET USER %1 ISAUTHORIZED").arg(contactId)).section(' ', 3, 3).stripWhiteSpace().upper() == "TRUE") + return Author; + else + return Deny; +} + +bool Skype::ableConference() { + return false; +} + +#include "skype.moc" diff --git a/plugins/skype/libskype/skype.h b/plugins/skype/libskype/skype.h new file mode 100644 index 0000000..11241a8 --- /dev/null +++ b/plugins/skype/libskype/skype.h @@ -0,0 +1,466 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Michal Vaner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ +#ifndef SKYPE_H +#define SKYPE_H + +#include + +class SkypePrivate; +class SkypeAccount; + +/** + * This class is internal backend for skype. It provides slots for such things like "send a IM" and so + * @author SIM Developers + */ +class Skype : public QObject +{ + Q_OBJECT + private: + ///The d pointer for private things + SkypePrivate *d; + /** + * Will try to hitchhike a message. It will hitchhike it, show it in the proper chat session and so on, but just when it is enabled by hitchhike mode and will maker it as read if enabled + * @param messageId ID of the message to hitchHike + */ + void hitchHike(const QString &messageId); + private slots: + /** + * Adds new message do be sent to skype (normaly is sent imediatelly). + * If there is no connection to skype, it is created before it is sent. + * @param message Message to send to skype + * @param deleteQueue If this is true, all message waiting to be sent are deleted and only this one stays in the queue + */ + void queueSkypeMessage(const QString &message, bool deleteQueue); + /** + * Listens for closed skype connection + */ + void closed(int reason); + /** + * Listens for finishing the connecting attempt and sending the queue if it was successful + * @param error - Did it work or was there some error? + * @param protocolVer - Version of protocol used by this connection + */ + void connectionDone(int error, int protocolVer); + /** + * This one showes an error message + * @param message What to write on the dialog box + */ + void error(const QString &message); + /** + * This one scans messages from Skype API and acts acordingly to them (changing online status, showing messages.... + * @param message What the skype said + */ + void skypeMessage(const QString &message); + /** + * This one resets the online status showed on the icon in SIM depending on last values from skype. + * Used when the status changes + */ + void resetStatus(); + /** + * Makes the Skype search for something and saves what it was to decide later, what to do with it + * @param what What are we searching for + */ + void search(const QString &what); + public: + /** + * Constructor + * @param account The account that this connection belongs to + */ + Skype(SkypeAccount &account); + /** + * Destructor + */ + ~Skype(); + ///Can we comunicate with the skype program right now? + bool canComunicate(); + /** + * Enables or disables hitchhake mode of incoming messages + * @see SkypeAccount::setHitchHike + */ + void setHitchMode(bool value); + /** + * Enables or disables mark read messages mode + * @see SkypeAccount::setMarkRead + */ + void setMarkMode(bool value); + /** + * Enables/disables scanning for unread messages after login + * @see SkypeAccount::setScanForUnread + */ + void setScanForUnread(bool value); + /** + * Is that call incoming call? + * @param callId What call you mean? + * @return true if the call is incoming + */ + bool isCallIncoming(const QString &callId); + /** + * Returns ID of chat to what given message belongs + * @param messageId Id of the wanted message + * @return ID of the chat. For unexisten message the result is not defined. + */ + QString getMessageChat(const QString &messageId); + /** + * Returns list of users in that chat without actual user + * @param chat ID of that chat you want to know + */ + QStringList getChatUsers(const QString &chat); + /** + * This will return ID of the actual user this one that uses this skype) + */ + QString getMyself(); + /** + * Create a chat with that members + * @param users List of users separated by coma (user_1, user_2, user...) + * @return Id of the new chat + */ + QString createChat(const QString &users); + /** + * Says if the contact should be authorize, not authorized or blocked + */ + enum AuthorType { + Author, + Deny, + Block + }; + /** + * Ask if the user how is the user authorized + * @param contactId What user are you interested in? + */ + AuthorType getAuthor(const QString &contactId); + /** + * Is this version of protocol able to create conference calls? + */ + bool ableConference(); + public slots: + /** + * Tell the skype to go online + */ + void setOnline(); + /** + * Tell the skype to go offline + */ + void setOffline(); + /** + * Tell the skype to go offline + */ + void setAway(); + /** + * Tell the skype to go not available + */ + void setNotAvailable(); + /** + * Tell the skype to go to Do not disturb + */ + void setDND(); + /** + * Tell the skype to go to Skype me mode + */ + void setSkypeMe(); + /** + * Tell the skype to go invisible + */ + void setInvisible(); + /** + * This sets the values of the account. + * @see SkypeAccount + */ + void setValues(int launchType, const QString &appName); + /** + * Retrieve info of that contact + * @param contact What contact wants it + */ + void getContactInfo(const QString &contact); + /** + * Asks skype for buddy status of some contact. Buddystatus is some property that ondicates, weather it is in contact list, awaiting authorization, just been mentioned or what exactly happened with it.. + * After skype responses, you will get the response by emiting the received signal + * @param contact It is the contact id of the user you want to check. + */ + void getContactBuddy(const QString &contact); + /** + * Sends a message trough skype + * @param user To who it should be sent + * @param body What to send + */ + void send(const QString &user, const QString &body); + /** + * Send a message to a given chat + * @param chat What chat to send it in + * @param body Text of that message + */ + void sendToChat(const QString &chat, const QString &body); + /** + * Begins new call. + * @param userId ID of user to call (or multiple users separated by comas) + * @see acceptCall + * @see hangUp + * @see holdCall + * @see callStatus + * @see callError + */ + void makeCall(const QString &userId); + /** + * Accept an incoming call + * @param callId ID of call to accept. + * @see makeCall + * @see hangUp + * @see holdCall + * @see callStatus + * @see callError + * @see newCall + */ + void acceptCall(const QString &callId); + /** + * Hang up (finish) call in progress or deny an incoming call + * @param callId Which one + * @see makeCall + * @see acceptCall + * @see holdCall + * @see callStatus + * @see callError + * @see newCall + */ + void hangUp(const QString &callId); + /** + * Hold call in progress or resume holded call. That call will not finish, you just leave it for later. + * @param callId Which call + * @see makeCall + * @see acceptCall + * @see hangUp + * @see callStatus + * @see callError + * @see newCall + */ + void toggleHoldCall(const QString &callId); + /** + * Get the skoype out balance + */ + void getSkypeOut(); + /** + * Sets if the Skype is checked in short intervals by pings. If you turn that off, you will not know when skype exits. + * @param enabled Ping or not? + */ + void enablePings(bool enabled); + /** + * Sends one ping and takes actions if it can not be delivered (skype is down) + */ + void ping(); + /** + * What DBus bus is used? + */ + void setBus(int bus); + /** + * Start DBus if not wunning? + */ + void setStartDBus(bool value); + /** + * Set the launch timeout - after that launch of Skype will be considered as unsuccessfull if connection can not be established + */ + void setLaunchTimeout(int seconds); + /** + * Set a command to start skype by + */ + void setSkypeCommand(const QString &command); + /** + * Sets if we wait a bit before connecting to Skype after it's start-up + */ + void setWaitConnect(int value); + /** + * This gets a topic for given chat session + * @param chat What chat wants that + */ + void getTopic(const QString &chat); + /** + * Invites a user to a chat + * @param chatId What chat + * @param userId What user + */ + void inviteUser(const QString &chatId, const QString &userId); + /** + * Closes/leaves a chat + * @param chatId What chat + */ + void leaveChat(const QString &chatId); + /** + * Removes a contact from the contact list + * @param contactId Id of the contact you want to remove + */ + void removeContact(const QString &contactId); + /** + * Adds a contact to the list + * @param contactId Id of the contact to add + * @param contactId + */ + void addContact(const QString &contactId); + /** + * Sets users authorization + * @param contactId ID of that user + * @param author for what is he authorized + */ + void setAuthor(const QString &contactId, AuthorType author); + signals: + /** + * Emitted when the skype changes to online (or says it goes online) + */ + void wentOnline(); + /** + * Emitted when the skype goes offline + */ + void wentOffline(); + /** + * Emitted when the skype goes away + */ + void wentAway(); + /** + * Emitted when the skype goes to Not awailable + */ + void wentNotAvailable(); + /** + * Emitted when the skype goes to DND mode + */ + void wentDND(); + /** + * Emitted when skype changes to skype me mode + */ + void wentSkypeMe(); + /** + * Emitted when skype becomes invisible + */ + void wentInvisible(); + /** + * Emitted when atempt to connect started + */ + void statusConnecting(); + /** + * Emitted when new user should be added to the list + * @param name The skype name of the user + */ + void newUser(const QString &name); + /** + * All contacts should be asked to request update of their information. This is emitted after the connection to skype is made. + */ + void updateAllContacts(); + /** + * This is emitted whenever some contact should be notified of info change + * @param contact What contact is it + * @param change The change. The syntax is [property (displayname, onlinestatus..)] [value] + */ + void contactInfo(const QString &contact, const QString &change); + /** + * This is emitted when a new message is received + * @param user Contact ID of user that sent it. It is NOT guaranteed that the user is in list! + * @param body The message body that was received + * @param messageId ID of that message + */ + void receivedIM(const QString &user, const QString &body, const QString &messageId); + /** + * This is emitted when a new message from multi-user chat is received + * @param chat Id of the chat + * @param body Tect of the message + * @param messageId Id of this message to get information about it if needed + * @param user Who sent it to that chat (ID) + */ + void receivedMultiIM(const QString &chat, const QString &body, const QString &messageId, const QString &user); + /** + * This is emitted when an Id of the last outgoing message is known + * @param id The ID of that message + */ + void gotMessageId(const QString &id); + /** + * This slot notifies about call status (onhold, in progress, routing, finished..) + * @param callId WHat call is it? + * @param status New status of the call. + * @see makeCall + * @see acceptCall + * @see hangUp + * @see holdCall + * @see callError + * @see newCall + */ + void callStatus(const QString &callId, const QString &status); + /** + * This slot informs of error that happened to the call. It is translated error and can be directly showed to user. + * @param callId ID of the call that has an error. + * @param message The error text + * @see makeCall + * @see acceptCall + * @see hangUp + * @see holdCall + * @see callStatus + * @see newCall + */ + void callError(const QString &callId, const QString &message); + /** + * Indicates a new call is established (is being established, incoming or so). In short, there is some new call. + * @param callId ID of the new call + * @param userId ID of the other user, or list of users (if more than one) divided by spaces + * @see makeCall + * @see acceptCall + * @see hangUp + * @see holdCall] + * @see callStatus + * @see callError + */ + void newCall(const QString &callId, const QString &userId); + /** + * Skype out balance info + * @param balance How much does the user have + * @param currency And what is it that he has + */ + void skypeOutInfo(int balance, const QString ¤cy); + /** + * Tells that my name is known or changed + * @param name The new name + */ + void setMyselfName(const QString &name); + /** + * Some topic has to be set + * @param chat What chat should change its topic + * @param topic The new topic + */ + void setTopic(const QString &chat, const QString &topic); + /** + * This is emitted when a new user joins a chat + * @param chat What chat he joined + * @param userId ID of the new user + */ + void joinUser(const QString &chat, const QString &userId); + /** + * This is emitted when user leaves a chat + * @param chat What chat did he leave + * @param userId ID of that user + * @param reason Reason why he left + */ + void leftUser(const QString &chat, const QString &userd, const QString &reason); + /** + * Emitted when some message is being sent out right now + * @param body Text of the message + * @param chat Id of the chat it has been sent to + */ + void outgoingMessage(const QString &body, const QString &chat); + /** + * Put this call into a group, where other calls are (will be), used with conference calls + * @param callId Id of the call + * @param groupId The id of a group + * Note: the group should be closed when all it's calls are closed + */ + void groupCall(const QString &callId, const QString &groupId); +}; + +#endif diff --git a/plugins/skype/libskype/skypedbus/connection.cpp b/plugins/skype/libskype/skypedbus/connection.cpp new file mode 100644 index 0000000..9608e4e --- /dev/null +++ b/plugins/skype/libskype/skypedbus/connection.cpp @@ -0,0 +1,426 @@ +// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; -*- + +/* connection.cpp: Qt wrapper for DBusConnection +* +* Copyright (C) 2003 Zack Rusin +* +* Licensed under the Academic Free License version 2.0 +* +* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +*/ + +#include +#include +#include + +#define DBUS_API_SUBJECT_TO_CHANGE +#include "connection.h" + +using namespace DBusQt; + +#include "integrator.h" +using Internal::Integrator; + +struct Connection::Private +{ + Private( Connection * qq ); + ~Private( ); + void setConnection( DBusConnection * c, bool tmp = FALSE ); + DBusConnection *connection; + int connectionSlot; + DBusError error; + Integrator *integrator; + int timeout; + Connection *q; +}; + +Connection::Private::Private( Connection * qq ):connection( 0 ), connectionSlot( -1 ), integrator( 0 ), timeout( -1 ), q( qq ) +{ + dbus_error_init( &error ); +} + +Connection::Private::~Private( ) +{ + delete integrator; +} + +void Connection::Private::setConnection( DBusConnection * c, bool tmp ) +{ + if ( !c ) + { + return; + } + + connection = c; + integrator = new Integrator( c, q, tmp ); + connect( integrator, SIGNAL( readReady( ) ), q, SLOT( dispatchRead( ) ) ); +} + +Connection::Connection( QObject * parent ):QObject( parent ) +{ + d = new Private( this ); + + dbus_error_init( &d->error ); +} + +Connection::Connection( const QString & host, QObject * parent ):QObject( parent ) +{ + d = new Private( this ); + + if ( !host.isEmpty( ) ) + { + DBusConnection *cn = dbus_connection_open( host.ascii( ), &d->error ); + + if ( error( ) ) + { + qDebug( "dbus_connection_open failed." ); + return; + } + + d->setConnection( cn, TRUE ); + } +} + +Connection::Connection( DBusBusType type, QObject * parent, bool temporary ):QObject( parent ) +{ + + qDebug( "Connection::Connection" ); + d = new Private( this ); + DBusConnection *cn = dbus_bus_get( type, &d->error ); + + if ( error( ) ) + { + qDebug( "dbus_bus_get failed." ); + return; + } + + d->setConnection( cn, temporary ); + + //QTimer *timer = new QTimer(this); + + //connect(timer, SIGNAL(timeout()), this, SLOT(dispatchRead())); + + //timer->start(500, FALSE); +} + +Connection::~Connection( ) +{ + delete d->integrator; + d->integrator = 0L; + + dbus_connection_unref( d->connection ); + delete d; +} + +void Connection::init( const QString & host ) +{ + d->setConnection( dbus_connection_open( host.ascii( ), &d->error ) ); + dbus_connection_allocate_data_slot( &d->connectionSlot ); + dbus_connection_set_data( d->connection, d->connectionSlot, 0, 0 ); +} + +bool Connection::isConnected( ) const +{ + return dbus_connection_get_is_connected( d->connection ); +} + +bool Connection::isAuthenticated( ) const +{ + return dbus_connection_get_is_authenticated( d->connection ); +} + +void Connection::open( const QString & host ) +{ + if ( host.isEmpty( ) ) + return; + + init( host ); +} + +void Connection::close( ) +{ + dbus_connection_disconnect( d->connection ); +} + +void Connection::flush( ) +{ + dbus_connection_flush( d->connection ); +} + +bool Connection::event( QEvent * e ) +{ + if ( e->type( ) == DBUS_EVENT_WAKEUP ) + { + qDebug( "Custom event received." ); + + dispatchRead( ); + + return TRUE; + } + else + return QObject::event( e ); +} + +void Connection::dispatchRead( ) +{ + qDebug( "API: dispatchRead" ); + + //dbus_connection_flush(d->connection); + + /*DBusDispatchStatus status = dbus_connection_get_dispatch_status(d->connection); + + if (status == DBUS_DISPATCH_DATA_REMAINS) + dbus_connection_dispatch( d->connection ); + */ + + /*DBusDispatchStatus status = dbus_connection_get_dispatch_status(d->connection); + + switch(status) + { + case DBUS_DISPATCH_DATA_REMAINS: + qDebug("DBUS_DISPATCH_DATA_REMAINS"); + break; + case DBUS_DISPATCH_COMPLETE: + qDebug("DBUS_DISPATCH_COMPLETE"); + break; + case DBUS_DISPATCH_NEED_MEMORY: + qDebug("DBUS_DISPATCH_NEED_MEMORY"); + break; + default: + qDebug("UNKNOWN"); + break; + } */ + + while ( dbus_connection_dispatch( d->connection ) == DBUS_DISPATCH_DATA_REMAINS ) ; + + // status; + //while(1) + /* + do + { + status = dbus_connection_dispatch(d->connection);//DBUS_DISPATCH_COMPLETE; + // + + switch(status) + { + case DBUS_DISPATCH_DATA_REMAINS: + qDebug("DBUS_DISPATCH_DATA_REMAINS"); + break; + case DBUS_DISPATCH_COMPLETE: + qDebug("DBUS_DISPATCH_COMPLETE"); + break; + case DBUS_DISPATCH_NEED_MEMORY: + qDebug("DBUS_DISPATCH_NEED_MEMORY"); + break; + default: + qDebug("UNKNOWN"); + break; + } + + if (status == DBUS_DISPATCH_DATA_REMAINS) + { + qDebug("dispatching ..."); + + dbus_connection_dispatch(d->connection); + } + + } while (status != DBUS_DISPATCH_COMPLETE); + */ +} + +DBusConnection *Connection::connection( ) +{ + return d->connection; +} + +Connection::Connection( DBusConnection * connection, QObject * parent ):QObject( parent ) +{ + d = new Private( this ); + d->setConnection( connection ); +} + +void Connection::send( const Message & m ) +{ + (void) getError(); + dbus_connection_send( d->connection, m.message( ), 0 ); +} + +void Connection::sendWithReply( const Message & ) +{ +} + +Message Connection::sendWithReplyAndBlock( const Message & m ) +{ + (void) getError(); + DBusMessage *reply; + + reply = dbus_connection_send_with_reply_and_block( d->connection, m.message( ), d->timeout, &d->error ); + + if ( error( ) ) + return m; + else + return Message( reply ); +} + +bool Connection::error( ) +{ + return dbus_error_is_set( &d->error ); +} + +QString Connection::getError( ) +{ + QString err; + + if ( dbus_error_is_set( &d->error ) ) + { + err = d->error.name; + dbus_error_free( &d->error ); + } + + return err; +} + +void *Connection::virtual_hook( int, void * ) +{ + return 0; +} + +static DBusHandlerResult nm_message_handler( DBusConnection * connection, DBusMessage * message, void *user_data ) +{ + const char *method; + const char *path; + const char *sender; + const char *signature; + + //DBusMessage *reply_message = NULL; + //gboolean handled = TRUE; + Connection *c = static_cast < Connection * >( user_data ); + + //g_return_val_if_fail (connection != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED); + //g_return_val_if_fail (message != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED); + + qDebug( "nm_message_handler" ); + + c->dbusMessage( message ); + + method = dbus_message_get_member( message ); + path = dbus_message_get_path( message ); + sender = dbus_message_get_sender( message ); + signature = dbus_message_get_signature( message ); + + qDebug( "nm_dbus_nm_message_handler() got method %s for path %s, sender %s", method, path, sender ); + + /* + if (strcmp("testFunction", method) == 0) + return DBUS_HANDLER_RESULT_HANDLED; + else + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + */ + //Connection c(connection, NULL); + //Message in(message); + //Message out(in); + + //out << "Success."; + + //c->send(out); + + /* + if (strcmp ("setKeyForNetwork", method) == 0) + set_user_key_for_network (connection, message, user_data); + else + handled = FALSE; + + return (handled ? DBUS_HANDLER_RESULT_HANDLED : DBUS_HANDLER_RESULT_NOT_YET_HANDLED); + */ + return DBUS_HANDLER_RESULT_HANDLED; +} + +static void nm_unregister_handler( DBusConnection * connection, void *user_data ) +{ + /* do nothing */ + qDebug( "nm_unregister_handler" ); +} + +void Connection::dbusMessage( DBusMessage * message ) +{ + qDebug( "Connection::dbusMessage" ); + + Message *m = new Message( message ); + + /*if (m->expectReply()) + { + qDebug("Message expects reply. Generating."); + Message* reply = new Message(*m); + (*reply) << QString("OLLEH"); + send(*reply); + flush(); + } */ + + emit messageArrived( *m ); +} + +bool Connection::registerObjectPath( const QString & path, const QString & service ) +{ + DBusObjectPathVTable vtable = { &nm_unregister_handler, &nm_message_handler, NULL, NULL, NULL, + NULL + }; + + //dbus_bus_acquire_service(d->connection, service, 0, &d->error); + //dbus_bus_activate_service( d->connection, "org.freedesktop.DBus", 0, NULL, &d->error ); + + //dbus_bus_set_base_service(d->connection, "com.Skype.API"); + + if ( error( ) ) + { + return FALSE; + } + + //qDebug("Connection base name: %s", dbus_bus_get_base_service(d->connection)); + + /*dbus_bus_acquire_service(d->connection, "com.Skype.API", 0, &d->error); + + if (dbus_error_is_set (&d->error)) + { + qDebug("Could not acquire its service. dbus_bus_acquirebool success = dbus_connection_register_fallback(d->connection, path.ascii(), &vtable, this);_service() says: '%s'", d->error.message); + + return FALSE; + } */ + + //dbus_bus_add_match(d->connection, "type='method_call',interface='com.Skype.API'", &d->error); + + //if (dbus_error_is_set (&d->error)) + //{ + // qDebug("Could not add match. Error is: '%s'", d->error.message); + + // return FALSE; + //} + + //bool success = dbus_connection_register_object_path(d->connection, path.ascii(), &vtable, this); + //success = dbus_connection_register_fallback(d->connection, "/org/freedesktop/DBus", &vtable, this); + + bool success = dbus_connection_register_object_path(d->connection, service.utf8(), &vtable, this); + + //success = dbus_connection_add_filter(d->connection, nm_message_handler, this, NULL); + if (!success) + { + qDebug("Could not register a handler for NetworkManager. Not enough memory?"); + return FALSE; + } + + return TRUE; +} + +#include "connection.moc" diff --git a/plugins/skype/libskype/skypedbus/connection.h b/plugins/skype/libskype/skypedbus/connection.h new file mode 100644 index 0000000..5e6afb1 --- /dev/null +++ b/plugins/skype/libskype/skypedbus/connection.h @@ -0,0 +1,95 @@ +// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; -*- + +/* connection.h: Qt wrapper for DBusConnection + * + * Copyright (C) 2003 Zack Rusin + * + * Licensed under the Academic Free License version 2.1 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef DBUS_QT_CONNECTION_H +#define DBUS_QT_CONNECTION_H + +#include "message.h" + +#include +#include +#include +#include + +const int DBUS_EVENT_WAKEUP = QEvent::User + 100; + +namespace DBusQt +{ + namespace Internal + { + class Integrator; + } + + class Connection : public QObject + { + Q_OBJECT + public: + Connection( QObject * parent = 0 ); + Connection( const QString & host, QObject * parent = 0 ); + Connection( DBusBusType type, QObject * parent = 0, bool temporary = FALSE ); + virtual ~ Connection( ); + + bool isConnected( ) const; + bool isAuthenticated( ) const; + + Message borrowMessage( ); + Message popMessage( ); + void stealBorrowMessage( const Message & ); + void dbusMessage( DBusMessage * message ); + bool error( ); + QString getError( ); + + public slots: + void open( const QString & ); + void close( ); + void flush( ); + void send( const Message & ); + void sendWithReply( const Message & ); + Message sendWithReplyAndBlock( const Message & ); + bool registerObjectPath( const QString & path, const QString & service ); + + protected slots: + void dispatchRead( ); + + protected: + void init( const QString & host ); + virtual void *virtual_hook( int id, void *data ); + bool event( QEvent * ); + + private: + friend class Internal::Integrator; + DBusConnection *connection( ); + Connection( DBusConnection * connection, QObject * parent ); + + private: + struct Private; + Private *d; + + signals: + void messageArrived( const DBusQt::Message & m ); + }; + +} + +#endif diff --git a/plugins/skype/libskype/skypedbus/integrator.cpp b/plugins/skype/libskype/skypedbus/integrator.cpp new file mode 100644 index 0000000..e766b66 --- /dev/null +++ b/plugins/skype/libskype/skypedbus/integrator.cpp @@ -0,0 +1,450 @@ +// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; -*- +/* integrator.h: integrates D-BUS into Qt event loop + * + * Copyright (C) 2003 Zack Rusin + * + * Licensed under the Academic Free License version 2.0 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#define DBUS_API_SUBJECT_TO_CHANGE + +#include "integrator.h" +#include "connection.h" + +#include +#include +#include +#include +#include +#include + +namespace DBusQt +{ +namespace Internal { + +struct Watch{ + Watch(): readSocket( 0 ), writeSocket( 0 ) { } + //~Watch(); + + DBusWatch *watch; + QSocketNotifier *readSocket; + QSocketNotifier *writeSocket; +}; + +/*Watch::~Watch() +{ + if (readSocket) + delete readSocket; + + if (writeSocket) + delete writeSocket; +}*/ + +////////////////////////////////////////////////////////////// +dbus_bool_t dbusAddWatch(DBusWatch* watch, void* data) +{ + int fd = dbus_watch_get_fd(watch); + + qDebug ("API: fd is %d", fd); + + Integrator *con = static_cast( data ); + con->addWatch( watch ); + + return true; +} + +void dbusRemoveWatch( DBusWatch *watch, void *data ) +{ + Integrator *con = static_cast( data ); + con->removeWatch( watch ); +} + +void dbusToggleWatch( DBusWatch *watch, void *data ) +{ + //return; + Integrator *itg = static_cast( data ); + //Watch* qw = itg->m_watches.find(dbus_watch_get_fd(watch)); + + qDebug("API: dbusToggleWatch"); + + int fd = dbus_watch_get_fd(watch); + + qDebug ("API: fd is %d", fd); + + if (dbus_watch_get_enabled(watch)) + { + //if (qw->readSocket) qw->readSocket->setEnabled(TRUE); + //if (qw->writeSocket) qw->writeSocket->setEnabled(TRUE); + itg->addWatch(watch); + qDebug("enabling"); + } + else + { + //if (qw->readSocket) qw->readSocket->setEnabled(FALSE); + //if (qw->writeSocket) qw->writeSocket->setEnabled(FALSE); + itg->removeWatch(watch); + qDebug("disabling"); + } + + /* + bool en = dbus_watch_get_enabled(watch); + int flags = dbus_watch_get_flags(watch); + + Integrator *itg = static_cast( data ); + Watch* qw = itg->m_watches.find(dbus_watch_get_fd(watch)); + + + if ( flags && DBUS_WATCH_READABLE ) + { + qw->readSocket->setEnabled(en); + } + + if (flags && DBUS_WATCH_WRITABLE) + { + qw->writeSocket->setEnabled(en); + } + */ + /* + if (dbus_watch_get_enabled(watch)) + { + //itg->addWatch(watch); + + if (qw) + { + qw->readSocket->setEnabled(TRUE); + qw->writeSocket->setEnabled(TRUE); + } + else + itg->addWatch( watch ); + } + else + { + //itg->removeWatch(watch); + + if (qw) + { + qw->readSocket->setEnabled(FALSE); + qw->writeSocket->setEnabled(FALSE); + } + else + itg->removeWatch( watch ); + } + */ +} + +dbus_bool_t dbusAddTimeout( DBusTimeout *timeout, void *data ) +{ + if ( !dbus_timeout_get_enabled(timeout) ) + return true; + + Integrator *itg = static_cast( data ); + itg->addTimeout( timeout ); + return true; +} + +void dbusRemoveTimeout( DBusTimeout *timeout, void *data ) +{ + Integrator *itg = static_cast( data ); + itg->removeTimeout( timeout ); +} + +void dbusToggleTimeout( DBusTimeout *timeout, void *data ) +{ + Integrator *itg = static_cast( data ); + + if ( dbus_timeout_get_enabled( timeout ) ) + itg->addTimeout( timeout ); + else + itg->removeTimeout( timeout ); +} + +void dbusWakeupMain(void* c) +{ + qDebug("wake up!"); + + //Connection* conn = static_cast(c); + + //conn->flush(); + + //if (conn) + // QApplication::postEvent(conn, new QCustomEvent(DBUS_EVENT_WAKEUP)); + + qApp->eventLoop()->wakeUp(); +} + +void dbusDispatchStatusChanged(DBusConnection *connection, DBusDispatchStatus new_status, void *data) +{ + qDebug("dbusDispatchStatusChanged invoked"); + + switch(new_status) + { + case DBUS_DISPATCH_DATA_REMAINS: + qDebug("DBUS_DISPATCH_DATA_REMAINS"); + break; + case DBUS_DISPATCH_COMPLETE: + qDebug("DBUS_DISPATCH_COMPLETE"); + break; + case DBUS_DISPATCH_NEED_MEMORY: + qDebug("DBUS_DISPATCH_NEED_MEMORY"); + break; + default: + qDebug("UNKNOWN"); + break; + } +} + +static dbus_bool_t dbusUidHandler(DBusConnection* c, unsigned long uid, void* data) +{ + qDebug("API: dbusUidHandler uid is %lu", uid); + + return TRUE; +} + +static void dbusNewConnection( DBusServer *server, + DBusConnection *new_connection, + void *data ) +{ + qDebug("dbusNewConnection() invoked"); + + dbus_connection_set_unix_user_function(new_connection, &dbusUidHandler, data, 0); + + Integrator *itg = static_cast( data ); + itg->handleConnection( new_connection ); +} + +///////////////////////////////////////////////////////////// + +Timeout::Timeout( QObject *parent, DBusTimeout *t ) + : QObject( parent ), m_timeout( t ) +{ + m_timer = new QTimer( this ); + connect( m_timer, SIGNAL(timeout()), + SLOT(slotTimeout()) ); +} + +void Timeout::slotTimeout() +{ + emit timeout( m_timeout ); +} + +void Timeout::start() +{ + m_timer->start( dbus_timeout_get_interval( m_timeout ) ); +} + +Integrator::Integrator(DBusConnection *conn, QObject *parent, bool tmp) + :QObject(parent), + m_connection(conn) +{ + qDebug("Integrator::Integrator(DBusConnection*) invoked"); + + m_timeouts.setAutoDelete( true ); + + dbus_connection_set_watch_functions( m_connection, + dbusAddWatch, + dbusRemoveWatch, + /*dbusToggleWatch*/0, + this, 0 ); + dbus_connection_set_timeout_functions( m_connection, + dbusAddTimeout, + dbusRemoveTimeout, + dbusToggleTimeout, + this, 0 ); + + //if (!tmp) + dbus_connection_set_wakeup_main_function(m_connection, dbusWakeupMain, parent, 0); + + //dbus_connection_set_dispatch_status_function(m_connection, dbusDispatchStatusChanged, this, 0); +} + +Integrator::Integrator( DBusServer *server, QObject *parent ) + : QObject( parent ), m_server( server ) +{ + qDebug("Integrator::Integrator(DBusServer*) invoked"); + + //m_connection = reinterpret_cast( m_server ); + m_timeouts.setAutoDelete( true ); + + dbus_server_set_watch_functions( m_server, + dbusAddWatch, + dbusRemoveWatch, + /*dbusToggleWatch*/0, + this, 0 ); + /*dbus_server_set_timeout_functions( m_server, + dbusAddTimeout, + dbusRemoveTimeout, + dbusToggleTimeout, + this, 0 );*/ + dbus_server_set_new_connection_function( m_server, + dbusNewConnection, + this, 0 ); +} + +Integrator::~Integrator() +{ + for (int nC = 0; nC < m_watches.count(); nC++) + delete m_watches[nC]; +} + +void Integrator::slotRead(int fd) +{ + qDebug("slotRead"); + QIntDictIterator it(m_watches); + + for (; it.current(); ++it) + dbus_watch_handle(it.current()->watch, DBUS_WATCH_READABLE); + + emit readReady(); + + /*if (Watch* ww = m_watches.find(fd)) + dbus_watch_handle(ww->watch, DBUS_WATCH_READABLE); + + if (m_connection) + { + //_dbus_connection_acquire_dispatch(m_connection); + //dbus_connection_dispatch(m_connection); + //_dbus_connection_release_dispatch(m_connection); + + emit readReady(); +}*/ +} + +void Integrator::slotWrite(int fd) +{ + //qDebug("slotWrite"); + + QIntDictIterator it(m_watches); + + for (; it.current(); ++it) + dbus_watch_handle(it.current()->watch, DBUS_WATCH_WRITABLE); + + /*Watch* ww = m_watches.find(fd); + + dbus_watch_handle(ww->watch, DBUS_WATCH_WRITABLE);*/ + + //if (m_connection) + //{ + //dbus_connection_flush(m_connection); + + //emit readReady(); + //} +} + +void Integrator::slotTimeout( DBusTimeout *timeout ) +{ + qDebug("Integrator::slotTimeout"); + dbus_timeout_handle( timeout ); +} + +void Integrator::addWatch( DBusWatch *watch ) +{ + qDebug("Integrator::addWatch invoked"); + + if ( !dbus_watch_get_enabled( watch ) ) + { + return; + } + + int flags = dbus_watch_get_flags(watch); + int fd = dbus_watch_get_fd(watch); + + Watch* ww = m_watches.find(fd); + + if (ww && (dbus_watch_get_flags(ww->watch) == flags)) + { + qDebug("API: not adding duplicate watch"); + return; + } + + Watch *qtwatch = new Watch; + qtwatch->watch = watch; + + //qDebug("flags == %d fd == %d", flags, fd); + + if ( flags & DBUS_WATCH_READABLE ) + { + qtwatch->readSocket = new QSocketNotifier( fd, QSocketNotifier::Read, this); + QObject::connect( qtwatch->readSocket, SIGNAL(activated(int)), this, SLOT(slotRead(int)) ); + } + + if (flags & DBUS_WATCH_WRITABLE) + { + qtwatch->writeSocket = new QSocketNotifier( fd, QSocketNotifier::Write, this); + QObject::connect( qtwatch->writeSocket, SIGNAL(activated(int)), this, SLOT(slotWrite(int)) ); + } + + m_watches.insert( fd, qtwatch ); +} + +void Integrator::removeWatch( DBusWatch *watch ) +{ + int key = dbus_watch_get_fd( watch ); + + Watch *qtwatch = m_watches.take( key ); + + if ( qtwatch ) + { + delete qtwatch->readSocket; + qtwatch->readSocket = 0; + delete qtwatch->writeSocket; + qtwatch->writeSocket = 0; + delete qtwatch; + } +} + +void Integrator::addTimeout( DBusTimeout *timeout ) +{ + qDebug("add timeout"); + Timeout *mt = new Timeout( this, timeout ); + m_timeouts.insert( timeout, mt ); + connect( mt, SIGNAL(timeout(DBusTimeout*)), + SLOT(slotTimeout(DBusTimeout*)) ); + mt->start(); +} + +void Integrator::removeTimeout( DBusTimeout *timeout ) +{ + m_timeouts.remove( timeout ); +} + +void Integrator::handleConnection( DBusConnection *c ) +{ + //dbus_connection_ref(c); + //int fd; + //dbus_connection_get_unix_fd(c, &fd); + + //qDebug("Integrator::handleConnection() invoked, fd is %d", fd); + //qDebug("Connection base name: %s", dbus_bus_get_base_service(c)); + + dbus_connection_ref(c); + + //dbus_bus_set_base_service(c, "/com/Skype/API"); + + Connection *con = new Connection( c, this ); + + dbus_connection_set_wakeup_main_function(c, &dbusWakeupMain, con, 0); + //dbus_connection_set_dispatch_status_function(c, dbusDispatchStatusChanged, this, 0); + + + emit newConnection( con ); +} + +}//end namespace Internal +}//end namespace DBusQt + +#include "integrator.moc" diff --git a/plugins/skype/libskype/skypedbus/integrator.h b/plugins/skype/libskype/skypedbus/integrator.h new file mode 100644 index 0000000..475b42f --- /dev/null +++ b/plugins/skype/libskype/skypedbus/integrator.h @@ -0,0 +1,94 @@ +// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; -*- +/* integrator.h: integrates D-BUS into Qt event loop + * + * Copyright (C) 2003 Zack Rusin + * + * Licensed under the Academic Free License version 2.1 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#ifndef DBUS_QT_INTEGRATOR_H +#define DBUS_QT_INTEGRATOR_H + +#include + +#include +#include + +#include + +class QTimer; + +namespace DBusQt +{ + class Connection; + + namespace Internal + { + struct Watch; + + class Timeout : public QObject + { + Q_OBJECT + public: + Timeout( QObject *parent, DBusTimeout *t ); + public: + void start(); + signals: + void timeout( DBusTimeout* ); + protected slots: + void slotTimeout(); + private: + QTimer *m_timer; + DBusTimeout *m_timeout; + }; + + class Integrator : public QObject + { + Q_OBJECT + public: + Integrator( DBusConnection *connection, QObject *parent, bool tmp = FALSE ); + Integrator( DBusServer *server, QObject *parent ); + virtual ~Integrator(); + + signals: + void readReady(); + void newConnection( DBusQt::Connection* ); + + protected slots: + void slotRead( int ); + void slotWrite( int ); + void slotTimeout( DBusTimeout *timeout ); + + public: + void addWatch( DBusWatch* ); + void removeWatch( DBusWatch* ); + + void addTimeout( DBusTimeout* ); + void removeTimeout( DBusTimeout* ); + + void handleConnection( DBusConnection* ); + + QIntDict m_watches; + private: + QPtrDict m_timeouts; + DBusConnection *m_connection; + DBusServer *m_server; + }; + } +} + +#endif diff --git a/plugins/skype/libskype/skypedbus/message.cpp b/plugins/skype/libskype/skypedbus/message.cpp new file mode 100644 index 0000000..a7cf5ad --- /dev/null +++ b/plugins/skype/libskype/skypedbus/message.cpp @@ -0,0 +1,738 @@ + +/* -*- mode: C++; c-file-style: "gnu" -*- */ + +/* message.cpp: Qt wrapper for DBusMessage + * + * Copyright (C) 2003 Zack Rusin + * + * Licensed under the Academic Free License version 2.0 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#define DBUS_API_SUBJECT_TO_CHANGE + +#include "message.h" + +#include + +#include + +namespace DBusQt +{ + + struct Message::iterator::IteratorData + { + DBusMessageIter *iter; + QVariant var; + bool end; + DBusMessage *mesg; + }; + +/** + * Iterator. + */ + Message::iterator::iterator( ) + { + d = new IteratorData; + d->iter = 0; + d->end = true; + } + +/** + * Constructs iterator for the message. + * @param msg message whose fields we want to iterate + */ + Message::iterator::iterator( DBusMessage * msg ) + { + d = new IteratorData; + d->mesg = msg; + d->iter = + static_cast < + DBusMessageIter * >( malloc( sizeof( DBusMessageIter ) ) ); + dbus_message_iter_init( d->mesg, d->iter ); + if ( !d->iter ) + { + qDebug( "No iterator??" ); + } + fillVar( ); + d->end = false; + } + +/** + * Copy constructor for the iterator. + * @param itr iterator + */ + Message::iterator::iterator( const iterator & itr ) + { + d = new IteratorData; + d->iter = itr.d->iter; + d->var = itr.d->var; + d->end = itr.d->end; + } + +/** + * Destructor. + */ + Message::iterator::~iterator( ) + { + free( d->iter ); + delete d; + + d = 0; + } + +/** + * Creates an iterator equal to the @p itr iterator + * @param itr other iterator + * @return + */ + Message::iterator & Message::iterator::operator=( const iterator & itr ) + { + IteratorData *tmp = new IteratorData; + + tmp->iter = itr.d->iter; + tmp->var = itr.d->var; + tmp->end = itr.d->end; + delete d; + + d = tmp; + return *this; + } + +/** + * Returns the constant QVariant held by the iterator. + * @return the constant reference to QVariant held by this iterator + */ + const QVariant & Message::iterator::operator*( ) const + { + return d->var; + } + +/** + * Returns the QVariant held by the iterator. + * @return reference to QVariant held by this iterator + */ + QVariant & Message::iterator::operator*( ) + { + return d->var; + } + +/** + * Moves to the next field and return a reference to itself after + * incrementing. + * @return reference to self after incrementing + */ + Message::iterator & Message::iterator::operator++( ) + { + if ( d->end ) + return *this; + + if ( dbus_message_iter_next( d->iter ) ) + { + fillVar( ); + } + else + { + d->end = true; + d->var = QVariant( ); + } + return *this; + } + +/** + * Moves to the next field and returns self before incrementing. + * @return self before incrementing + */ + Message::iterator Message::iterator::operator++( int ) + { + iterator itr( *this ); + + operator++( ); + return itr; + } + +/** + * Compares this iterator to @p it iterator. + * @param it the iterator to which we're comparing this one to + * @return true if they're equal, false otherwise + */ + bool Message::iterator::operator==( const iterator & it ) + { + if ( d->end == it.d->end ) + { + if ( d->end == true ) + { + return true; + } + else + { + return d->var == it.d->var; + } + } + else + return false; + } + +/** + * Compares two iterators. + * @param it The other iterator. + * @return true if two iterators are not equal, false + * otherwise + */ + bool Message::iterator::operator!=( const iterator & it ) + { + return !operator==( it ); + } + +#ifdef OLD_DBUS + QVariant Message::iterator::marshallBaseType( DBusMessageIter * i ) + { + QVariant ret; + + switch ( dbus_message_iter_get_arg_type( i ) ) + { + case DBUS_TYPE_INT32: + ret = QVariant( dbus_message_iter_get_int32( i ) ); + break; + case DBUS_TYPE_UINT32: + ret = QVariant( dbus_message_iter_get_uint32( i ) ); + break; + case DBUS_TYPE_DOUBLE: + ret = QVariant( dbus_message_iter_get_double( i ) ); + break; + case DBUS_TYPE_BOOLEAN: + ret = QVariant( dbus_message_iter_get_boolean( i ) ); + break; + case DBUS_TYPE_STRING: + { + char *str = dbus_message_iter_get_string( i ); + + ret = QVariant( QString::fromUtf8( str ) ); + dbus_free( str ); + } + break; + default: + ret = QVariant( ); + break; + } + + return ret; + } +#else + + QVariant Message::iterator::marshallBaseType( DBusMessageIter* i ) { + QVariant ret; + switch (dbus_message_iter_get_arg_type(i)) { + case DBUS_TYPE_INT32: + { + dbus_int32_t v; + dbus_message_iter_get_basic (i, &v); + ret = QVariant( v ); + } + break; + case DBUS_TYPE_UINT32: + { + dbus_uint32_t v; + dbus_message_iter_get_basic (i, &v); + ret = QVariant( v ); + } + break; + case DBUS_TYPE_DOUBLE: + { + double v; + dbus_message_iter_get_basic (i, &v); + ret = QVariant( v ); + } + break; + case DBUS_TYPE_STRING: + { + const char *v; + dbus_message_iter_get_basic (i, &v); + ret = QVariant( v ); + } + break; + default: + ret = QVariant(); + break; + } + return ret; + } +#endif + +/** + * Fills QVariant based on what current DBusMessageIter helds. + */ +#ifdef OLD_DBUS + void Message::iterator::fillVar( ) + { + switch ( dbus_message_iter_get_arg_type( d->iter ) ) + { + case DBUS_TYPE_INT32: + case DBUS_TYPE_UINT32: + case DBUS_TYPE_DOUBLE: + case DBUS_TYPE_STRING: + case DBUS_TYPE_BOOLEAN: + qDebug( "Message::iterator::fillVar, type == DBUS_TYPE_STRING" ); + d->var = marshallBaseType( d->iter ); + break; + case DBUS_TYPE_ARRAY: + { + switch ( dbus_message_iter_get_array_type( d->iter ) ) + { + case DBUS_TYPE_STRING: + { + QStringList tempList; + int count; + char **charArray; + + dbus_message_iter_get_string_array( d->iter, + &charArray, &count ); + + for ( int i = 0; i < count; i++ ) + { + tempList.append( QString( charArray[i] ) ); + } + + d->var = QVariant( tempList ); + dbus_free( charArray ); + break; + } + default: + qDebug( "Array of type not implemented" ); + d->var = QVariant( ); + break; + } + break; + } + case DBUS_TYPE_DICT: + { + qDebug( "Got a hash!" ); + QMap < QString, QVariant > tempMap; + DBusMessageIter dictIter; + + dbus_message_iter_init_dict_iterator( d->iter, &dictIter ); + do + { + char *key = dbus_message_iter_get_dict_key( &dictIter ); + + tempMap[key] = marshallBaseType( &dictIter ); + dbus_free( key ); + dbus_message_iter_next( &dictIter ); + } + while ( dbus_message_iter_has_next( &dictIter ) ); + d->var = QVariant( tempMap ); + break; + qDebug( "Hash/Dict type not implemented" ); + d->var = QVariant( ); + break; + } + default: + qDebug( "not implemented" ); + d->var = QVariant( ); + break; + } + } +#else + + void Message::iterator::fillVar() { + switch ( dbus_message_iter_get_arg_type( d->iter ) ) { + case DBUS_TYPE_INT32: + case DBUS_TYPE_UINT32: + case DBUS_TYPE_DOUBLE: + case DBUS_TYPE_STRING: + d->var = marshallBaseType( d->iter ); + break; + case DBUS_TYPE_ARRAY: { + switch ( dbus_message_iter_get_element_type( d->iter ) ) { + case DBUS_TYPE_STRING: { + QStringList tempList; + DBusMessageIter sub; + dbus_message_iter_recurse (d->iter, &sub); + while (dbus_message_iter_get_arg_type (&sub) != DBUS_TYPE_INVALID) + { + const char *v; + dbus_message_iter_get_basic (&sub, &v); + tempList.append( QString( v ) ); + dbus_message_iter_next (&sub); + } + d->var = QVariant( tempList ); + break; + } + default: + qDebug( "Array of type not implemented" ); + d->var = QVariant(); + break; + } + break; + } +#if 0 + /* DICT is gone for now, but expected to be reintroduced, or else + * reintroduced as a flag on the introspection data that can + * apply to array of struct of two fields + */ + case DBUS_TYPE_DICT: { + qDebug( "Got a hash!" ); + QMap tempMap; + DBusMessageIter dictIter; + dbus_message_iter_init_dict_iterator( d->iter, &dictIter ); + do { + char *key = dbus_message_iter_get_dict_key( &dictIter ); + tempMap[key] = marshallBaseType( &dictIter ); + dbus_free( key ); + dbus_message_iter_next( &dictIter ); + } while( dbus_message_iter_has_next( &dictIter ) ); + d->var = QVariant( tempMap ); + break; + qDebug( "Hash/Dict type not implemented" ); + d->var = QVariant(); + break; + } +#endif + default: + qDebug( "not implemented" ); + d->var = QVariant(); + break; + } + } +#endif + +/** + * Returns a QVariant help by this iterator. + * @return QVariant held by this iterator + */ + QVariant Message::iterator::var( ) const + { + return d->var; + } + + struct Message::Private + { + DBusMessage *msg; + }; + + Message::Message( DBusMessage * m ) + { + d = new Private; + d->msg = m; + } + +/** + * + */ + Message::Message( int messageType ) + { + d = new Private; + d->msg = dbus_message_new( messageType ); + } + +/** + * Constructs a new Message with the given service and name. + * @param service service service that the message should be sent to + * @param name name of the message + */ + Message::Message( const QString & service, const QString & path, + const QString & interface, const QString & method ) + { + d = new Private; + d->msg = + dbus_message_new_method_call( service.latin1( ), path.latin1( ), + interface.latin1( ), + method.latin1( ) ); + } + +/** + * Constructs a message that is a reply to some other + * message. + * @param name the name of the message + * @param replayingTo original_message the message which the created + * message is a reply to. + */ + Message::Message( const Message & replayingTo ) + { + d = new Private; + d->msg = dbus_message_new_method_return( replayingTo.d->msg ); + } + + Message::Message( const QString & path, const QString & interface, + const QString & name ) + { + qDebug( "Message::Message" ); + d = new Private; + d->msg = dbus_message_new_signal( path.ascii( ), interface.ascii( ), + name.ascii( ) ); + } + + Message::Message( const Message & replayingTo, const QString & errorName, + const QString & errorMessage ) + { + d = new Private; + d->msg = + dbus_message_new_error( replayingTo.d->msg, errorName.utf8( ), + errorMessage.utf8( ) ); + } + + Message Message::operator=( const Message & other ) + { + //FIXME: ref the other.d->msg instead of copying it? + } + +/** + * Destructs message. + */ + Message::~Message( ) + { + if ( d->msg ) + { + dbus_message_unref( d->msg ); + } + delete d; + + d = 0; + } + + int Message::type( ) const + { + return dbus_message_get_type( d->msg ); + } + + void Message::setAutoActivation( bool aa ) + { +#ifdef OLD_DBUS + dbus_message_set_auto_activation( d->msg, aa ); +#else + dbus_message_set_auto_start(d->msg, aa); +#endif + } + + bool Message::autoActication( ) + { +#ifdef OLD_DBUS + return dbus_message_get_auto_activation( d->msg ); +#else + return dbus_message_get_auto_start(d->msg); +#endif + } + + void Message::setPath( const QString & path ) + { + dbus_message_set_path( d->msg, path.ascii( ) ); + } + + QString Message::path( ) const + { + return dbus_message_get_path( d->msg ); + } + + void Message::setInterface( const QString & iface ) + { + dbus_message_set_interface( d->msg, iface.ascii( ) ); + } + + QString Message::interface( ) const + { + return dbus_message_get_interface( d->msg ); + } + + void Message::setMember( const QString & member ) + { + dbus_message_set_member( d->msg, member.ascii( ) ); + } + + QString Message::member( ) const + { + return dbus_message_get_member( d->msg ); + } + + void Message::setErrorName( const QString & err ) + { + dbus_message_set_error_name( d->msg, err.utf8() ); + } + + QString Message::errorName( ) const + { + return dbus_message_get_error_name( d->msg ); + } + + void Message::setDestination( const QString & dest ) + { + dbus_message_set_destination( d->msg, dest.utf8() ); + } + + QString Message::destination( ) const + { + return dbus_message_get_destination( d->msg ); + } + +/** + * Sets the message sender. + * @param sender the sender + * @return false if unsuccessful + */ + bool Message::setSender( const QString & sender ) + { + return dbus_message_set_sender( d->msg, sender.latin1( ) ); + } + +/** + * Returns sender of this message. + * @return sender + */ + QString Message::sender( ) const + { + return dbus_message_get_sender( d->msg ); + } + + bool Message::expectReply( ) const + { + return !dbus_message_get_no_reply( d->msg ); + } + + QString Message::signature( ) const + { + return dbus_message_get_signature( d->msg ); + } + +/** + * Returns the starting iterator for the fields of this + * message. + * @return starting iterator + */ + Message::iterator Message::begin( ) const + { + return iterator( d->msg ); + } + +/** + * Returns the ending iterator for the fields of this + * message. + * @return ending iterator + */ + Message::iterator Message::end( ) const + { + return iterator( ); + } + +/** + * Returns the field at position @p i + * @param i position of the wanted field + * @return QVariant at position @p i or an empty QVariant + */ + QVariant Message::at( int i ) + { + iterator itr( d->msg ); + + while ( i-- ) + { + if ( itr == end( ) ) + return QVariant( ); //nothing there + ++itr; + } + return *itr; + } + +/** + * The underlying DBusMessage of this class. + * @return DBusMessage pointer. + */ + DBusMessage *Message::message( ) const + { + return d->msg; + } + + Message & Message::operator<<( bool b ) + { +#ifdef OLD_DBUS + dbus_message_append_args( d->msg, DBUS_TYPE_BOOLEAN, b, +#else + const dbus_bool_t right_size_bool = b; + dbus_message_append_args( d->msg, DBUS_TYPE_BOOLEAN, &right_size_bool, +#endif + DBUS_TYPE_INVALID ); + return *this; + } + +#ifdef OLD_DBUS +#define APER +#else +#define APER & +#endif + + Message & Message::operator<<( Q_INT8 byte ) + { + dbus_message_append_args( d->msg, DBUS_TYPE_BYTE, APER byte, + DBUS_TYPE_INVALID ); + return *this; + } + + Message & Message::operator<<( Q_INT32 num ) + { + dbus_message_append_args( d->msg, DBUS_TYPE_INT32, APER num, + DBUS_TYPE_INVALID ); + return *this; + } + + Message & Message::operator<<( Q_UINT32 num ) + { + dbus_message_append_args( d->msg, DBUS_TYPE_UINT32, APER num, + DBUS_TYPE_INVALID ); + return *this; + } + + Message & Message::operator<<( Q_INT64 num ) + { + dbus_message_append_args( d->msg, DBUS_TYPE_INT64, APER num, + DBUS_TYPE_INVALID ); + return *this; + } + + Message & Message::operator<<( Q_UINT64 num ) + { + dbus_message_append_args( d->msg, DBUS_TYPE_UINT64, APER num, + DBUS_TYPE_INVALID ); + return *this; + } + + Message & Message::operator<<( double num ) + { + dbus_message_append_args( d->msg, DBUS_TYPE_DOUBLE, APER num, + DBUS_TYPE_INVALID ); + return *this; + } + + Message & Message::operator<<( const QString & str ) + { +#ifdef OLD_DBUS + dbus_message_append_args( d->msg, + DBUS_TYPE_STRING, + ( const char * ) ( str.utf8( ) ), 0 ); +#else + const char *u = str.utf8(); + dbus_message_append_args( d->msg, + DBUS_TYPE_STRING, + u, 0 ); +#endif + return *this; + } + + Message & Message::operator<<( const QVariant & custom ) + { + //FIXME: imeplement + return *this; + } + +} + diff --git a/plugins/skype/libskype/skypedbus/message.h b/plugins/skype/libskype/skypedbus/message.h new file mode 100644 index 0000000..5134ccd --- /dev/null +++ b/plugins/skype/libskype/skypedbus/message.h @@ -0,0 +1,136 @@ +/* -*- mode: C++; c-file-style: "gnu" -*- */ +/* message.h: Qt wrapper for DBusMessage + * + * Copyright (C) 2003 Zack Rusin + * + * Licensed under the Academic Free License version 2.1 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#ifndef DBUS_QT_MESSAGE_H +#define DBUS_QT_MESSAGE_H + +#include +#include +#include + +#include + +namespace DBusQt { + + class Message + { + public: + class iterator { + public: + iterator(); + iterator( const iterator& ); + iterator( DBusMessage* msg ); + ~iterator(); + + iterator& operator=( const iterator& ); + const QVariant& operator*() const; + QVariant& operator*(); + iterator& operator++(); + iterator operator++(int); + bool operator==( const iterator& it ); + bool operator!=( const iterator& it ); + + QVariant var() const; + protected: + QVariant marshallBaseType( DBusMessageIter* i ); + void fillVar(); + struct IteratorData; + IteratorData *d; + }; + + Message( int messageType ); + Message( DBusMessage * );//hide this one from the public implementation + Message( const QString& service, const QString& path, + const QString& interface, const QString& method ); + Message( const Message& replayingTo ); + Message( const QString& path, const QString& interface, + const QString& name ); + Message( const Message& replayingTo, const QString& errorName, + const QString& errorMessage ); + + Message operator=( const Message& other ); + + virtual ~Message(); + + int type() const; + + void setPath( const QString& ); + QString path() const; + + void setInterface( const QString& ); + QString interface() const; + + void setMember( const QString& ); + QString member() const; + + void setErrorName( const QString& ); + QString errorName() const; + + void setDestination( const QString& ); + QString destination() const; + + bool setSender( const QString& sender ); + QString sender() const; + + void setAutoActivation(bool aa); + bool autoActication(); + + bool expectReply() const; + + QString signature() const; + + iterator begin() const; + iterator end() const; + + QVariant at( int i ); + + + public: + Message& operator<<( bool ); + Message& operator<<( Q_INT8 ); + Message& operator<<( Q_INT32 ); + Message& operator<<( Q_UINT32 ); + Message& operator<<( Q_INT64 ); + Message& operator<<( Q_UINT64 ); + Message& operator<<( double ); + Message& operator<<( const QString& ); + Message& operator<<( const QVariant& ); + //Message& operator<<(); + //Message& operator<<(); + //Message& operator<<(); + //Message& operator<<(); + //Message& operator<<(); + //Message& operator<<(); + //Message& operator<<(); + + protected: + friend class Connection; + DBusMessage* message() const; + + private: + struct Private; + Private *d; + }; + +} + +#endif diff --git a/plugins/skype/libskype/skypedbus/skypeconnection.cpp b/plugins/skype/libskype/skypedbus/skypeconnection.cpp new file mode 100644 index 0000000..5014494 --- /dev/null +++ b/plugins/skype/libskype/skypedbus/skypeconnection.cpp @@ -0,0 +1,391 @@ +// +// C++ Implementation: skypeconnection +// +// Description: +// +// +// Author: SIM Developers , (C) 2005 +// +// Copyright: See COPYING file that comes with this distribution +// +// +#define DBUS_API_SUBJECT_TO_CHANGE +#include "skypeconnection.h" + +///@todo When QT 4 is used, the signal-slot wrapper will be better, replace it +#include "connection.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +typedef enum { + cfConnected, + cfNotConnected, + cfNameSent, + cfProtocolSent, + cfWaitingStart +} connFase; + +class SkypeConnectionPrivate { + public: + ///Are we connected/connecting? + connFase fase; + ///How will we be known to skype? + QString appName; + ///What is the protocol version used (wanted if not connected yet) + int protocolVer; + ///The connection to DBus + DBusQt::Connection *conn; + ///This timer will keep trying until Skype starts + QTimer *startTimer; + ///How much time rest? (until I say starting skype did not work) + int timeRemaining; + ///Wait a while before we conect to just-started skype? + int waitBeforeConnect; +}; + +SkypeConnection::SkypeConnection() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + d = new SkypeConnectionPrivate;//create the d pointer + d->fase = cfNotConnected;//not connected yet + d->conn = 0L;//No connetion created + d->startTimer = 0L; + + connect(this, SIGNAL(received(const QString&)), this, SLOT(parseMessage(const QString&)));//look into all messages +} + +SkypeConnection::~SkypeConnection() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + disconnectSkype();//disconnect before you leave + delete d;//Remove the D pointer +} + +void SkypeConnection::startLogOn() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + if (d->startTimer) { + d->startTimer->deleteLater(); + d->startTimer = 0L; + } + + DBusQt::Message ping("com.Skype.API", "/com/Skype", "com.Skype.API", "Ping");//create a ping message + ping.setAutoActivation(true); + DBusQt::Message reply = d->conn->sendWithReplyAndBlock(ping);//send it there + + DBusQt::Message::iterator it = reply.begin(); + if (it == reply.end()) { + emit error(i18n("Could not ping Skype")); + disconnectSkype(crLost); + emit connectionDone(seNoSkype, 0); + return; + } + + d->fase = cfNameSent; + send(QString("NAME %1").arg(d->appName)); +} + +void SkypeConnection::gotMessage(const DBusQt::Message &message) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + if (message.member() == "Ping") {//Skype wants to know if we are alive + kdDebug(14311) << "Skype sent us ping, responding" << endl; + DBusQt::Message reply(message);//Create the reply + reply << getpid();//respond with our PID + d->conn->send(reply);//send it + d->conn->flush(); + return;//It is enough + } + + if (message.member() == "Notify") {//Something importatnt? + for (DBusQt::Message::iterator it = message.begin(); it != message.end(); ++it) {//run trough the whole message + emit received((*it).toString());//Take out the string and use it + } + + if (message.expectReply()) { + kdDebug(14311) << "Message expects reply, sending a dummy one" << endl; + DBusQt::Message *reply = new DBusQt::Message(message);//generate a reply for that message + (*reply) << QString("ERROR 2");//write there seme error + d->conn->send(*reply);//send the message + d->conn->flush(); + } + } +} + +void SkypeConnection::parseMessage(const QString &message) { + kdDebug(14311) << k_funcinfo << QString("(message: %1)").arg(message) << endl;//some debug info + + switch (d->fase) { + case cfNameSent: { + + if (message == "OK") {//Accepted by skype + d->fase = cfProtocolSent;//Sending the protocol + send(QString("PROTOCOL %1").arg(d->protocolVer));//send the protocol version + } else {//Not accepted by skype + emit error(i18n("Skype did not accept this application"));//say there is an error + emit connectionDone(seAuthorization, 0);//Problem with authorization + disconnectSkype(crLost);//Lost the connection + } + break; + } + case cfProtocolSent: { + if (message.contains("PROTOCOL", false)) {//This one inform us what protocol do we use + bool ok; + int version = message.section(' ', 1, 1).stripWhiteSpace().toInt(&ok, 0);//take out the protocol version and make it int + if (!ok) { + emit error(i18n("Skype API syntax error")); + emit connectionDone(seUnknown, 0); + disconnectSkype(crLost);//lost the connection + return;//I have enough + } + d->protocolVer = version;//this will be the used version of protocol + d->fase = cfConnected; + emit connectionDone(seSuccess, version);//tell him that we are connected at last + } else {//the API is not ready yet, try later + emit error(i18n("Skype API not ready yet, wait a bit longer")); + emit connectionDone(seUnknown, 0); + disconnectSkype(crLost); + return; + } + break;//Other messages are ignored, waiting for the protocol response + } + } +} + +void SkypeConnection::connectSkype(const QString &start, const QString &appName, int protocolVer, int bus, bool startDBus, int launchTimeout, int waitBeforeConnect) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + if (d->fase != cfNotConnected) + return; + + d->appName = appName; + d->protocolVer = protocolVer; + + if (bus == 0) + d->conn = new DBusQt::Connection(DBUS_BUS_SESSION, this); + else + d->conn = new DBusQt::Connection(DBUS_BUS_SYSTEM, this); + + if ((!d->conn) || (!d->conn->isConnected())) { + if ((bus == 0) && (startDBus)) { + KProcess bus_launch; + bus_launch << "dbus_launch"; + bus_launch << "--exit-with-session"; + connect(&bus_launch, SIGNAL(receivedStdout(KProcess *, char *, int)), this, SLOT(setEnv(KProcess *, char*, int ))); + bus_launch.start(KProcess::Block, KProcess::Stdout); + connectSkype(start, appName, protocolVer, bus, false, launchTimeout, waitBeforeConnect);//try it once again, but if the dbus start did not work, it won't work that time ether, so do not cycle + return; + } + emit error(i18n("Could not connect to DBus")); + disconnectSkype(crLost); + emit connectionDone(seNoDBus, 0); + return; + } + + d->conn->registerObjectPath("org.kde.SIM.skype", "/com/Skype/Client"); + + connect(d->conn, SIGNAL(messageArrived(const DBusQt::Message&)), this, SLOT(gotMessage(const DBusQt::Message &))); + + { + DBusQt::Message m("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "ServiceExists"); + m << QString("com.Skype.API"); + m.setAutoActivation(true); + + DBusQt::Message reply = d->conn->sendWithReplyAndBlock(m); + + DBusQt::Message::iterator it = reply.begin(); + if ((it == reply.end()) || ((*it).toBool() != true)) { + if (!start.isEmpty()) {//try starting Skype by the given command + KProcess sk; + QStringList args = QStringList::split(' ', start); + for (QStringList::iterator i = args.begin(); i != args.end(); ++i) { + sk << (*i); + } + if (!sk.start(KProcess::DontCare, KProcess::NoCommunication)) { + emit error(i18n("Could not launch Skype")); + disconnectSkype(crLost); + emit connectionDone(seNoSkype, 0); + return; + } + d->fase = cfWaitingStart; + d->startTimer = new QTimer(); + connect(d->startTimer, SIGNAL(timeout()), this, SLOT(tryConnect())); + d->startTimer->start(1000); + d->timeRemaining = launchTimeout; + d->waitBeforeConnect = waitBeforeConnect; + return; + } + emit error(i18n("Could not find Skype")); + disconnectSkype(crLost); + emit connectionDone(seNoSkype, 0); + return; + } + } + + startLogOn(); +} + +void SkypeConnection::disconnectSkype(skypeCloseReason reason) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + if (!d->conn) //nothing to disconnect + return; + d->conn->close();//close the connection + delete d->conn;//destroy it + d->conn = 0L;//andmark it as empty + if (d->startTimer) { + d->startTimer->stop(); + d->startTimer->deleteLater(); + d->startTimer = 0L; + } + + d->fase = cfNotConnected;//No longer connected + emit connectionDone(seCanceled, 0); + emit connectionClosed(reason);//we disconnect +} + +void SkypeConnection::send(const QString &message) { + kdDebug(14311) << k_funcinfo << QString("(message: %1)").arg(message) << endl;//some debug info + + if (d->fase == cfNotConnected) + return;//not connected, posibly because of earlier error, do not show it again + + DBusQt::Message m("com.Skype.API", "/com/Skype", "com.Skype.API", "Invoke"); + m << message; + m.setAutoActivation(true); + DBusQt::Message reply = d->conn->sendWithReplyAndBlock(m); + + d->conn->flush(); + if (d->conn->error()) {//There was some error + emit error(i18n("Error while sending a message to skype (%1)").arg(d->conn->getError()));//say there was the error + if (d->fase != cfConnected) + emit connectionDone(seUnknown, 0);//Connection attempt finished with error + disconnectSkype(crLost);//lost the connection + + return;//this is enough, no more errors please.. + } + + for (DBusQt::Message::iterator it = reply.begin(); it != reply.end(); ++it) { + emit received((*it).toString());//use the message + } +// d->conn->send(m); +} + +bool SkypeConnection::connected() const { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + return d->fase == cfConnected; +} + +int SkypeConnection::protocolVer() const { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + return d->protocolVer;//just give him the protocol version +} + +SkypeConnection &SkypeConnection::operator <<(const QString &message) { + send(message);//just send it + return *this;//and return yourself +} + +QString SkypeConnection::operator %(const QString &message) { + kdDebug(14311) << k_funcinfo << "message: " << message << endl;//some debug info + + if (d->fase == cfNotConnected) + return "";//not connected, posibly because of earlier error, do not show it again + + DBusQt::Message m("com.Skype.API", "/com/Skype", "com.Skype.API", "Invoke"); + m << message; + m.setAutoActivation(true); + DBusQt::Message reply = d->conn->sendWithReplyAndBlock(m); + + d->conn->flush(); + if (d->conn->error()) {//There was some error + emit error(i18n("Error while sending a message to skype (%1)").arg(d->conn->getError()));//say there was the error + if (d->fase != cfConnected) + emit connectionDone(seUnknown, 0);//Connection attempt finished with error + disconnectSkype(crLost);//lost the connection + return "";//this is enough, no more errors please.. + } + + for (DBusQt::Message::iterator it = reply.begin(); it != reply.end(); ++it) { + kdDebug(14311) << (*it).toString() << endl;//show what we have received + return (*it).toString();//ok, just return it + } + + return "";//the skype did not respond, which is unusual but what can I do.. +} + +void SkypeConnection::setEnv(KProcess *, char *buffer, int length) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + char *myBuff = new char[length + 1]; + myBuff[length] = '\0'; + memcpy(myBuff, buffer, length);//copy the output from there + + char *next; + + for (char *c = myBuff; *c; c++) if (*c == '=') { + *c = '\0';//Split the string + next = c + 1;//This is the next one + break; + } + + if (strcmp(myBuff, "DBUS_SESSION_BUS_ADDRESS") != 0) { + delete[] myBuff; + return;//something I'm not interested in + } + + //strip the apostrophes or quotes given by the dbus-launch command + if ((next[0] == '\'') || (next[0] == '"')) ++next; + int len = strlen(next); + if ((next[len - 1] == '\'') || (next[len - 1] == '"')) next[len - 1] = '\0'; + + setenv(myBuff, next, false);//and set the environment variable + + delete[] myBuff; +} + +void SkypeConnection::tryConnect() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + { + DBusQt::Message m("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "ServiceExists"); + m << QString("com.Skype.API"); + m.setAutoActivation(true); + + DBusQt::Message reply = d->conn->sendWithReplyAndBlock(m); + + DBusQt::Message::iterator it = reply.begin(); + if ((it == reply.end()) || ((*it).toBool() != true)) { + if (--d->timeRemaining == 0) { + d->startTimer->stop(); + d->startTimer->deleteLater(); + d->startTimer = 0L; + emit error(i18n("Could not find Skype")); + disconnectSkype(crLost); + emit connectionDone(seNoSkype, 0); + return; + } + return;//Maybe next time + } + } + + d->startTimer->stop(); + d->startTimer->deleteLater(); + d->startTimer = 0L; + if (d->waitBeforeConnect) { + QTimer::singleShot(1000 * d->waitBeforeConnect, this, SLOT(startLogOn())); + //Skype does not like being bothered right after it's start, give it a while to breathe + } else + startLogOn();//OK, it's your choise +} + +#include "skypeconnection.moc" diff --git a/plugins/skype/libskype/skypedbus/skypeconnection.h b/plugins/skype/libskype/skypedbus/skypeconnection.h new file mode 100644 index 0000000..ff4c9e8 --- /dev/null +++ b/plugins/skype/libskype/skypedbus/skypeconnection.h @@ -0,0 +1,171 @@ +// +// C++ Interface: skypeconnection +// +// Description: +// +// +// Author: SIM Developers , (C) 2005 +// +// Copyright: See COPYING file that comes with this distribution +// +// +#ifndef SKYPECONNECTION_H +#define SKYPECONNECTION_H + +#include + +typedef enum { + ///The connection was successful + seSuccess = 0, + ///No runnign DBUS found + seNoDBus, + ///No running skype found and launching disabled or did not worked + seNoSkype, + ///User did not accept this app + seAuthorization, + ///Some other error + seUnknown, + ///It was canceled (by disconnectSkype) + seCanceled +} skypeConnectionError; + +///This describes why was the connection closed +typedef enum { + ///It was closed by this application + crLocalClosed, + ///It was closed by skype (reserverd for future versions of protocol, does not work yet) + crRemoteClosed, + ///The connection was lost, skype does not respond for the ping command or messages can not be sent + crLost, +} skypeCloseReason; + +class SkypeConnectionPrivate; +namespace DBusQt { + class Message; +}; +class KProcess; + +/** + * This class is classs wrapping DBUS so it can be used easilly to connect to skype, disconnect send and receive messages from it. + * @author SIM Developers +*/ +class SkypeConnection : public QObject +{ + Q_OBJECT + private: + ///The D-pointer for internal things + SkypeConnectionPrivate *d; + private slots: + ///This one listens for incoming messages + void gotMessage(const DBusQt::Message &); + ///This one takes care of incoming messages if they have some sence for the connection (protocol, pings and so on) + void parseMessage(const QString &message); + ///Set environment variables set from dbus-launch command (private DBus session) + void setEnv(KProcess *, char *buff, int len); + ///Starts logging into skype + void startLogOn(); + ///Another interval try to connect to just started Skype + void tryConnect(); + public slots: + /** + * Connects to skype + * After connection (both successful or unsuccessful) connectionDone is emitted + * @see connectionDone + * @param start By what command start Skype if it is not running (empty string means nothing is started) + * @param appName tells as what application it should authorise itself (this will user see on the "do you want to allow" dialog box) + * @param protocolVer Maximal protocol version that this app manages + * @param bus 0 - session bus, 1 - system bus + * @param startDbus Start session DBUs if needed (etc. not running and session DBus should be used) + * @param launchTimeout How long max. should wait to tell that launching skype did not work + * @param waitBeforeConnect Do we need to wait a while after skype starts? + */ + void connectSkype(const QString &start, const QString &appName, int protocolVer, int bus, bool startDBus, int launchTimeout, int waitBeforeConnect); + /** + * Disconnects from skype + * @see connectionClosed + */ + void disconnectSkype(skypeCloseReason reason = crLocalClosed); + /** + * Sends a message to skype. You must be connected before ! + * @param message Contains the message to send + */ + void send(const QString &message); + public: + /** + * Constructor. Creates UNCONECTED connection (sounds oddly ?) + */ + SkypeConnection(); + /** + * Destructor + */ + ~SkypeConnection(); + /** + * This enables/disables pings to skype and sets interval of the pings and timeout + * @param enable Enable or not the pings? If this is false, no pings are done and the rest of parameters has no effect + * @param interval Interval in witch pings should be sent, in miliseconds + * @param timeout When the ping should be considered unanwsered? (should be shorter than interval), in miliseconds + */ + void setPing(bool enable, int interval, int timeout); + /** + * @return Are the pings enabled? + */ + bool getPing() const; + /** + * @return What is the interval of pings? (ms) + */ + int getPingInterval() const; + /** + * @return What is the timeout od pings? (ms) + */ + int getPingTimeout() const; + /** + * @return Are we connected to the skype? + */ + bool connected() const; + /** + * @return What is the protocol version? + */ + int protocolVer() const; + /** + * This operator makes it possible to just send messages by writing connection << SomeString << anotherString. They are sent as separate objects; + * @param message What will be sent + */ + SkypeConnection &operator<<(const QString &message); + /** + * This operator sends a message to skype and returns the response from it. Note that this one blocks. + * @param message What should be sent to skype + * @return The response from skype + */ + QString operator%(const QString &message); + signals: + /** + * This signal is emitted when an attempt to connect to skype application is done. It is done in both cases, success or not. + * @param error Indicates error code. seSuccess means there was no error and the connection was successful. + * @param protocolVer Protocol version used by this connection. Is less or equal to the version set in connect + * @see connect + */ + void connectionDone(int error, int protocolVer); + /** + * This signal is emitted when the connection is closed due to error or because it was disconnetcted + * @param reason Describes why it was closed (you can typecast it to skypeCloseReason if you are interested, or just use the numeric values) + */ + void connectionClosed(int reason); + /** + * This slot is emitted when something is coming from skype. + * It contains pongs as well (responses to ping) and if you do not care about them, you should ignore them. + * @param message The message that arrived + */ + void received(const QString &message); + /** + * This is emitted when some error occurs + * @param message Describes the error + */ + void error(const QString &message); + /** + * This is provided for debugging so you can see what you have sent to skype + * @param message The message that was sent to skype + */ + void sent(const QString &message); +}; + +#endif diff --git a/plugins/skype/skypeaccount.cpp b/plugins/skype/skypeaccount.cpp new file mode 100644 index 0000000..7c00a8a --- /dev/null +++ b/plugins/skype/skypeaccount.cpp @@ -0,0 +1,828 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Michal Vaner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +#include "skypeaccount.h" +#include "skypeprotocol.h" +#include "skypecontact.h" +#include "skype.h" +#include "skypecalldialog.h" +#include "skypechatsession.h" +#include "skypeconference.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class SkypeAccountPrivate { + public: + ///The skype protocol pointer + SkypeProtocol *protocol; + ///ID of this account (means my skype name) + QString ID; + ///The skype back-end + Skype skype; + ///The hitchhike mode of incoming messages + bool hitch; + ///The mark read messages mode + bool markRead; + ///Search for unread messages on login? + bool searchForUnread; + ///Do we show call control window? + bool callControl; + ///Metacontact for all users that aren't in the list + SIM::MetaContact notInListUsers; + ///Constructor + SkypeAccountPrivate(SkypeAccount &account) : skype(account) {};//just an empty constructor + ///Automatic close of call window when the call finishes (in seconds, 0 -> disabled) + int callWindowTimeout; + ///Are the pings enabled? + bool pings; + ///What bus are we using, session (0) or system (1)? + int bus; + ///Do we start DBus if needed? + bool startDBus; + ///How long can I keep trying connect to newly started skype, before I give up (seconds) + int launchTimeout; + ///By what command is the skype started? + QString skypeCommand; + ///What is my name, by the way? + QString myName; + ///Do we wait before connecting? + int waitBeforeConnect; + ///List of chat all chat sessions + QDict sessions; + ///Last used chat session + SkypeChatSession *lastSession; + ///List of the conference calls + QDict conferences; + ///List of existing calls + QDict calls; + ///Shall chat window leave the chat whenit is closed + bool leaveOnExit; + ///Executed before making the call + QString startCallCommand; + ///Executed after finished the call + QString endCallCommand; + ///Wait for the start call command to finitsh? + bool waitForStartCallCommand; + ///Execute the end call command only if no other calls exists? + bool endCallCommandOnlyLats; + ///How many calls are opened now? + int callCount; + ///Command executed on incoming call + QString incommingCommand; +}; + +SkypeAccount::SkypeAccount(SkypeProtocol *protocol) : SIM::Account(protocol, "Skype", (char *)0) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + //keep track of what accounts the protocol has + protocol->registerAccount(this); + + //the d pointer + d = new SkypeAccountPrivate(*this); + d->calls.setAutoDelete(false); + d->conferences.setAutoDelete(false); + //remember the protocol, it will be needed + d->protocol = protocol; + + //load the properties + KConfigGroup *config = configGroup(); + author = config->readEntry("Authorization");//get the name how to authorize myself + launchType = config->readNumEntry("Launch");//launch the skype? + setScanForUnread(config->readBoolEntry("ScanForUnread")); + setCallControl(config->readBoolEntry("CallControl")); + setPings(config->readBoolEntry("Pings", true)); + setBus(config->readNumEntry("Bus", 1)); + //setStartDBus(config->readBoolEntry("StartDBus", false)); + ///@todo Once Dbus launching works, remove this v and uncomment this ^ + setStartDBus(false); + setLaunchTimeout(config->readNumEntry("LaunchTimeout", 30)); + d->myName = config->readEntry("MyselfName", "Skype"); + setSkypeCommand(config->readEntry("SkypeCommand", "artsdsp skype --use-session-dbus")); + setWaitBeforeConnect(config->readNumEntry("WaitBeforeConnect", 10)); + setLeaveOnExit(config->readBoolEntry("LeaveOnExit", true)); + setStartCallCommand(config->readEntry("StartCallCommand", "")); + setEndCallCommand(config->readEntry("EndCallCommand", "")); + setWaitForStartCallCommand(config->readBoolEntry("WaitForStartCallCommand", false)); + setEndCallCommandOnlyForLast(config->readBoolEntry("EndCallCommandOnlyLast", false)); + setIncomingCommand(config->readEntry("IncomingCall", "")); + + //create myself contact + SkypeContact *_myself = new SkypeContact(this, "Skype", SIM::ContactList::self()->myself(), false); + setMyself(_myself); + //and set default online status (means offline) + myself()->setOnlineStatus(protocol->Offline); + + //Now, connect the signals + QObject::connect(&d->skype, SIGNAL(wentOnline()), this, SLOT(wentOnline())); + QObject::connect(&d->skype, SIGNAL(wentOffline()), this, SLOT(wentOffline())); + QObject::connect(&d->skype, SIGNAL(wentAway()), this, SLOT(wentAway())); + QObject::connect(&d->skype, SIGNAL(wentNotAvailable()), this, SLOT(wentNotAvailable())); + QObject::connect(&d->skype, SIGNAL(wentDND()), this, SLOT(wentDND())); + QObject::connect(&d->skype, SIGNAL(wentInvisible()), this, SLOT(wentInvisible())); + QObject::connect(&d->skype, SIGNAL(wentSkypeMe()), this, SLOT(wentSkypeMe())); + QObject::connect(&d->skype, SIGNAL(statusConnecting()), this, SLOT(statusConnecting())); + QObject::connect(&d->skype, SIGNAL(newUser(const QString&)), this, SLOT(newUser(const QString&))); + QObject::connect(&d->skype, SIGNAL(contactInfo(const QString&, const QString& )), this, SLOT(updateContactInfo(const QString&, const QString& ))); + QObject::connect(&d->skype, SIGNAL(receivedIM(const QString&, const QString&, const QString& )), this, SLOT(receivedIm(const QString&, const QString&, const QString& ))); + QObject::connect(&d->skype, SIGNAL(gotMessageId(const QString& )), this, SLOT(gotMessageId(const QString& )));//every time some ID is known inform the contacts + QObject::connect(&d->skype, SIGNAL(newCall(const QString&, const QString&)), this, SLOT(newCall(const QString&, const QString&))); + QObject::connect(&d->skype, SIGNAL(setMyselfName(const QString&)), this, SLOT(setMyselfName(const QString& ))); + QObject::connect(&d->skype, SIGNAL(receivedMultiIM(const QString&, const QString&, const QString&, const QString& )), this, SLOT(receiveMultiIm(const QString&, const QString&, const QString&, const QString& ))); + QObject::connect(&d->skype, SIGNAL(outgoingMessage(const QString&, const QString&)), this, SLOT(sentMessage(const QString&, const QString& ))); + QObject::connect(&d->skype, SIGNAL(groupCall(const QString&, const QString& )), this, SLOT(groupCall(const QString&, const QString& ))); + + //set values for the connection (should be updated if changed) + d->skype.setValues(launchType, author); + setHitchHike(config->readBoolEntry("Hitch", true)); + setMarkRead(config->readBoolEntry("MarkRead", true));//read the modes of account + d->callWindowTimeout = config->readNumEntry("CloseWindowTimeout", 3); + setPings(config->readBoolEntry("Pings", true)); + d->sessions.setAutoDelete(false); + d->lastSession = 0L; + d->callCount = 0; +} + + +SkypeAccount::~SkypeAccount() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + save(); + + d->protocol->unregisterAccount();//This account no longer exists + + //free memory + delete d; +} + +bool SkypeAccount::createContact(const QString &contactID, SIM::MetaContact *parentContact) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + if (!contact(contactID)) {//check weather it is not used already + SkypeContact *newContact = new SkypeContact(this, contactID, parentContact);//create the contact + + return newContact != 0L;//test weather it was created + } else { + kdDebug(14311) << k_funcinfo << "Contact already exists:" << contactID << endl;//Tell that it is not OK + + return false; + } +} + +void SkypeAccount::setAway(bool away, const QString &reason) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + if (away) + setOnlineStatus(d->protocol->Away, reason); + else + setOnlineStatus(d->protocol->Online, reason); +} + +void SkypeAccount::setOnlineStatus(const SIM::OnlineStatus &status, const QString &) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + if (status == d->protocol->Online) + d->skype.setOnline();//Go online + else if (status == d->protocol->Offline) + d->skype.setOffline();//Go offline + else if (status == d->protocol->Away) + d->skype.setAway(); + else if (status == d->protocol->NotAvailable) + d->skype.setNotAvailable(); + else if (status == d->protocol->DoNotDisturb) + d->skype.setDND(); + else if (status == d->protocol->Invisible) + d->skype.setInvisible(); + else if (status == d->protocol->SkypeMe) + d->skype.setSkypeMe(); + else + kdDebug(14311) << "Unknown online status" << endl;//Just a warning that I do not know that status +} + +void SkypeAccount::disconnect() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + setOnlineStatus(d->protocol->Offline, ""); +} + +SkypeContact *SkypeAccount::contact(const QString &id) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + return static_cast(contacts()[id]);//get the contact and convert it into the skype contact, there are no other contacts anyway +} + +void SkypeAccount::connect(const SIM::OnlineStatus &Status) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + if ((Status != d->protocol->Online) && (Status != d->protocol->Away) && + (Status != d->protocol->NotAvailable) && (Status != d->protocol->DoNotDisturb) && + (Status != d->protocol->SkypeMe))//some strange online status, taje a default one + setOnlineStatus(d->protocol->Online, ""); + else + setOnlineStatus(Status, "");//just change the status +} + +void SkypeAccount::save() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + KConfigGroup *config = configGroup();//get the config + config->writeEntry("Authorization", author);//write the authorization name + config->writeEntry("Launch", launchType);//and the launch type + config->writeEntry("Hitch", getHitchHike());//save the hitch hike messages mode + config->writeEntry("MarkRead", getMarkRead());//save the Mark read messages mode + config->writeEntry("ScanForUnread", getScanForUnread()); + config->writeEntry("CallControl", getCallControl()); + config->writeEntry("CloseWindowTimeout", d->callWindowTimeout); + config->writeEntry("Pings", getPings()); + config->writeEntry("Bus", getBus()); + config->writeEntry("StartDBus", getStartDBus()); + config->writeEntry("LaunchTimeout", getLaunchTimeout()); + config->writeEntry("SkypeCommand", getSkypeCommand()); + config->writeEntry("MyselfName", d->myName); + config->writeEntry("WaitBeforeConnect", getWaitBeforeConnect()); + config->writeEntry("LeaveOnExit", leaveOnExit()); + config->writeEntry("StartCallCommand", startCallCommand()); + config->writeEntry("EndCallCommand", endCallCommand()); + config->writeEntry("WaitForStartCallCommand", waitForStartCallCommand()); + config->writeEntry("EndCallCommandOnlyLast", endCallCommandOnlyLast()); + config->writeEntry("IncomingCall", incomingCommand()); + + //save it into the skype connection as well + d->skype.setValues(launchType, author); +} + +void SkypeAccount::wentOnline() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + myself()->setOnlineStatus(d->protocol->Online);//just set the icon + d->skype.enablePings(d->pings); + emit connectionStatus(true); +} + +void SkypeAccount::wentOffline() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + myself()->setOnlineStatus(d->protocol->Offline);//just change the icon + emit connectionStatus(false); +} + +void SkypeAccount::wentAway() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + myself()->setOnlineStatus(d->protocol->Away);//just change the icon + emit connectionStatus(true); +} + +void SkypeAccount::wentNotAvailable() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + myself()->setOnlineStatus(d->protocol->NotAvailable); + emit connectionStatus(true); +} + +void SkypeAccount::wentDND() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + myself()->setOnlineStatus(d->protocol->DoNotDisturb); + emit connectionStatus(true); +} + +void SkypeAccount::wentInvisible() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + myself()->setOnlineStatus(d->protocol->Invisible); + emit connectionStatus(true); +} + +void SkypeAccount::wentSkypeMe() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + myself()->setOnlineStatus(d->protocol->SkypeMe); + emit connectionStatus(true); +} + +void SkypeAccount::statusConnecting() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + myself()->setOnlineStatus(d->protocol->Connecting); + emit connectionStatus(false); +} + +void SkypeAccount::newUser(const QString &name) { + kdDebug(14311) << k_funcinfo << QString("name = %1").arg(name) << endl;//some debug info + if (contacts().find(name)) + return; + addContact(name); +} + +void SkypeAccount::prepareContact(SkypeContact *contact) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + QObject::connect(&d->skype, SIGNAL(updateAllContacts()), contact, SLOT(requestInfo()));//all contacts will know that + QObject::connect(contact, SIGNAL(infoRequest(const QString& )), &d->skype, SLOT(getContactInfo(const QString& )));//How do we ask for info? + QObject::connect(this, SIGNAL(connectionStatus(bool )), contact, SLOT(connectionStatus(bool ))); + QObject::connect(contact, SIGNAL(setCallPossible(bool )), d->protocol, SLOT(updateCallActionStatus())); +} + +void SkypeAccount::updateContactInfo(const QString &contact, const QString &change) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + SkypeContact *cont = static_cast (contacts().find(contact));//get the contact + if (cont) + cont->setInfo(change);//give it the message + else {//it does not yet exist, create it if it is in skype contact list (can be got by buddystatus) + const QString &type = change.section(' ', 0, 0).stripWhiteSpace().upper();//get the first part of the message, it should be BUDDYSTATUS + const QString &value = change.section(' ', 1, 1).stripWhiteSpace();//get the second part if it is some reasonable value + if ((type == "BUDDYSTATUS") && ((value == "2") || (value == "3"))) {//the user is in skype contact list + newUser(contact); + } else if (type != "BUDDYSTATUS")//this is some other info + d->skype.getContactBuddy(contact);//get the buddy status for the account and check, if it is in contact list or not + } +} + +bool SkypeAccount::canComunicate() { + return d->skype.canComunicate(); +} + +SkypeProtocol * SkypeAccount::protocol() { + return d->protocol; +} + +void SkypeAccount::sendMessage(SIM::Message &message, const QString &chat) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + if (chat.isEmpty()) { + const QString &user = message.to().at(0)->contactId();//get id of the first contact, messages to multiple people are not yet possible + const QString &body = message.plainBody();//get the text of the message + + d->skype.send(user, body);//send it by skype + } else { + const QString &body = message.plainBody(); + + d->skype.sendToChat(chat, body); + } +} + +bool SkypeAccount::getHitchHike() const { + return d->hitch; +} + +bool SkypeAccount::getMarkRead() const { + return d->markRead; +} + +void SkypeAccount::setHitchHike(bool value) { + d->hitch = value;//save it + d->skype.setHitchMode(value);//set it in the skype +} + +void SkypeAccount::setMarkRead(bool value) { + d->markRead = value;//remember it + d->skype.setMarkMode(value); +} + +bool SkypeAccount::userHasChat(const QString &userId) { + SkypeContact *cont = static_cast (contacts().find(userId));//get the contact + + if (cont)//it exists + return cont->hasChat();//so ask it + else + return false;//if it does not exist it can not have a chat opened +} + +void SkypeAccount::receivedIm(const QString &user, const QString &message, const QString &messageId) { + kdDebug(14311) << k_funcinfo << "User: " << user << ", message: " << message << endl;//some debug info + getContact(user)->receiveIm(message, getMessageChat(messageId));//let the contact show the message +} + +void SkypeAccount::setScanForUnread(bool value) { + d->searchForUnread = value; + d->skype.setScanForUnread(value); +} + +bool SkypeAccount::getScanForUnread() const { + return d->searchForUnread; +} + +void SkypeAccount::makeCall(SkypeContact *user) { + makeCall(user->contactId()); +} + +void SkypeAccount::makeCall(const QString &users) { + startCall(); + d->skype.makeCall(users); +} + +bool SkypeAccount::getCallControl() const { + return d->callControl; +} + +void SkypeAccount::setCallControl(bool value) { + d->callControl = value; +} + +void SkypeAccount::newCall(const QString &callId, const QString &userId) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + if (d->callControl) {//Show the skype call control window + SkypeCallDialog *dialog = new SkypeCallDialog(callId, userId, this);//It should free itself when it is closed + QObject::connect(&d->skype, SIGNAL(callStatus(const QString&, const QString& )), dialog, SLOT(updateStatus(const QString&, const QString& ))); + QObject::connect(dialog, SIGNAL(acceptTheCall(const QString& )), &d->skype, SLOT(acceptCall(const QString& ))); + QObject::connect(dialog, SIGNAL(hangTheCall(const QString& )), &d->skype, SLOT(hangUp(const QString& ))); + QObject::connect(dialog, SIGNAL(toggleHoldCall(const QString& )), &d->skype, SLOT(toggleHoldCall(const QString& ))); + QObject::connect(&d->skype, SIGNAL(callError(const QString&, const QString& )), dialog, SLOT(updateError(const QString&, const QString& ))); + QObject::connect(&d->skype, SIGNAL(skypeOutInfo(int, const QString& )), dialog, SLOT(skypeOutInfo(int, const QString& ))); + QObject::connect(dialog, SIGNAL(updateSkypeOut()), &d->skype, SLOT(getSkypeOut())); + QObject::connect(dialog, SIGNAL(callFinished(const QString& )), this, SLOT(removeCall(const QString& ))); + d->skype.getSkypeOut(); + + d->calls.insert(callId, dialog); + } + + if ((!d->incommingCommand.isEmpty()) && (d->skype.isCallIncoming(callId))) { + kdDebug(14311) << "Running ring command" << endl; + KProcess *proc = new KProcess(); + (*proc) << QStringList::split(' ', d->incommingCommand); + QObject::connect(proc, SIGNAL(processExited(KProcess* )), proc, SLOT(deleteLater())); + proc->start(); + } +} + +bool SkypeAccount::isCallIncoming(const QString &callId) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + return d->skype.isCallIncoming(callId); +} + +void SkypeAccount::setCloseWindowTimeout(int timeout) { + d->callWindowTimeout = timeout; +} + +int SkypeAccount::closeCallWindowTimeout() const { + return d->callWindowTimeout; +} + +QString SkypeAccount::getUserLabel(const QString &userId) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + if (userId.find(' ') != -1) {//there are more people than just one + QStringList users = QStringList::split(' ', userId); + for (QStringList::iterator it = users.begin(); it != users.end(); ++it) { + (*it) = getUserLabel((*it).stripWhiteSpace()); + } + return users.join("\n"); + } + + SIM::Contact *cont = contact(userId); + + if (!cont) { + addContact(userId, QString::null, 0L, Temporary);//create a temporary contact + + cont = (contacts().find(userId));//It should be there now + if (!cont) + return userId;//something odd,.but better do nothing than crash + } + + return QString("%1 (%2)").arg(cont->nickName()).arg(userId); +} + +void SkypeAccount::setPings(bool enabled) { + d->skype.enablePings(enabled); + d->pings = enabled; +} + +bool SkypeAccount::getPings() const { + return d->pings; +} + +int SkypeAccount::getBus() const { + return d->bus; +} + +void SkypeAccount::setBus(int bus) { + d->bus = bus; + d->skype.setBus(bus); +} + +void SkypeAccount::setStartDBus(bool enable) { + d->startDBus = enable; + d->skype.setStartDBus(enable); +} + +bool SkypeAccount::getStartDBus() const { + return d->startDBus; +} + +void SkypeAccount::setLaunchTimeout(int seconds) { + d->launchTimeout = seconds; + d->skype.setLaunchTimeout(seconds); +} + +int SkypeAccount::getLaunchTimeout() const { + return d->launchTimeout; +} + +void SkypeAccount::setSkypeCommand(const QString &command) { + d->skypeCommand = command; + d->skype.setSkypeCommand(command); +} + +const QString &SkypeAccount::getSkypeCommand() const { + return d->skypeCommand; +} + +void SkypeAccount::setMyselfName(const QString &name) { + d->myName = name; + myself()->setNickName(name); +} + +void SkypeAccount::setWaitBeforeConnect(int value) { + d->waitBeforeConnect = value; + d->skype.setWaitConnect(value); +} + +int SkypeAccount::getWaitBeforeConnect() const { + return d->waitBeforeConnect; +} + +SkypeContact *SkypeAccount::getContact(const QString &userId) { + SkypeContact *cont = static_cast (contacts().find(userId));//get the contact + if (!cont) {//We do not know such contact + addContact(userId, QString::null, 0L, Temporary);//create a temporary contact + + cont = static_cast (contacts().find(userId));//It should be there now + } + return cont; +} + +void SkypeAccount::prepareChatSession(SkypeChatSession *session) { + QObject::connect(session, SIGNAL(updateChatId(const QString&, const QString&, SkypeChatSession* )), this, SLOT(setChatId(const QString&, const QString&, SkypeChatSession* ))); + QObject::connect(session, SIGNAL(wantTopic(const QString& )), &d->skype, SLOT(getTopic(const QString& ))); + QObject::connect(&d->skype, SIGNAL(joinUser(const QString&, const QString& )), session, SLOT(joinUser(const QString&, const QString& ))); + QObject::connect(&d->skype, SIGNAL(leftUser(const QString&, const QString&, const QString& )), session, SLOT(leftUser(const QString&, const QString&, const QString& ))); + QObject::connect(&d->skype, SIGNAL(setTopic(const QString&, const QString& )), session, SLOT(setTopic(const QString&, const QString& ))); + QObject::connect(session, SIGNAL(inviteUserToChat(const QString&, const QString& )), &d->skype, SLOT(inviteUser(const QString&, const QString& ))); + QObject::connect(session, SIGNAL(leaveChat(const QString& )), &d->skype, SLOT(leaveChat(const QString& ))); +} + +void SkypeAccount::setChatId(const QString &oldId, const QString &newId, SkypeChatSession *sender) { + d->sessions.remove(oldId);//remove the old one + if (!newId.isEmpty()) { + d->sessions.insert(newId, sender); + } +} + +bool SkypeAccount::chatExists(const QString &chat) { + return d->sessions.find(chat); +} + +void SkypeAccount::receiveMultiIm(const QString &chatId, const QString &body, const QString &messageId, const QString &user) { + SkypeChatSession *session = d->sessions.find(chatId); + + if (!session) { + QStringList users = d->skype.getChatUsers(chatId); + SIM::ContactPtrList list; + for (QStringList::iterator it = users.begin(); it != users.end(); ++it) { + list.append(getContact(*it)); + } + + session = new SkypeChatSession(this, chatId, list); + } + + SIM::Message mes(getContact(user), myself(), body, SIM::Message::Inbound); + session->appendMessage(mes); +} + +QString SkypeAccount::getMessageChat(const QString &messageId) { + return d->skype.getMessageChat(messageId); +} + +void SkypeAccount::registerLastSession(SkypeChatSession *lastSession) { + d->lastSession = lastSession; +} + +void SkypeAccount::gotMessageId(const QString &messageId) { + if ((d->lastSession) && (!messageId.isEmpty())) { + d->lastSession->setChatId(d->skype.getMessageChat(messageId)); + } + + d->lastSession = 0L; +} + +void SkypeAccount::sentMessage(const QString &body, const QString &chat) { + kdDebug(14311) << k_funcinfo << "chat: " << chat << endl;//some debug info + + SkypeChatSession *session = d->sessions.find(chat); + const QStringList &users = d->skype.getChatUsers(chat); + QPtrList *recv = 0L; + + if (!session) + if (d->hitch) { + recv = constructContactList(users); + if (recv->count() == 1) { + SkypeContact *cont = static_cast (recv->at(0)); + cont->startChat(); + session = cont->getChatSession(); + session->setChatId(chat); + } else { + session = new SkypeChatSession(this, chat, *recv); + } + } else { + return; + } + + if (!recv) + recv = constructContactList(users); + + session->sentMessage(recv, body); + delete recv; +} + +QPtrList *SkypeAccount::constructContactList(const QStringList &users) { + QPtrList *list= new QPtrList (); + for (QStringList::const_iterator it = users.begin(); it != users.end(); ++it) { + list->append(getContact(*it)); + } + + return list; +} + +void SkypeAccount::groupCall(const QString &callId, const QString &groupId) { + kdDebug(14311) << k_funcinfo << endl; + + //TODO: Find out a way to embet qdialog into another one after creation + return; + + if (!d->callControl) + return; + + SkypeConference *conf; + if (!(conf = d->conferences[groupId])) {//does it already exist? + conf = new SkypeConference(groupId);//no, create one then.. + d->conferences.insert(groupId, conf); + + QObject::connect(conf, SIGNAL(removeConference(const QString& )), this, SLOT(removeCallGroup(const QString& ))); + } + + conf->embedCall(d->calls[callId]); +} + +void SkypeAccount::removeCall(const QString &callId) { + kdDebug(14311) << k_funcinfo << endl; + d->calls.remove(callId); +} + +void SkypeAccount::removeCallGroup(const QString &groupId) { + kdDebug(14311) << k_funcinfo << endl; + d->conferences.remove(groupId); +} + +QString SkypeAccount::createChat(const QString &users) { + return d->skype.createChat(users); +} + +bool SkypeAccount::leaveOnExit() const { + return d->leaveOnExit; +} + +void SkypeAccount::setLeaveOnExit(bool value) { + d->leaveOnExit = value; +} + +void SkypeAccount::chatUser(const QString &userId) { + SkypeContact *contact = getContact(userId); + + contact->execute(); +} + +void SkypeAccount::setStartCallCommand(const QString &value) { + d->startCallCommand = value; +} + +void SkypeAccount::setEndCallCommand(const QString &value) { + d->endCallCommand = value; +} + +void SkypeAccount::setWaitForStartCallCommand(bool value) { + d->waitForStartCallCommand = value; +} +void SkypeAccount::setEndCallCommandOnlyForLast(bool value) { + d->endCallCommandOnlyLats = value; +} + +QString SkypeAccount::startCallCommand() const { + return d->startCallCommand; +} + +QString SkypeAccount::endCallCommand() const { + return d->endCallCommand; +} + +bool SkypeAccount::waitForStartCallCommand() const { + return d->waitForStartCallCommand; +} + +bool SkypeAccount::endCallCommandOnlyLast() const { + return d->endCallCommandOnlyLats; +} + +void SkypeAccount::startCall() { + kdDebug(14311) << k_funcinfo << endl; + + KProcess *proc = new KProcess(); + QObject::connect(proc, SIGNAL(processExited(KProcess* )), proc, SLOT(deleteLater())); + QStringList args = QStringList::split(' ', d->startCallCommand); + (*proc) << args;//set what will be executed + KProcess::RunMode mode = d->waitForStartCallCommand ? KProcess::Block : KProcess::NotifyOnExit; + proc->start(mode); + ++d->callCount; +} + +void SkypeAccount::endCall() { + kdDebug(14311) << k_funcinfo << endl; + + if ((--d->callCount == 0) || (!d->endCallCommandOnlyLats)) { + KProcess *proc = new KProcess(); + QObject::connect(proc, SIGNAL(processExited(KProcess* )), proc, SLOT(deleteLater())); + (*proc) << QStringList::split(' ', d->endCallCommand); + proc->start(); + } + if (d->callCount < 0) + d->callCount = 0; +} + +void SkypeAccount::setIncomingCommand(const QString &command) { + d->incommingCommand = command; +} + +QString SkypeAccount::incomingCommand() const { + return d->incommingCommand; +} + +void SkypeAccount::registerContact(const QString &contactId) { + kdDebug(14311) << k_funcinfo << endl; + d -> skype.addContact(contactId); +} + +void SkypeAccount::removeContact(const QString &contactId) { + d -> skype.removeContact(contactId); +} + +bool SkypeAccount::ableMultiCall() { + return (d->skype.ableConference()); +} + +bool SkypeAccount::canAlterAuth() { + return (d->skype.canComunicate()); +} + +void SkypeAccount::authorizeUser(const QString &userId) { + d->skype.setAuthor(userId, Skype::Author); +} + +void SkypeAccount::disAuthorUser(const QString &userId) { + d->skype.setAuthor(userId, Skype::Deny); +} + +void SkypeAccount::blockUser(const QString &userId) { + d->skype.setAuthor(userId, Skype::Block); +} + +int SkypeAccount::getAuthor(const QString &contactId) { + switch (d->skype.getAuthor(contactId)) { + case Skype::Author: + return 0; + case Skype::Deny: + return 1; + case Skype::Block: + return 2; + } +} + +#include "skypeaccount.moc" diff --git a/plugins/skype/skypeaccount.h b/plugins/skype/skypeaccount.h new file mode 100644 index 0000000..8d836f6 --- /dev/null +++ b/plugins/skype/skypeaccount.h @@ -0,0 +1,509 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Michal Vaner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ +#ifndef SKYPEACCOUNT_H +#define SKYPEACCOUNT_H + +#include + +class SkypeProtocol; +class QString; +class SkypeAccountPrivate; +class SkypeContact; +class SkypeChatSession; +template class QPtrList; + +namespace SIM { + class MetaContact; + class OnlineStatus; + class Message; + class Kontact; +} + +#define DBUS_SESSION 0 +#define DBUS_SYSTEM 1 + +/** + * @author Michal Vaner + * @short Skype account + * Account to use external skype program. At this time, it only supports one skype account at one, may be more in future. + */ +class SkypeAccount : public SIM::Account +{ +Q_OBJECT + private: + ///Some internal things + SkypeAccountPrivate *d; + ///Constructs list of users from their ID list. Have to be deleted later! + QPtrList *constructContactList(const QStringList &users); + private slots: + /** + * This sets the right icon for the status - online + */ + void wentOnline(); + /** + * This changes the account icon to offline + */ + void wentOffline(); + /** + * This changes the account icon to away + */ + void wentAway(); + /** + * This changes the account icon to not available + */ + void wentNotAvailable(); + /** + * This changes the account icon to Do not disturb + */ + void wentDND(); + /** + * This changes the status icon of account to Invisible + */ + void wentInvisible(); + /** + * This changes the status indicator to Skype me + */ + void wentSkypeMe(); + /** + * The status changed to actually connecting + */ + void statusConnecting(); + /** + * This adds user to the contact list if it is not there + * @param name The skype name of the contact + */ + void newUser(const QString &name); + /** + * This is used for receiving messages from skype network + * @param user The user that sent it + * @param message The text of the message + * @param messageId Id of that message + */ + void receivedIm(const QString &user, const QString &message, const QString &messageId); + /** + * New cal to show (or not, depending on setup) the call control window. + * @param callId ID of the new call + * @param userId User that is on the other end. If conference, list of IDs divided by spaces. + */ + void newCall(const QString &callId, const QString &userId); + /** + * This one sets name of myself + * @param name What the new name is. + */ + void setMyselfName(const QString &name); + /** + * This one keeps track of chat sessions that know their chat id + * @param oldId The old chat ID, or empty if no chat ID was known before + * @param newId The new chat ID, or empty if the chat just exists + * @param sender Pointer to the session + */ + void setChatId(const QString &oldId, const QString &newId, SkypeChatSession *sender); + /** + * Some message is meing sent out by Skype, it should be showed + * @param body Text of the message + * @param chat Id of the chat it was sent to + */ + void sentMessage(const QString &body, const QString &chat); + /** + * An Id of some message is known, use it + * @param messageId New id of that message + */ + void gotMessageId(const QString &messageId); + /** + * This is used to group conference call participants together + * @param callId What call to add to the group + * @param groupIt to what group to add it + */ + void groupCall(const QString &callId, const QString &groupId); + /** + * Remove that call from list + * @param callId what call + */ + void removeCall(const QString &callId); + /** + * Remove reference to a call group + * @param groupId What group to remove + */ + void removeCallGroup(const QString &groupId); + protected: + /** + * Creates new skype contact and adds it into the parentContact. + * @param contactID ID of the contact (the skype name) + * @param parentContact Metacontact to add it into. + * @return True if it worked, false otherwise. + */ + virtual bool createContact(const QString &contactID, SIM::MetaContact *parentContact); + public: + /** + * Constructor. + * @param protocol The skype protocol pointer. + */ + SkypeAccount(SkypeProtocol *protocol); + /** + * Destructor + */ + ~SkypeAccount(); + /** + * Finds contact of given id + * @param id id of the wanted contact + * @return eather pointer to that contact or 0L of it was not found. + */ + SkypeContact *contact(const QString &id); + /** + * How to launch the Skype + */ + int launchType; + /** + * Is this verson of protocol able to create call conferences? + */ + bool ableMultiCall(); + /** + * Is it possible to alter the authorization now? + */ + bool canAlterAuth(); + /** + * How shoul SIM authorize it self? (empty means as SIM) + */ + QString author; + /** + * This saves properties to the config file + */ + void save(); + /** + * Prepares this contact for life and integrates it into this account. Should be called only by the contact in its constructor. + * @param conntact The contact to prepare + */ + void prepareContact(SkypeContact *contact); + ///Can we comunicate with the skype? (not with the network, just with the program) + bool canComunicate(); + ///returns the protocol + SkypeProtocol * protocol(); + /** + * @return Is the HitchHike mode enabled or not? + * @see setHitchHike + */ + bool getHitchHike() const; + /** + * @return Is the MarkRead mode enabled or not? + * @see setMarkRead + */ + bool getMarkRead() const; + /** + * Is the scan for unread message on login enabled? + * @return Is it enabled or not? + * @see setSearchForUnread + */ + bool getScanForUnread() const; + /** + * @return true if this user already has opened chat session, false if he doesn't have opened chat session or the user do not exist + * @param userId ID of the user in interest + */ + bool userHasChat(const QString &userId); + /** + * @return Should a control window be showed for calls? + */ + bool getCallControl() const; + /** + * Is that call incoming or not? + * @param callId What call you want to know? + * @return true if the call is incoming call (someone calls you), false otherwise (outgoing, not a call at all..) + */ + bool isCallIncoming(const QString &callId); + /** + * @return The time after the call finished to auto-closing the window. If auto-closing is disabled, 0 is returned + * @see setCallWindowTimeout + */ + int closeCallWindowTimeout() const; + /** + * @return Returns name that shouls be showed by a call window + */ + QString getUserLabel(const QString &userId); + /** + * Are pings to Skype enabled? + * @return You guess.. + */ + bool getPings() const; + /** + * What bus is set to use now? + * @return 0 as session bus, 1 as system wide + */ + int getBus() const; + /** + * Is starting Dbus when it is not running enabled? + * @return You guess.. + */ + bool getStartDBus() const; + /** + * How long does it try to connect to newly started skype, until it gives up (seconds) + */ + int getLaunchTimeout() const; + /** + * What is the command that launches skype? + */ + const QString &getSkypeCommand() const; + /** + * Do we wait before connecting? + */ + int getWaitBeforeConnect() const; + /** + * Do we have that chat opened? + * @param chatId What chat are you interested in? + */ + bool chatExists(const QString &chatId); + /** + * This one returns contact of that name. If that contact does not exist in the contact list, a temporary one is created + * @param userId ID of that user + */ + SkypeContact *getContact(const QString &userId); + /** + * @param messageId ID of a message + * @return ID of chat the message belongs to. If no such message exists, the result is not defined. + */ + QString getMessageChat(const QString &messageId); + /** + * This will mark last active chat (last that sent out some message). It will be set an ID soon after that, user will not have time to write another message anyway + * @param session Pointer to that chat session + */ + void registerLastSession(SkypeChatSession *session); + /** + * Create a chat with given members + * @param users Comma sepparated list of members + * @return ID of the chat + */ + QString createChat(const QString &users); + /** + * Should chat leave when it's window is closed? + */ + bool leaveOnExit() const; + /** + * Returns the call that should be executed before making a call. + * @return The command or empty string if nothing should be executed + */ + QString startCallCommand() const; + /** + * Should we wait for the startCallCommand to finish before making the call. + */ + bool waitForStartCallCommand() const; + /** + * The command that should be executed after the call is finished. + * @return The command or empty string if user does not want to execute anything. + */ + QString endCallCommand() const; + /** + * Should be tha command executed only for the last call? + */ + bool endCallCommandOnlyLast() const; + /** + * Command that should be executed on incoming call, or empty string if nothing to execute + */ + QString incomingCommand() const; + /** + * Registers this contact to the skype contact list + * @param contactId What user should be added? + */ + void registerContact(const QString &contactId); + /** + * returns how is user authorized + * @return 0 if he is authorized, 1 if not and 2 if he is blocked + */ + int getAuthor(const QString &contactId); + public slots: + /** + * Disconnects from server. + */ + virtual void disconnect(); + /** + * Sets online status to away/online. + * @param away If true, it sets to away, otherwise it sets to online. + * @param reason Message to set. Ignored with skype as it does not support away messages. (Or I don't know about it)) + */ + virtual void setAway(bool away, const QString &reason); + /** + * Sets online status for the account. + * @param status Status to set. + * @param reason Away message. Ignored by skype. + */ + virtual void setOnlineStatus(const SIM::OnlineStatus &status, const QString &reason); + /** + * Connect to the skype with given status + * @param status The status to connect with. If it is something unusual (like offline or something unknown), online is used + */ + virtual void connect(const SIM::OnlineStatus &status); + /** + * This notifies contact of some change of its information + * @param contact What contact is it? + * @param change And what happende. + */ + void updateContactInfo(const QString &contact, const QString &change); + /** + * This will send message by the skype connection. Will take care of all notifications when it is done and so. (means it will emit messageSent when it is sent) + * @param message What to send. + * @param chat Chat to send it to. If it is empty, it is sent just to that person listed in the message + */ + void sendMessage(SIM::Message &message, const QString &chat); + /** + * Enables or disables the HitchHike mode of getting messages. If it is enabled, a new message to unstarted chat will be showed. If not, they will be ignored and you will have to open them in Skype + * @param value True enables HitchHike mode, false disables. + * @see getHitchHike + */ + void setHitchHike(bool value); + /** + * Enables reading messages by SIM. If it is on, all messages showed in SIM will be marked as read, if disable, you will have to read them in Skype/something else. + * If HitchHike mode is disabled, messages that creates chats are NOT marked as read, because they are not showed. + * @param value Enable or disable the mode + * @see getMarkRead + * @see getHitchHake + * @see setHitchHike + */ + void setMarkRead(bool value); + /** + * Set if there should be scan for unread messages when SIM connects to Skype. + * @param value Enable or disable the scan. + * @see getScanForUnread + */ + void setScanForUnread(bool value); + /** + * Make a call to that user + * @param user To who we call. + */ + void makeCall(SkypeContact *user); + /** + * Make conference call to more than one user (possibly) + * @param users comma separated list of user IDs + */ + void makeCall(const QString &users); + /** + * Set if a control window will be showed for calls. + * @param value Is it enabled or disabled now? + */ + void setCallControl(bool value); + /** + * Sets timeout in seconds how long will be call window visible after the call finished. If you want to disable it, set to 0. + */ + void setCloseWindowTimeout(int timeout); + /** + * Turns pinging skype on/off + * If it is on, every second a ping message is sent to skype so track of if Skype is running is still hold. f it is off, skype can be turned off and you won't know it. + * @param enabled Are they on or off from now? + */ + void setPings(bool enabled); + /** + * Sets bus on which Skype listens + * @param bus 0 -> session bus, 1 -> system wide bus + */ + void setBus(int bus); + /** + * Should be DBus started when needed? + */ + void setStartDBus(bool enabled); + /** + * Set the timeout for giving up launching Skype + */ + void setLaunchTimeout(int seconds); + /** + * Set command by what the Skype will be started + */ + void setSkypeCommand(const QString &command); + /** + * Set if we wait a while before connecting to just started skype + */ + void setWaitBeforeConnect(int value); + /** + * This should be called with all new chat sessions to connect all signals to them + * @param session The chat session + */ + void prepareChatSession(SkypeChatSession *session); + /** + * This receives a multi-user chat message and delivers it to the chat session + * @param chatId What chat should get it + * @param boty Text of that message + * @param messageId ID of the received message + * @param user The one who sent it + */ + void receiveMultiIm(const QString &chatId, const QString &body, const QString &messageId, const QString &user); + /** + * Set if chat window should close a chat window when you close it + */ + void setLeaveOnExit(bool value); + /** + * Open chat to the user + * @param userId + */ + void chatUser(const QString &userId); + /** + * Sets the command to be executed before making/accepting call (or empty if nothing) + */ + void setStartCallCommand(const QString &value); + /** + * Set the command that will be executed when a call is finished + */ + void setEndCallCommand(const QString &value); + /** + * Do we wait for the command to be executed before making the call? + */ + void setWaitForStartCallCommand(bool value); + /** + * Should be the end command executed only for the last closed call or for every call that is closed? + */ + void setEndCallCommandOnlyForLast(bool value); + /** + * Notify me when a call has begun and I should run the start call command + */ + void startCall(); + /** + * Notify me when the call ends to run the end call command + */ + void endCall(); + /** + * Sets a command to be executed for incoming call + */ + void setIncomingCommand(const QString &command); + /** + * Removes a given contact from skype + */ + void removeContact(const QString &contactId); + /** + * authorizes a user + * @param userId what user + */ + void authorizeUser(const QString &userId); + /** + * removes authorization from user + * @param userId what user + */ + void disAuthorUser(const QString &userId); + /** + * Blocks a user (no more messages will be accepted) + * @param userId what user + */ + void blockUser(const QString &userId); + signals: + /** + * This is emited when the message has been sent by skype + * @param messageId Id of the message that has been sent + */ + void sentMessage(const QString &messageId); + /** + * This slot notifies of connecting/disconnecting. Needed to be sure, if alling is possible. + * @param online Are we online now? + */ + void connectionStatus(bool online); +}; + +#endif diff --git a/plugins/skype/skypeaddcontact.cpp b/plugins/skype/skypeaddcontact.cpp new file mode 100644 index 0000000..b322a10 --- /dev/null +++ b/plugins/skype/skypeaddcontact.cpp @@ -0,0 +1,93 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Michal Vaner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ +#include "skypeaddcontact.h" +#include "skypeprotocol.h" +#include +#include "skypeaccount.h" + +#include +#include +#include +#include +#include + +class SkypeAddContactWidget : public SkypeAddContactBase { + private: + public: + SkypeAddContactWidget(QWidget *parent, const char *name = 0L) : SkypeAddContactBase(parent, name) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + } +}; + +class SkypeAddContactPrivate { + public: + SkypeProtocol *protocol; + SkypeAddContactWidget *widget; + SkypeAccount *account; +}; + +SkypeAddContact::SkypeAddContact(SkypeProtocol *protocol, QWidget *parent, SkypeAccount *account, const char *name) : AddContactPage(parent, name) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + d = new SkypeAddContactPrivate();//create the d ponter + d->protocol = protocol;//remember the protocol + d->account = account; + + (new QVBoxLayout(this))->setAutoAdd(true);//create the layout and add there automatically + d->widget = new SkypeAddContactWidget(this);//create the insides +} + + +SkypeAddContact::~SkypeAddContact() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + //free everything (the widget is deleted automatically) + delete d; +} + +bool SkypeAddContact::validateData() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + if (!d->account->canComunicate()) { + KMessageBox::sorry(d->widget, i18n("You must connect to Skype first"), i18n("Not Connected")); + return false; + } + + if (d->widget->NameEdit->text().isEmpty()) {//He wrote nothing + KMessageBox::sorry(d->widget, i18n("You must write the contact's name"), i18n("Wrong Information"));//Tell the user I don't like this at all + return false;//and don't allow to continue + } + + if (d->account->contact(d->widget->NameEdit->text())) {//this contact already exists in this account + KMessageBox::sorry(d->widget, i18n("This contact already exists in this account"), i18n("Wrong Information"));//Tell the user + return false;//do not proceed + } + + return true; +} + +bool SkypeAddContact::apply(SIM::Account *, SIM::MetaContact *metaContact) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + d->account->registerContact(d->widget->NameEdit->text()); + d->account->addContact(d->widget->NameEdit->text(), metaContact, SIM::Account::ChangeKABC); + return true;//all OK +} + +#include "skypeaddcontact.moc" diff --git a/plugins/skype/skypeaddcontact.h b/plugins/skype/skypeaddcontact.h new file mode 100644 index 0000000..dc0e808 --- /dev/null +++ b/plugins/skype/skypeaddcontact.h @@ -0,0 +1,66 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Michal Vaner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ +#ifndef SKYPEADDCONTACT_H +#define SKYPEADDCONTACT_H + +#include + +class SkypeAddContactPrivate; +class QString; +class SkypeProtocol; +class SkypeAccount; + +/** + * @author Michal Vaner (vorner) + * Just a widget with a line and label ;-) + */ +class SkypeAddContact : public AddContactPage +{ + Q_OBJECT + private: + ///internal things + SkypeAddContactPrivate *d; + public: + /** + * Constructor. + * @param protocol Pointer to the Skype protocol. + * @param parent Widget inside which I will be showed. + * @param name My name I can be found by. + */ + SkypeAddContact(SkypeProtocol *protocol, QWidget *parent, SkypeAccount *account, const char *name); + /** + * Destructor. + */ + ~SkypeAddContact(); + /** + * Check, weather user wrote something sane. + * @return True if it is useable, false otherwise. + */ + virtual bool validateData(); + public slots: + /** + * Adds it into the account.kdDebug(14311) << k_funcinfo << endl;//some debug info + * @param account Where to add it. + * @param metaContact Metacontact which will hold it. + * @return True if it worked, false if not. + */ + virtual bool apply(SIM::Account *account, SIM::MetaContact *metaContact); +}; + +#endif diff --git a/plugins/skype/skypeaddcontactbase.ui b/plugins/skype/skypeaddcontactbase.ui new file mode 100644 index 0000000..0d71b52 --- /dev/null +++ b/plugins/skype/skypeaddcontactbase.ui @@ -0,0 +1,144 @@ + +SkypeAddContactBase + + + SkypeAddContactBase + + + + 0 + 0 + 362 + 372 + + + + Add Skype Contact + + + + unnamed + + + + layout2 + + + + unnamed + + + + textLabel1 + + + Skype name: + + + + + NameEdit + + + + + + + groupBox1 + + + Search + + + + unnamed + + + + textLabel2 + + + Sorry, but the search function was not yet implemented. + + + WordBreak|AlignVCenter + + + + + layout3 + + + + unnamed + + + + spacer3 + + + Vertical + + + Expanding + + + + 20 + 0 + + + + + + SearchButton + + + false + + + Se&arch + + + + + spacer5 + + + Vertical + + + Expanding + + + + 20 + 0 + + + + + + + + + + spacer4 + + + Vertical + + + Expanding + + + + 20 + 61 + + + + + + + diff --git a/plugins/skype/skypecalldialog.cpp b/plugins/skype/skypecalldialog.cpp new file mode 100644 index 0000000..e6c30d0 --- /dev/null +++ b/plugins/skype/skypecalldialog.cpp @@ -0,0 +1,295 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Michal Vaner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "skypecalldialog.h" +#include "skypeaccount.h" + +typedef enum { + csNotRunning, + csOnHold, + csInProgress, + csShuttingDown +} callStatus; + +class SkypeCallDialogPrivate { + public: + ///The call is done by some account + SkypeAccount *account; + ///The other side + QString userId; + ///Id of the call + QString callId; + ///Was there some error? + bool error; + ///The timer for updating call info + QTimer *updater; + ///The status of the call + callStatus status; + ///The time the call is running or on hold (in halfes of seconds) + int totalTime; + ///The time the call is actually running (in halfes of seconds) + int callTime; + ///Did I reported the ed of call already? + bool callEnded; + ///Report that the call has ended, please + void endCall() { + if (!callEnded) { + callEnded = true; + account->endCall(); + } + }; +}; + +SkypeCallDialog::SkypeCallDialog(const QString &callId, const QString &userId, SkypeAccount *account) : SkypeCallDialogBase() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + //Initialize values + d = new SkypeCallDialogPrivate(); + d->account = account; + d->callId = callId; + d->userId = userId; + d->error = false; + d->status = csNotRunning; + d->totalTime = 0; + d->callTime = 0; + d->callEnded = false; + + d->updater = new QTimer(); + connect(d->updater, SIGNAL(timeout()), this, SLOT(updateCallInfo())); + d->updater->start(500); + + NameLabel->setText(account->getUserLabel(userId)); + + //Show the window + show(); + KWin::activateWindow(winId()); +} + + +SkypeCallDialog::~SkypeCallDialog(){ + kdDebug(14311) << k_funcinfo << endl;//some debug info + + emit callFinished(d->callId); + d->endCall(); + + delete d->updater; + delete d; +} + +void SkypeCallDialog::updateStatus(const QString &callId, const QString &status) { + kdDebug(14311) << k_funcinfo << "Status: " << status << endl;//some debug info + + if (callId == d->callId) { + if (status == "CANCELLED") { + HoldButton->setEnabled(false); + HangButton->setEnabled(false); + AcceptButton->setEnabled(false); + StatusLabel->setText(i18n("Canceled")); + closeLater(); + d->status = csNotRunning; + } else if (status == "BUSY") { + HoldButton->setEnabled(false); + HangButton->setEnabled(false); + AcceptButton->setEnabled(false); + StatusLabel->setText(i18n("Other person is busy")); + closeLater(); + d->status = csNotRunning; + } else if (status == "REFUSED") { + HoldButton->setEnabled(false); + HangButton->setEnabled(false); + AcceptButton->setEnabled(false); + StatusLabel->setText(i18n("Refused")); + closeLater(); + d->status = csNotRunning; + } else if (status == "MISSED") { + HoldButton->setEnabled(false); + HangButton->setEnabled(false); + AcceptButton->setEnabled(true); + AcceptButton->setText(i18n("Call Back")); + StatusLabel->setText(i18n("Missed")); + d->status = csNotRunning; + disconnect(AcceptButton, SIGNAL(clicked()), this, SLOT(acceptCall())); + connect(AcceptButton, SIGNAL(clicked()), this, SLOT(callBack())); + } else if (status == "FINISHED") { + HoldButton->setEnabled(false); + HangButton->setEnabled(false); + AcceptButton->setEnabled(false); + StatusLabel->setText(i18n("Finished")); + closeLater(); + d->status = csNotRunning; + } else if (status == "LOCALHOLD") { + HoldButton->setEnabled(true); + HoldButton->setText(i18n("Resume")); + HangButton->setEnabled(true); + AcceptButton->setEnabled(false); + StatusLabel->setText(i18n("On hold (local)")); + d->status = csOnHold; + } else if (status == "REMOTEHOLD") { + HoldButton->setEnabled(false); + HangButton->setEnabled(true); + AcceptButton->setEnabled(false); + StatusLabel->setText(i18n("On hold (remote)")); + d->status = csOnHold; + } else if (status == "ONHOLD") { + HoldButton->setEnabled(true); + HangButton->setEnabled(true); + AcceptButton->setEnabled(false); + StatusLabel->setText(i18n("On hold")); + d->status = csOnHold; + } else if (status == "INPROGRESS") { + HoldButton->setEnabled(true); + HoldButton->setText(i18n("Hold")); + HangButton->setEnabled(true); + AcceptButton->setEnabled(false); + StatusLabel->setText(i18n("In progress")); + d->status=csInProgress; + } else if (status == "RINGING") { + HoldButton->setEnabled(false); + AcceptButton->setEnabled(d->account->isCallIncoming(callId)); + HangButton->setEnabled(true); + StatusLabel->setText(i18n("Ringing")); + d->status = csNotRunning; + } else if (status == "FAILED") { + if (d->error) //This one is already handled + return; + HoldButton->setEnabled(false); + AcceptButton->setEnabled(false); + HangButton->setEnabled(false); + StatusLabel->setText(i18n("Failed")); + d->status = csNotRunning; + } else if (status == "ROUTING") { + HoldButton->setEnabled(false); + AcceptButton->setEnabled(false); + HangButton->setEnabled(true); + StatusLabel->setText(i18n("Connecting")); + d->status = csNotRunning; + } else if (status == "EARLYMEDIA") { + HoldButton->setEnabled(false); + AcceptButton->setEnabled(false); + HangButton->setEnabled(true); + StatusLabel->setText(i18n("Early media (waitong for operator..)")); + d->status = csNotRunning; + } else if (status == "UNPLACED") {//Ups, whats that, how that call got here? + deleteLater();//Just give up, this one is odd + } + } +} + +void SkypeCallDialog::acceptCall() { + d->account->startCall(); + emit acceptTheCall(d->callId); +} + +void SkypeCallDialog::hangUp() { + emit hangTheCall(d->callId); +} + +void SkypeCallDialog::holdCall() { + emit toggleHoldCall(d->callId); +} + +void SkypeCallDialog::closeEvent(QCloseEvent *) { + emit hangTheCall(d->callId);//Finish the call before you give up + deleteLater();//some kind of suicide +} + +void SkypeCallDialog::deathTimeout() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + deleteLater();//OK, the death is here :-) +} + +void SkypeCallDialog::closeLater() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + d->endCall(); + + if ((d->account->closeCallWindowTimeout()) && (d->status != csShuttingDown)) { + QTimer::singleShot(1000 * d->account->closeCallWindowTimeout(), this, SLOT(deathTimeout())); + d->status = csShuttingDown; + } +} + +void SkypeCallDialog::updateError(const QString &callId, const QString &message) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + if (callId == d->callId) { + AcceptButton->setEnabled(false); + HangButton->setEnabled(false); + HoldButton->setEnabled(false); + StatusLabel->setText(i18n("Failed (%1)").arg(message)); + closeLater(); + d->error = true; + } +} + +void SkypeCallDialog::updateCallInfo() { + switch (d->status) { + case csInProgress: + if (d->callTime % 20 == 0) + emit updateSkypeOut();//update the skype out + ++d->callTime; + //Do not break, do that as well + case csOnHold: + ++d->totalTime; + default: + ;//Get rid of that stupid warning about not handled value in switch + } + const QString &activeTime = KGlobal::locale()->formatTime(QTime().addSecs(d->callTime / 2), true, true); + const QString &totalTime = KGlobal::locale()->formatTime(QTime().addSecs(d->totalTime / 2), true, true); + TimeLabel->setText(i18n("%1 active\n%2 total").arg(activeTime).arg(totalTime)); +} + +void SkypeCallDialog::skypeOutInfo(int balance, const QString ¤cy) { + float part;//How to change the balance before showing (multiply by this) + QString symbol;//The symbol of the currency is + int digits; + if (currency == "EUR") { + part = 0.01;//It's in cent's not in euros + symbol = i18n("€"); + digits = 2; + } else { + CreditLabel->setText(i18n("Skypeout inactive")); + return; + } + float value = balance * part; + CreditLabel->setText(KGlobal::locale()->formatMoney(value, symbol, digits)); +} + +void SkypeCallDialog::chatUser() { + d->account->chatUser(d->userId); +} + +void SkypeCallDialog::callBack() { + deleteLater();//close this window + + d->account->makeCall(d->userId); +} + + +#include "skypecalldialog.moc" diff --git a/plugins/skype/skypecalldialog.h b/plugins/skype/skypecalldialog.h new file mode 100644 index 0000000..9b0405b --- /dev/null +++ b/plugins/skype/skypecalldialog.h @@ -0,0 +1,103 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Michal Vaner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +#ifndef SKYPECALLDIALOG_H +#define SKYPECALLDIALOG_H + +#include + +class SkypeAccount; +class SkypeCallDialogPrivate; + +/** + * This class is a window that can control a call (show information about it, hang up, hold, ...) + * @author Michal Vaner (Vorner) + */ +class SkypeCallDialog : public SkypeCallDialogBase +{ + Q_OBJECT + private: + SkypeCallDialogPrivate *d; + ///Start timeout to close + void closeLater(); + private slots: + ///Close it after timeout after finishing the call + void deathTimeout(); + ///Update the call info now + void updateCallInfo(); + ///Call the user back + void callBack(); + protected slots: + ///The accept button was clicked, accept the call + virtual void acceptCall(); + ///Hold or release the call + virtual void holdCall(); + ///Hang up the call + virtual void hangUp(); + ///Start chat to the user + virtual void chatUser(); + protected: + ///I want to know when I'm closed + virtual void closeEvent(QCloseEvent *e); + public: + /** + * Constructor + */ + SkypeCallDialog(const QString &callId, const QString &userId, SkypeAccount *account); + ///Destructor + ~SkypeCallDialog(); + public slots: + ///Update the status of call and disable/enable the right buttons and show it in the labels + void updateStatus(const QString &callId, const QString &status); + ///Updates an error message when some error occurred + void updateError(const QString &callId, const QString &status); + /** + * Incoming skype-out balance info + * @param balance How much of that ddoes user have + * @param currency What currency is it (actually only euro-cents are used) + */ + void skypeOutInfo(int balance, const QString ¤cy); + signals: + /** + * accept an incoming call + * @param callId What call is it + */ + void acceptTheCall(const QString &callId); + /** + * Hang up this call for me, please + * @param callId What call are we talking about + */ + void hangTheCall(const QString &callId); + /** + * Hold or resume a call (depending on its actual status + * @param callId What call are we tlking about + */ + void toggleHoldCall(const QString &callId); + /** + * Tell me the skype out balance, please + */ + void updateSkypeOut(); + /** + * This is emited when a call dialog is closed and is going to be deleted + * @param callId Id of it's call + */ + void callFinished(const QString &callId); +}; + +#endif diff --git a/plugins/skype/skypecalldialogbase.ui b/plugins/skype/skypecalldialogbase.ui new file mode 100644 index 0000000..1fb4932 --- /dev/null +++ b/plugins/skype/skypecalldialogbase.ui @@ -0,0 +1,300 @@ + +SkypeCallDialogBase + + + SkypeCallDialogBase + + + + 0 + 0 + 430 + 235 + + + + Skype Call + + + false + + + + unnamed + + + + layout3 + + + + unnamed + + + + NameLabel + + + + + + WordBreak|AlignVCenter + + + Partners name + + + Name of the other person of call (or list of names if the call is conference). + + + + + textLabel1 + + + Name: + + + AlignVCenter|AlignRight + + + Partners + + + Name + + + + + textLabel2 + + + Time: + + + AlignVCenter|AlignRight + + + Time elapsed + + + together. + + + + + CreditLabel + + + + + + WordBreak|AlignVCenter + + + Skype-out credits left + + + Skype-ou credits left + + + + + TimeLabel + + + + + + WordBreak|AlignVCenter + + + Time elapsed + + + Total time elapsed by the call/<br />time elapsed by the call and on hold together. + + + + + StatusLabel + + + + + + WordBreak|AlignVCenter + + + + + textLabel1_2 + + + Status: + + + AlignVCenter|AlignRight + + + + + textLabel3 + + + Skype-out credits: + + + AlignVCenter|AlignRight + + + Skype-out credits left + + + Skype-ou credits left + + + + + + + layout9 + + + + unnamed + + + + spacer3 + + + Horizontal + + + Expanding + + + + 48 + 20 + + + + + + AcceptButton + + + Accept + + + + + + Accept call + + + Accept incoming call + + + + + HangButton + + + H&ang up + + + Finish the call + + + Terminate the call + + + + + HoldButton + + + H&old + + + Hold the call + + + Interrupt the call for a moment and resume (or hang up) it later + + + + + pushButton4 + + + Chat + + + + + + Open chat to the person + + + Open chat to the person you are talking with + + + + + spacer2 + + + Horizontal + + + Expanding + + + + 49 + 20 + + + + + + + + + + AcceptButton + clicked() + SkypeCallDialogBase + acceptCall() + + + HangButton + clicked() + SkypeCallDialogBase + hangUp() + + + HoldButton + clicked() + SkypeCallDialogBase + holdCall() + + + pushButton4 + clicked() + SkypeCallDialogBase + chatUser() + + + + acceptCall() + holdCall() + hangUp() + chatUser() + + + diff --git a/plugins/skype/skypechatsession.cpp b/plugins/skype/skypechatsession.cpp new file mode 100644 index 0000000..21b6681 --- /dev/null +++ b/plugins/skype/skypechatsession.cpp @@ -0,0 +1,222 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Michal Vaner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +#include "skypechatsession.h" +#include "skypeaccount.h" +#include "skypeprotocol.h" +#include "skypecontact.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +static SIM::MetaContact *dummyContacts = new SIM::MetaContact(); + +class ChatDummyContact : public SIM::Contact { + public: + ChatDummyContact(SkypeAccount *account, const QString &name) : SIM::Contact(account, name, dummyContacts) {}; + virtual SIM::ChatSession *manager (CanCreateFlags canCreate) {return 0L;}; +}; + +class SkypeChatSessionPrivate { + private: + ///Dummy contact representing this chat + SIM::Contact *dummyContact; + public: + ///Referenco to the protocol + SkypeProtocol *protocol; + ///Reference to the account + SkypeAccount *account; + ///Am I connected to the messageSent signal? + bool connectedSent; + ///ID of this chat session + QString chatId; + /** + * Constructor + * @param _protocol Reference to the Skype protocol + * @param _account Reference to the account this chat belongs to + */ + SkypeChatSessionPrivate(SkypeProtocol *_protocol, SkypeAccount *_account) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + //save given values + account = _account; + protocol = _protocol; + + connectedSent = false; + chatId = ""; + dummyContact = 0L; + }; + ///Is it multi-user chat? + bool isMulti; + ///Please give me a contact that stands for the whole chat so I can send it to it + SIM::Contact *getDummyContact() { + if (dummyContact) + return dummyContact; + else { + return dummyContact = new ChatDummyContact(account, chatId); + } + }; + ///The action to call the user(s) + KAction *callAction; + ///The contact if any (and one) + SkypeContact *contact; +}; + +static SIM::ContactPtrList constructList(SkypeContact *contact) { + SIM::ContactPtrList list;//create the contact + list.append(contact);//add there the contact + + return list;//and return the list +} + +SkypeChatSession::SkypeChatSession(SkypeAccount *account, SkypeContact *contact) : + SIM::ChatSession(account->myself(), constructList(contact), account->protocol(), (char *)0L) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + setInstance(KGenericFactory::instance()); + + //create the D-pointer + d = new SkypeChatSessionPrivate(account->protocol(), account); + SIM::ChatSessionManager::self()->registerChatSession( this ); + connect(this, SIGNAL(messageSent(SIM::Message&, SIM::ChatSession*)), this, SLOT(message(SIM::Message& )));//this will send the messages from this user going out + account->prepareChatSession(this); + d->isMulti = false; + + d->callAction = new KAction(i18n("Call"), QString::fromLatin1("call"), 0, this, SLOT(callChatSession()), actionCollection(), "callSkypeContactFromChat"); + connect(contact, SIGNAL(setCallPossible(bool )), d->callAction, SLOT(setEnabled(bool ))); + connect(this, SIGNAL(becameMultiChat(const QString&, SkypeChatSession* )), this, SLOT(disallowCall())); + + d->contact = contact; + + setMayInvite(true);//It is possible to invite people to chat with Skype + setXMLFile("skypechatui.rc"); +} + +SkypeChatSession::SkypeChatSession(SkypeAccount *account, const QString &session, const SIM::ContactPtrList &users) : + SIM::ChatSession(account->myself(), users, account->protocol(), (char *) 0L) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + setInstance(KGenericFactory::instance()); + + d = new SkypeChatSessionPrivate(account->protocol(), account); + SIM::ChatSessionManager::self()->registerChatSession(this); + connect(this, SIGNAL(messageSent(SIM::Message&, SIM::ChatSession*)), this, SLOT(message(SIM::Message& ))); + account->prepareChatSession(this); + d->isMulti = true; + d->chatId = session; + emit updateChatId("", session, this); + + + d->callAction = new KAction(i18n("Call"), QString::fromLatin1("call"), 0, this, SLOT(callChatSession()), actionCollection(), "callSkypeContactFromChat"); + disallowCall();//TODO I hope it will not be needed in future + + setMayInvite(true);//It is possible to invite people to chat with Skype + setXMLFile("skypechatui.rc"); +} + +SkypeChatSession::~SkypeChatSession() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + if (d->account->leaveOnExit() && (d->isMulti)) + emit leaveChat(d->chatId); + emit updateChatId(d->chatId, "", this); + delete d;//remove the D pointer +} + +void SkypeChatSession::message(SIM::Message &message) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + d->account->registerLastSession(this); + d->account->sendMessage(message, (d->isMulti) ? (d->chatId) : "");//send it + messageSucceeded(); +} + +void SkypeChatSession::setTopic(const QString &chat, const QString &topic) { + ///TODO This function +} + +void SkypeChatSession::joinUser(const QString &chat, const QString &userId) { + kdDebug(14311) << k_funcinfo << "Chat: " << chat << endl;//some debug info + + if (chat == d->chatId) { + addContact(d->account->getContact(userId)); + d->isMulti = true; + emit becameMultiChat(d->chatId, this); + } +} + +void SkypeChatSession::leftUser(const QString &chat, const QString &userId, const QString &reason) { + kdDebug(14311) << "User: " << userId<< k_funcinfo << endl;//some debug info + + if (chat == d->chatId) { + removeContact(d->account->getContact(userId), reason, SIM::Message::PlainText); + } +} + +void SkypeChatSession::setChatId(const QString &chatId) { + kdDebug(14311) << k_funcinfo << "ID: " << chatId << endl;//some debug info + + if (d->chatId != chatId) { + emit updateChatId(d->chatId, chatId, this); + d->chatId = chatId; + emit wantTopic(chatId); + } +} + +void SkypeChatSession::sentMessage(const QPtrList *recv, const QString &body) { + SIM::Message *mes; + /*if (recv->count() == 1) { + mes = new SIM::Message(d->account->myself(), *recv->begin(), body, SIM::Message::Outbound); + } else { + mes = new SIM::Message(d->account->myself(), d->account->myself(), body, SIM::Message::Outbound); + }*/ + mes = new SIM::Message(d->account->myself(), *recv, body, SIM::Message::Outbound); + appendMessage(*mes); + delete mes; +} + +void SkypeChatSession::disallowCall() { + d->callAction->setEnabled(false); + + if (d->contact) { + disconnect(d->contact, SIGNAL(setCallPossible(bool )), d->callAction, SLOT(setEnabled(bool ))); + d->contact = 0L; + } +} + +void SkypeChatSession::callChatSession() { + if (d->contact)///@todo find a better way to do it later to allow multiple people to call + d->contact->call(); +} + +void SkypeChatSession::inviteContact(const QString &contactId) { + if (d->chatId.isEmpty()) { + d->chatId = d->account->createChat(d->contact->contactId()); + emit updateChatId("", d->chatId, this); + } + + emit inviteUserToChat(d->chatId, contactId); +} + +#include "skypechatsession.moc" diff --git a/plugins/skype/skypechatsession.h b/plugins/skype/skypechatsession.h new file mode 100644 index 0000000..b6b9fa8 --- /dev/null +++ b/plugins/skype/skypechatsession.h @@ -0,0 +1,133 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Michal Vaner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ +#ifndef SKYPECHATSESSION_H +#define SKYPECHATSESSION_H + +#include + +class SkypeProtocol; +class SkypeAccount; +class SkypeContact; +class SkypeChatSessionPrivate; + +/** + * The chat session for the Skype protocol + * @author Michal Vaner (VORNER) + */ +class SkypeChatSession : public SIM::ChatSession +{ + Q_OBJECT + private: + ///The insides of the chat session + SkypeChatSessionPrivate *d; + private slots: + ///sends message to the skype user who this chat belongs to + void message(SIM::Message&); + /**This disables permanently the call button when the chat becomes a multi-user chat + * @todo make this unneeded and allow multiple-user calls + */ + void disallowCall(); + ///Do a call to all participants of the chat (in future, now it allows only one at onece) + void callChatSession(); + public: + /** + * Constructor. The chat session will be created with first message coming out. + * @param account The account it belongs to + * @param other The other side. There it no way user could create chat with more than one user at once. If user is invited to chat by someone, the other constructor should be used. It is automatically registered in the manager. + */ + SkypeChatSession(SkypeAccount *account, SkypeContact *other); + /** + * Constructor from chat session. + * Use this one if user is invited to an existing chat or if the first message in that chat was incoming message. The list of users will be loaded at startup. It is automatically registered in the manager. + * @param account The account this belongs to. + * @param session Identificator of the chat session in skype. The list of users will be loaded in startup and therefore they are not needed to be specified. + */ + SkypeChatSession(SkypeAccount *account, const QString &session, const SIM::ContactPtrList &contacts); + ///Destructor + ~SkypeChatSession(); + /** + * Invites a contact to the chat + * @param contactId What contact + */ + virtual void inviteContact(const QString &contactId); + public slots: + /** + * Update the chat topic + * @param chat What chat is it about? Maybe me? + * @param topic What to set as topic + */ + void setTopic(const QString &chat, const QString &topic); + /** + * Set this chat's ID + * @param chatId The new ID + */ + void setChatId(const QString &chatId); + /** + * Add new user to chat + * @param chat To know if he joined this chat + * @param userId ID of that user + */ + void joinUser(const QString &chat, const QString &userId); + /** + * Some user left the chat + * @param chat Is it this chat? + * @param userId ID of that user + * @param reason Why he left + */ + void leftUser(const QString &chat, const QString &userId, const QString &reason); + /** + * This will add message that has been sent out by this user + * @param recv List of receivers. If there are more than one, replaced by an dummy contact of that chat, because it does crash SIM otherwise + * @param body Text to show + */ + void sentMessage(const QPtrList *recv, const QString &body); + signals: + /** + * This is emited when it become a multi-user chat. It should be removed from the contact so when user clicks on the contact, new one with only that one should be created + * @param chatSession Identificator of the chat + * @param previousUser Id of the other user before it became a multichat or empty string if no such user ever was + * @param sender Pointer to the chat session that emited this + */ + void becameMultiChat(const QString &chatSession, SkypeChatSession *sender); + /** + * This is emited when there is an request to get a frindly name of a chat + * @param chat Id of that chat + */ + void wantTopic(const QString &chat); + /** + * This chat's ID has changed + * @param oldId What was before? If it is the first set of the ID, it is empty + * @param newId The new ID. If it is empty, it means that this chat is being deleted right now and should be removed from all lists + * @param sender Pointer to that chat + */ + void updateChatId(const QString &oldId, const QString &newId, SkypeChatSession *sender); + /** + * Request inviting user to a chat + * @param chatId What chat + * @param userId What user + */ + void inviteUserToChat(const QString &chatId, const QString &userId); + /** + * Request leaving the chat + * @param chatId What chat + */ + void leaveChat(const QString &chatId); +}; + +#endif diff --git a/plugins/skype/skypeconference.cpp b/plugins/skype/skypeconference.cpp new file mode 100644 index 0000000..fd66e3f --- /dev/null +++ b/plugins/skype/skypeconference.cpp @@ -0,0 +1,76 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Michal Vaner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +#include "skypeconference.h" +#include "skypecalldialog.h" + +#include +#include +#include +#include +#include + +class SkypeConferencePrivate { + public: + //my id + QString id; + //The layout + QHBoxLayout *layout; +}; + +SkypeConference::SkypeConference(const QString &id) : QDialog() { + kdDebug(14311) << k_funcinfo << endl; + + //create the d pointer + d = new SkypeConferencePrivate(); + + //some UI + setCaption(i18n("Conference Call")); + d->layout = new QHBoxLayout(this); + + //remember all things + d->id = id; + + //show myself + show(); +} + +SkypeConference::~SkypeConference() { + kdDebug(14311) << k_funcinfo << endl; + + //free all memory + delete d->layout; + delete d; +} + +void SkypeConference::closeEvent(QCloseEvent *) { + emit removeConference(d->id); + + deleteLater(); +} + +void SkypeConference::embedCall(SkypeCallDialog *dialog) { + dialog->hide(); + insertChild(dialog); + d->layout->add(dialog); + + connect(this, SIGNAL(destroyed()), dialog, SLOT(hangUp())); +} + +#include "skypeconference.moc" diff --git a/plugins/skype/skypeconference.h b/plugins/skype/skypeconference.h new file mode 100644 index 0000000..e34af9f --- /dev/null +++ b/plugins/skype/skypeconference.h @@ -0,0 +1,64 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Michal Vaner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ +#ifndef SKYPECONFERENCE_H +#define SKYPECONFERENCE_H + +#include + +class SkypeConferencePrivate; +class SkypeCallDialog; + +class QString; + +/** + * @author Michal Vaner + * @short Dialog to group calls + * This dialog can group calls that belongs + */ +class SkypeConference : public QDialog +{ + Q_OBJECT + private: + ///Here are stored the private things, just for better readibility + SkypeConferencePrivate *d; + protected: + ///Make a suicide when closed + virtual void closeEvent(QCloseEvent *e); + public: + /** + * Constructor, also shows itself + * @param id My ID + */ + SkypeConference(const QString &id); + ///Destrucotr + ~SkypeConference(); + /** + * Add a call to this group + * @param dialog What to add there + */ + void embedCall(SkypeCallDialog *dialog); + signals: + /** + * The conference is being removed right now + * @param conferenceId what conference + */ + void removeConference(const QString &conferenceId); +}; + +#endif diff --git a/plugins/skype/skypecontact.cpp b/plugins/skype/skypecontact.cpp new file mode 100644 index 0000000..9140a3d --- /dev/null +++ b/plugins/skype/skypecontact.cpp @@ -0,0 +1,421 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Michal Vaner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ +#include "skypecontact.h" +#include "skypeaccount.h" +#include "skypeprotocol.h" +#include "skypechatsession.h" +#include "skypedetails.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef enum { + osOffline, + osOnline, + osAway, + osNA, + osDND, + osSkypeOut, + osSkypeMe +} onlineStatus; + +typedef enum { + bsNotInList, + bsNoAuth, + bsInList +} buddyStatus; + +class SkypeContactPrivate { + public: + ///Full name of the contact + QString fullName; + ///Acount that this contact belongs to + SkypeAccount *account; + ///Is it some user or is it something special (myself contact or such) + bool user; + ///Online status + onlineStatus status; + ///Buddy status + buddyStatus buddy; + ///The chat session + SkypeChatSession *session; + ///The action to call the user + KAction *callContactAction; + ///Authorization action + KAction *authorizeAction; + ///Remove authorization action + KAction *disAuthorAction; + ///Block user action + KAction *blockAction; + ///The private phone + QString privatePhone; + ///The private mobile phone + QString privateMobile; + ///The work phone + QString workPhone; + ///The homepage + QString homepage; + ///The contacts sex + QString sex; +}; + +SkypeContact::SkypeContact(SkypeAccount *account, const QString &id, SIM::MetaContact *parent, bool user) + : SIM::Contact(account, id, parent, QString::null) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + d = new SkypeContactPrivate;//create the insides + d->session = 0L;//no session yet + d->account = account;//save the account for future, it will be needed + connect(this, SIGNAL(setCallPossible(bool )), this, SLOT(enableCall(bool ))); + account->prepareContact(this);//let the account prepare us + d->user = user; + + d->callContactAction = new KAction(i18n("Call Contact"), "call", KShortcut(), this, SLOT(call()), this, "call_contact"); + d->authorizeAction = new KAction(i18n("(Re)send Authorization To"), "mail_forward", KShortcut(), this, SLOT(authorize()), this, "authorize_contact"); + d->disAuthorAction = new KAction(i18n("Remove Authorization From"), "mail_delete", KShortcut(), this, SLOT(disAuthor()), this, "dis_authorize_contact"); + d->blockAction = new KAction(i18n("Block"), "cancel", KShortcut(), this, SLOT(block()), this, "block_contact"); + statusChanged();//This one takes care of disabling/enabling this action depending on the user's status. + + connect(this, SIGNAL(onlineStatusChanged(SIM::Contact*,const SIM::OnlineStatus&,const SIM::OnlineStatus&)), this, SLOT(statusChanged())); + if (account->canComunicate() && user) + emit infoRequest(contactId());//retrieve information + + setNickName(id);//Just default, should be replaced later by something.. + + setOnlineStatus(account->protocol()->Offline); +} + +SkypeContact::~SkypeContact() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + //free memory + delete d; +} + +SIM::ChatSession *SkypeContact::manager(SIM::Contact::CanCreateFlags CanCreate) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + if ((!d->session) && (CanCreate)) {//It is not there and I can create it + d->session = new SkypeChatSession(d->account, this); + connect(d->session, SIGNAL(destroyed()), this, SLOT(removeChat()));//Care about loosing the session + connect(d->session, SIGNAL(becameMultiChat(const QString&, SkypeChatSession* )), this, SLOT(removeChat()));//This means it no longer belongs to this user + } + + return d->session;//and return it +} + +void SkypeContact::serialize(QMap &serializedData, QMap &) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + serializedData["contactId"] = contactId();//save the ID +} + +void SkypeContact::requestInfo() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + if (d->user) + emit infoRequest(contactId());//just ask for the info +} + +void SkypeContact::setInfo(const QString &change) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + kdDebug(14311) << "info is: " << change << endl;//some debug info + + const QString &receivedProperty = change.section(' ', 0, 0).stripWhiteSpace().upper();//get the first part + if (receivedProperty == "FULLNAME") { + setProperty( SIM::Global::Properties::self()->fullName(), change.section(' ', 1).stripWhiteSpace() );//save the name + } else if (receivedProperty == "DISPLAYNAME") { + const QString &name = change.section(' ', 1).stripWhiteSpace();//get the name + if (name.isEmpty()) + setNickName( property( SIM::Global::Properties::self()->fullName() ).value().toString() ); + else + setNickName(name);//set the display name + } else if (receivedProperty == "ONLINESTATUS") {//The online status eather changed or we just logged in and I asked for it + const QString &status = change.section(' ', 1, 1).stripWhiteSpace().upper();//get the status + + if (status == "OFFLINE") { + d->status = osOffline; + } else if (status == "ONLINE") { + d->status = osOnline; + } else if (status == "AWAY") { + d->status = osAway; + } else if (status == "NA") { + d->status = osNA; + } else if (status == "DND") { + d->status = osDND; + } else if (status == "SKYPEOUT") { + d->status = osSkypeOut; + } else if (status == "SKYPEME") { + d->status = osSkypeMe; + } + + resetStatus(); + } else if (receivedProperty == "BUDDYSTATUS") { + int value = change.section(' ', 1, 1).stripWhiteSpace().toInt();//get the value + + switch (value) { + case 0: + d->buddy = bsNotInList; + break; + case 1: + d->buddy = bsNotInList; + return; + case 2: + d->buddy = bsNoAuth; + break; + case 3: + d->buddy = bsInList; + break; + } + + resetStatus(); + } else + { + QString propValue = change.section(' ', 1).stripWhiteSpace(); + if ( !propValue.isEmpty() ) + { + if ( receivedProperty == "PHONE_HOME" ) { + setProperty( d->account->protocol()->propPrivatePhone, change.section(' ', 1).stripWhiteSpace() ); + d->privatePhone = change.section(' ', 1).stripWhiteSpace(); + } else if ( receivedProperty == "PHONE_OFFICE" ) { + setProperty( d->account->protocol()->propWorkPhone, change.section(' ', 1).stripWhiteSpace() ); + d->workPhone = change.section(' ', 1).stripWhiteSpace(); + } else if ( receivedProperty == "PHONE_MOBILE" ) { + setProperty(d->account->protocol()->propPrivateMobilePhone, change.section(' ', 1).stripWhiteSpace()); + d->privateMobile = change.section(' ', 1).stripWhiteSpace(); + } else if ( receivedProperty == "HOMEPAGE" ) { + //setProperty( d->account->protocol()->propPrivateMobilePhone, change.section(' ', 1).stripWhiteSpace() ); << This is odd, isn't it? + d->homepage = change.section(' ', 1).stripWhiteSpace(); + } else if (receivedProperty == "SEX") { + if (change.section(' ', 1).stripWhiteSpace().upper() == "MALE") { + d->sex = i18n("Male"); + } else if (change.section(' ', 1).stripWhiteSpace().upper() == "FEMALE") { + d->sex = i18n("Female"); + } else + d->sex = ""; + } + } + } +} + +QString SkypeContact::formattedName() const { + if (!d->user) + return nickName(); + return d->fullName; +} + +void SkypeContact::resetStatus() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + SkypeProtocol * protocol = d->account->protocol();//get the protocol + + if (d->status == osSkypeOut) { + setOnlineStatus(protocol->Phone);//this is the SkypeOut contact, in many ways special + return; + } + + switch (d->buddy) { + case bsNotInList: + setOnlineStatus(protocol->NotInList); + return; + case bsNoAuth: + setOnlineStatus(protocol->NoAuth); + return; + case bsInList://just put there normal status + break; + } + + switch (d->status) { + case osOffline: + setOnlineStatus(protocol->Offline); + break; + case osOnline: + setOnlineStatus(protocol->Online); + break; + case osAway: + setOnlineStatus(protocol->Away); + break; + case osNA: + setOnlineStatus(protocol->NotAvailable); + break; + case osDND: + setOnlineStatus(protocol->DoNotDisturb); + break; + case osSkypeOut: + setOnlineStatus(protocol->Phone); + break; + case osSkypeMe: + setOnlineStatus(protocol->SkypeMe); + break; + } +} + +bool SkypeContact::isReachable() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + const SIM::OnlineStatus &st = d->account->myself()->onlineStatus(); + if ((st == d->account->protocol()->Offline) || (st == d->account->protocol()->Connecting)) + return false; + + switch (d->buddy) { + case bsNotInList: + case bsNoAuth://I do not know, weather he is online, but I will send it trough the server + return true; + case bsInList: + break;//Do it by online status + } + + switch (d->status) { + //case osOffline://he is offline + case osSkypeOut://This one can not get messages, it is skype-out contact + return false; + default://some kind of online + return true; + } +} + +void SkypeContact::removeChat() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + d->session = 0L;//it exists no more or it is no longer of this contact +} + +bool SkypeContact::hasChat() const { + return d->session;//does it have a chat session? +} + +void SkypeContact::receiveIm(const QString &message, const QString &chat) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + if (!hasChat()) { + manager(CanCreate);//create it + if (!hasChat())//something failed + return; + } + + SIM::Message mes(this, d->account->myself(), message, SIM::Message::Inbound);//create the message + d->session->setChatId(chat); + d->session->appendMessage(mes);//add it to the session +} + +QPtrList *SkypeContact::customContextMenuActions() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + if (d->account->myself() == this) + return 0L; + + QPtrList *actions = new QPtrList(); + + actions->append(d->callContactAction); + actions->append(d->authorizeAction); + actions->append(d->disAuthorAction); + actions->append(d->blockAction); + + return actions; +} + +void SkypeContact::enableCall(bool value) { + d->callContactAction->setEnabled(value); +} + +void SkypeContact::statusChanged() { + SkypeProtocol * protocol = d->account->protocol(); + const SIM::OnlineStatus &myStatus = (d->account->myself()) ? d->account->myself()->onlineStatus() : protocol->Offline; + if (d->account->canAlterAuth()) { + d->authorizeAction->setEnabled(true); + d->disAuthorAction->setEnabled(true); + d->blockAction->setEnabled(true); + } else { + d->authorizeAction->setEnabled(false); + d->disAuthorAction->setEnabled(false); + d->blockAction->setEnabled(false); + } + if (this == d->account->myself()) { + emit setCallPossible(false); + } else if ((myStatus == protocol->Online) || (myStatus == protocol->Away) || (myStatus == protocol->NotAvailable) || (myStatus == protocol->DoNotDisturb) || (myStatus == protocol->NoAuth) || (myStatus == protocol->NotInList) || (myStatus == protocol->Phone) || (myStatus == protocol->SkypeMe)) + emit setCallPossible(true); + else + emit setCallPossible(false); +} + +void SkypeContact::call() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + d->account->makeCall(this); +} + +void SkypeContact::connectionStatus(bool connected) { + if (connected) { + statusChanged(); + } else + emit setCallPossible(false); +} + +SkypeChatSession *SkypeContact::getChatSession() { + return d->session; +} + +bool SkypeContact::canCall() const { + if (!d->account->canComunicate()) + return false; + if (!d->callContactAction) + return false; + return d->callContactAction->isEnabled(); +} + +void SkypeContact::slotUserInfo() { + kdDebug(14311) << k_funcinfo << endl; + + (new SkypeDetails)->setNames(contactId(), nickName(), formattedName()).setPhones(d->privatePhone, d->privateMobile, d->workPhone).setHomepage(d->homepage).setAuthor(d->account->getAuthor(contactId()), d->account).setSex(d->sex).exec(); +} + +void SkypeContact::deleteContact() { + d->account->removeContact(contactId()); + deleteLater(); +} + +void SkypeContact::sync(unsigned int changed) { + kdDebug(14311) << k_funcinfo << endl; + + if (changed & MovedBetweenGroup) { + d->account->registerContact(contactId()); + } +} + +void SkypeContact::authorize() { + d->account->authorizeUser(contactId()); +} + +void SkypeContact::disAuthor() { + d->account->disAuthorUser(contactId()); +} + +void SkypeContact::block() { + d->account->blockUser(contactId()); +} + +#include "skypecontact.moc" diff --git a/plugins/skype/skypecontact.h b/plugins/skype/skypecontact.h new file mode 100644 index 0000000..d9ee277 --- /dev/null +++ b/plugins/skype/skypecontact.h @@ -0,0 +1,150 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Michal Vaner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ +#ifndef SKYPECONTACT_H +#define SKYPECONTACT_H + +#include + +class SkypeAccount; +class QString; +class SkypeContactPrivate; +namespace SIM { + class MetaContact; + class ChatSession; +} +class KAction; +template class QPtrList; +class SkypeChatSession; + +/** + * @author Michal Vaner (VORNER) + */ +class SkypeContact : public SIM::Contact +{ + Q_OBJECT + private: + ///some internal things + SkypeContactPrivate *d; + ///This examines all factors of users online status and sets the status acordingly + void resetStatus(); + private slots: + ///This will note that the session was destroyed and therefore can't be used again. As well used when the chat becomes multi-user so it no longer belongs to this contact + void removeChat(); + ///Enables or disables the call action depending on if it can be called or not. + void enableCall(bool value); + ///The status changed, so there should be update of the availiblity of some things + void statusChanged(); + public: + /** + * Constructor. + * @param account Account to which it belongs + * @param id ID of the new contact + * @param parent Metacontact to put it inside + */ + SkypeContact(SkypeAccount *account, const QString &id, SIM::MetaContact *parent, bool user = true); + /** + * Destructor. + */ + ~SkypeContact(); + /** + * Creates a chat session. + * @param flags Can I create it? + * @return Pointer to that session + */ + virtual SIM::ChatSession *manager(SIM::Contact::CanCreateFlags flags); + /** + * Save this contact (resp. set what should be saved and it will be written automatically by SIM) + */ + virtual void serialize(QMap &serializedData, QMap &addressBookData); + ///Returns full name for the contact + virtual QString formattedName() const; + ///Is it reachable now? + virtual bool isReachable(); + ///Does this contact has opened chat session? + bool hasChat() const; + ///Tell SIM which actions to show in the contact pop-up menu + QPtrList *customContextMenuActions(); + ///Give me actually existing chat session + SkypeChatSession *getChatSession(); + ///Can this contact be called now? + bool canCall() const; + private slots: + /** + * Authorize the user to see if I'm online + */ + void authorize(); + /** + * Remove authorization from that user + */ + void disAuthor(); + /** + * Block this user, no more messages + */ + void block(); + public slots: + /** + * Please ask for the contact information (emit infoReques with your name) + */ + void requestInfo(); + /** + * Chnages something in the contact. + * @param change What change was it? It looks like [property] [value] + */ + void setInfo(const QString &change); + /** + * This one showes message in the chat session. + * @param message The message to show + * @param chat The chat ID of the chat the message belongs to + */ + void receiveIm(const QString &message, const QString &chat); + /** + * connection status changed + * @param connected Are we connected now? + */ + void connectionStatus(bool connected); + ///This slot calls a contact + void call(); + /** + * This slot should show the user info + * TODO: Implement this + * Now it only shows a messagebox + */ + virtual void slotUserInfo(); + /** + * Remove the contact from skype server + */ + virtual void deleteContact(); + /** + * Save me to the Skype + */ + virtual void sync(unsigned int changed); + signals: + /** + * There is a request to get/refresh the contact info from skype + * @param contact Which contact wants it? + */ + void infoRequest(const QString &contact); + /** + * The possibility to call this contact has changed, so GUI should enable/disable some buttons. + * @param value Is it possible to call it now? + */ + void setCallPossible(bool value); +}; + +#endif diff --git a/plugins/skype/skypedetails.cpp b/plugins/skype/skypedetails.cpp new file mode 100644 index 0000000..3280f98 --- /dev/null +++ b/plugins/skype/skypedetails.cpp @@ -0,0 +1,88 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Michal Vaner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +#include "skypedetails.h" +#include "skypeaccount.h" + +#include +#include +#include +#include + +SkypeDetails::SkypeDetails() : SkypeDetailsBase() { + kdDebug(14311) << k_funcinfo << endl; +} + + +SkypeDetails::~SkypeDetails() { + kdDebug(14311) << k_funcinfo << endl; +} + +void SkypeDetails::closeEvent(QCloseEvent *) { + kdDebug(14311) << k_funcinfo << endl; + deleteLater(); +} + +void SkypeDetails::changeAuthor(int item) { + kdDebug(14311) << k_funcinfo << endl; + switch (item) { + case 0: + account->authorizeUser(idEdit->text()); + break; + case 1: + account->disAuthorUser(idEdit->text()); + break; + case 2: + account->blockUser(idEdit->text()); + break; + } +} + +SkypeDetails &SkypeDetails::setNames(const QString &id, const QString &nick, const QString &name) { + setCaption(i18n("Details for User %1").arg(id)); + idEdit->setText(id); + nickEdit->setText(nick); + nameEdit->setText(name); + return *this; +} + +SkypeDetails &SkypeDetails::setPhones(const QString &priv, const QString &mobile, const QString &work) { + privatePhoneEdit->setText(priv); + mobilePhoneEdit->setText(mobile); + workPhoneEdit->setText(work); + return *this; +} + +SkypeDetails &SkypeDetails::setHomepage(const QString &homepage) { + homepageEdit->setText(homepage); + return *this; +} + +SkypeDetails &SkypeDetails::setAuthor(int author, SkypeAccount *account) { + authorCombo->setCurrentItem(author); + this->account = account; + return *this; +} + +SkypeDetails &SkypeDetails::setSex(const QString &sex) { + sexEdit->setText(sex); + return *this; +} + +#include "skypedetails.moc" diff --git a/plugins/skype/skypedetails.h b/plugins/skype/skypedetails.h new file mode 100644 index 0000000..aaa8a72 --- /dev/null +++ b/plugins/skype/skypedetails.h @@ -0,0 +1,76 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Michal Vaner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ +#ifndef SKYPEDETAILS_H +#define SKYPEDETAILS_H + +#include + +class QString; +class SkypeAccount; + +/** + * @author Michal Vaner (VORNER) + * Dialog that shows users details + */ +class SkypeDetails : public SkypeDetailsBase { + Q_OBJECT + private: + SkypeAccount *account; + protected slots: + void changeAuthor(int item); + protected: + ///Make sure it is deleted after it is closed + void closeEvent(QCloseEvent *e); + public: + ///Just constructor + SkypeDetails(); + ///Only a destructor + ~SkypeDetails(); + public slots: + /** + * Sets the ID, the nick and the name + * @param id The ID of the user + * @param nick user's nick + * @param name user's full name + */ + SkypeDetails &setNames(const QString &id, const QString &nick, const QString &name); + /** + * Sets the phone numbers what will be showed + * @param priv The private phone number + * @param mobile The mobile phone + * @param work The work phone + */ + SkypeDetails &setPhones(const QString &priv, const QString &mobile, const QString &work); + /** + * Sets the homepage + * @param homepage The value to set + */ + SkypeDetails &setHomepage(const QString &homepage); + /** + * Sets the users authorization + * @param author The authorization - 0 = authorized, 1 = not authorized, 2 = blocked + */ + SkypeDetails &setAuthor(int author, SkypeAccount *account); + /** + * Sets the string to show in 'sex' edit box + */ + SkypeDetails &setSex(const QString &sex); +}; + +#endif diff --git a/plugins/skype/skypedetailsbase.ui b/plugins/skype/skypedetailsbase.ui new file mode 100644 index 0000000..9bc7f5e --- /dev/null +++ b/plugins/skype/skypedetailsbase.ui @@ -0,0 +1,277 @@ + +SkypeDetailsBase + + + SkypeDetailsBase + + + + 0 + 0 + 365 + 331 + + + + Users Details + + + + unnamed + + + + textLabel1 + + + Skype ID: + + + AlignVCenter|AlignRight + + + + + idEdit + + + true + + + + + privatePhoneEdit + + + true + + + + + layout4 + + + + unnamed + + + + spacer6 + + + Horizontal + + + Expanding + + + + 40 + 20 + + + + + + pushButton3 + + + &Close + + + + + spacer7 + + + Horizontal + + + Expanding + + + + 40 + 20 + + + + + + + + + Authorized + + + + + Not Authorized + + + + + Blocked + + + + authorCombo + + + + + textLabel5 + + + Mobile phone: + + + AlignVCenter|AlignRight + + + + + textLabel6 + + + Work phone: + + + AlignVCenter|AlignRight + + + + + homepageEdit + + + true + + + + + textLabel4 + + + Private phone: + + + AlignVCenter|AlignRight + + + + + textLabel7 + + + Is authorized: + + + AlignVCenter|AlignRight + + + + + mobilePhoneEdit + + + true + + + + + workPhoneEdit + + + true + + + + + textLabel2 + + + Nick: + + + AlignVCenter|AlignRight + + + + + nameEdit + + + true + + + + + nickEdit + + + true + + + + + textLabel3 + + + Full name: + + + AlignVCenter|AlignRight + + + + + textLabel1_2 + + + Homepage: + + + AlignVCenter|AlignRight + + + + + textLabel1_3 + + + Sex: + + + AlignVCenter|AlignRight + + + + + sexEdit + + + true + + + + + + + pushButton3 + clicked() + SkypeDetailsBase + close() + + + authorCombo + activated(int) + SkypeDetailsBase + changeAuthor(int) + + + + changeAuthor(int) + + + diff --git a/plugins/skype/skypeeditaccount.cpp b/plugins/skype/skypeeditaccount.cpp new file mode 100644 index 0000000..eef8dea --- /dev/null +++ b/plugins/skype/skypeeditaccount.cpp @@ -0,0 +1,158 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Michal Vaner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + + +#include "skypeeditaccount.h" +#include "skypeprotocol.h" +#include "skypeaccount.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class SkypeEditAccountPrivate { + public: + ///The protocol + SkypeProtocol *protocol; + ///The account + SkypeAccount *account; +}; + +skypeEditAccount::skypeEditAccount(SkypeProtocol *protocol, SIM::Account *account, QWidget *parent) : SkypeEditAccountBase(parent), SIMEditAccountWidget(account) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + d = new SkypeEditAccountPrivate();//the d pointer + d->protocol = protocol;//I may need the protocol later + + d->account = (SkypeAccount *) account;//save the account + + //Now, check weather it is existing account or just an old one to modify + if (account) {//it is old one + excludeCheck->setChecked(account->excludeConnect());//Check, weather it should be excluded + LaunchGroup->setButton(d->account->launchType);//set the launch type + AuthorCheck->setChecked(!d->account->author.isEmpty());//set the check box that allows you to change authorization + if (AuthorCheck->isChecked()) + AuthorEdit->setText(d->account->author);//set the name + MarkCheck->setChecked(d->account->getMarkRead());//set the get read mode + HitchCheck->setChecked(d->account->getHitchHike()); + ScanCheck->setChecked(d->account->getScanForUnread()); + CallCheck->setChecked(d->account->getCallControl()); + PingsCheck->setChecked(d->account->getPings()); + BusGroup->setButton(d->account->getBus()); + DBusCheck->setChecked(d->account->getStartDBus()); + LaunchSpin->setValue(d->account->getLaunchTimeout()); + CommandEdit->setText(d->account->getSkypeCommand()); + WaitSpin->setValue(d->account->getWaitBeforeConnect()); + if (d->account->closeCallWindowTimeout()) { + AutoCloseCallCheck->setChecked(true); + CloseTimeoutSpin->setValue(d->account->closeCallWindowTimeout()); + } else AutoCloseCallCheck->setChecked(false); + LeaveCheck->setChecked(d->account->leaveOnExit()); + const QString &startCallCommand = d->account->startCallCommand(); + StartCallCommandCheck->setChecked(!startCallCommand.isEmpty()); + StartCallCommandEdit->setText(startCallCommand); + WaitForStartCallCommandCheck->setChecked(d->account->waitForStartCallCommand()); + const QString &endCallCommand = d->account->endCallCommand(); + EndCallCommandCheck->setChecked(!endCallCommand.isEmpty()); + EndCallCommandEdit->setText(endCallCommand); + OnlyLastCallCommandCheck->setChecked(d->account->endCallCommandOnlyLast()); + const QString &incomingCommand = d->account->incomingCommand(); + IncomingCommandCheck->setChecked(!incomingCommand.isEmpty()); + IncomingCommandEdit->setText(incomingCommand); + } else { + //KMessageBox::information(this, i18n("Please note that this version of Skype plugin is a development version and it is probable it will cause more problems than solve. You have been warned"), i18n("Version info")); - I hope it is not needed any more + } +} + +skypeEditAccount::~skypeEditAccount() { + kdDebug(14311) << k_funcinfo << endl;//some debug info +} + +bool skypeEditAccount::validateData() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + if (d->protocol->hasAccount() && (!account())) {//he wants to create some account witch name is already used + KMessageBox::sorry(this, i18n("You can have only one skype account"), i18n("Wrong Information"));//Tell him to use something other + return false; + } + + return true;//It seems OK +} + +SIM::Account *skypeEditAccount::apply() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + //first, I need a pointer to that account + if (!account()) //it does not exist + setAccount(new SkypeAccount(d->protocol));//create a new one + SkypeAccount *skype = static_cast(account());//get the account + + //set it's values + skype->setExcludeConnect(excludeCheck->isChecked());//Save the "exclude from connection" setup + skype->launchType = LaunchGroup->selectedId();//get the type how to launch skype + if (AuthorCheck->isChecked()) + skype->author = AuthorEdit->text();//put there what user wrote + else + skype->author = "";//nothing unusual + skype->setHitchHike(HitchCheck->isChecked());//save the hitch hike mode and activat ethe new value + skype->setMarkRead(MarkCheck->isChecked());//set the mark read messages mode and activate it + skype->setScanForUnread(ScanCheck->isChecked()); + skype->setCallControl(CallCheck->isChecked()); + skype->setPings(PingsCheck->isChecked()); + skype->setBus(BusGroup->selectedId()); + skype->setStartDBus(DBusCheck->isChecked()); + skype->setLaunchTimeout(LaunchSpin->value()); + skype->setSkypeCommand(CommandEdit->text()); + skype->setWaitBeforeConnect(WaitSpin->value()); + skype->setLeaveOnExit(LeaveCheck->isChecked()); + if (AutoCloseCallCheck->isChecked()) { + skype->setCloseWindowTimeout(CloseTimeoutSpin->value()); + } else { + skype->setCloseWindowTimeout(0); + } + if (StartCallCommandCheck->isChecked()) { + skype->setStartCallCommand(StartCallCommandEdit->text()); + } else { + skype->setStartCallCommand(""); + } + skype->setWaitForStartCallCommand(WaitForStartCallCommandCheck->isChecked()); + if (EndCallCommandCheck->isChecked()) { + skype->setEndCallCommand(EndCallCommandEdit->text()); + } else { + skype->setEndCallCommand(""); + } + if (IncomingCommandCheck->isChecked()) { + skype->setIncomingCommand(IncomingCommandEdit->text()); + } else { + skype->setIncomingCommand(""); + } + + skype->setEndCallCommandOnlyForLast(OnlyLastCallCommandCheck->isChecked()); + skype->save();//save it to config + return skype;//return the account +} + +#include "skypeeditaccount.moc" diff --git a/plugins/skype/skypeeditaccount.h b/plugins/skype/skypeeditaccount.h new file mode 100644 index 0000000..3936cad --- /dev/null +++ b/plugins/skype/skypeeditaccount.h @@ -0,0 +1,65 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Michal Vaner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +#ifndef SKYPEEDITACCOUNT_H +#define SKYPEEDITACCOUNT_H + +#include +#include "editaccountwidget.h" + +class SkypeEditAccountPrivate; +class SkypeProtocol; + +/** + * @author Michal Vaner + * @short Skype account edit-widget + * This widget will be showed inside the add account wizard when adding skype account or in edit account dialog, when editing skype account. + */ +class skypeEditAccount : public SkypeEditAccountBase, public SIMEditAccountWidget +{ +Q_OBJECT + private: + ///Some internal things + SkypeEditAccountPrivate *d; + public: + /** + * Constructor. + * @param account The account we are editing. 0 if new should be created. + * @param parent Inside what it will be showed. + */ + skypeEditAccount(SkypeProtocol *protocol, SIM::Account *account, QWidget *parent = 0L); + /** + * Destructor. + */ + virtual ~skypeEditAccount(); + /** + * Check, weather the written data can be used. + * @return True if the data are OK, false if not. + */ + virtual bool validateData(); + /** + * Aply all changes. Will change the actual account or create new one, if no was given. + * @return Pointer to that account. + */ + virtual SIM::Account *apply(); + public slots: +}; + +#endif + diff --git a/plugins/skype/skypeeditaccountbase.ui b/plugins/skype/skypeeditaccountbase.ui new file mode 100644 index 0000000..9c3efbc --- /dev/null +++ b/plugins/skype/skypeeditaccountbase.ui @@ -0,0 +1,1125 @@ + +SkypeEditAccountBase + + + SkypeEditAccountBase + + + + 0 + 0 + 561 + 444 + + + + + 7 + 7 + 0 + 0 + + + + If you have problems with arts and sound, you can use this to turn off arts for the call only. There are scripts duing this bundled with the SIM plugin (somewhere in you kde_folder/share/apps/skype) you can use. + + + + unnamed + + + + TabWidget + + + + 1 + 1 + 0 + 0 + + + + + tab + + + &Basic Setup + + + + unnamed + + + + groupBox1 + + + Account Information + + + + unnamed + + + + layout6 + + + + unnamed + + + + excludeCheck + + + E&xclude from connection + + + Check this if you do not want to connect with other protocols + + + + + spacer7 + + + Horizontal + + + Expanding + + + + 71 + 20 + + + + + + + + + + groupBox3 + + + Important Note + + + + unnamed + + + + textLabel3 + + + + 5 + 5 + 0 + 0 + + + + NoFrame + + + Plain + + + 0 + + + <p align="left">This is just a bridge to external running skype. This hase some consequences, like you need running instance of skype and thet only one skype account is possible</p> + + + AutoText + + + + + + + spacer10_2 + + + Vertical + + + MinimumExpanding + + + + 20 + 0 + + + + + + + + TabPage + + + Lau&nch + + + + unnamed + + + + LaunchGroup + + + Launch Skype + + + 0 + + + You can set weather and when should SIM launch skype. + + + + unnamed + + + + LaunchNeededRadio + + + When &not running + + + true + + + + + LaunchNeverRadio + + + N&ever + + + + + + + layout5 + + + + unnamed + + + + textLabel1 + + + Command: + + + + + CommandEdit + + + artsdsp skype --use-session-dbus + + + + + + + layout12 + + + + unnamed + + + + textLabel1_4 + + + Launch timeout: + + + + + LaunchSpin + + + 60 + + + 3 + + + 30 + + + + + textLabel2_3 + + + s + + + + + spacer23 + + + Horizontal + + + Expanding + + + + 151 + 20 + + + + + + + + DBusCheck + + + false + + + Laun&ch DBus + + + Launches DBus when not running + + + This will start session DBus if connection is set to session and it is not running. The prefered way is to set it in startup script, thought, so this if off by default. + + + + + layout18 + + + + unnamed + + + + textLabel2_4 + + + Wait before connect: + + + + + WaitSpin + + + 120 + + + 0 + + + 10 + + + trying + + + trying + + + + + textLabel1_5 + + + s + + + + + spacer21 + + + Horizontal + + + Expanding + + + + 218 + 20 + + + + + + + + textLabel2 + + + If you get error that Skype was not found and it is running, check instructions at http://www.skype.com/community/devzone/SkypeAPIforLinux.html or use session bus. (start skype with --use-session-dbus) + + + WordBreak|AlignVCenter + + + + + spacer8 + + + Vertical + + + Expanding + + + + 20 + 30 + + + + + + + + TabPage + + + C&onnection + + + + unnamed + + + + groupBox3_2 + + + Authorization + + + Each application that wants to use skype must tell a name to it and user is asked weather to allow such application to access it.<br> +By default, SIM provides SIM as its name, but if you suspect another application that it access skype with this name, you can set another and disallow applications that tries to log in as SIM. + + + + unnamed + + + + AuthorCheck + + + &Non-standard authorization + + + + + AuthorEdit + + + false + + + + + + + BusGroup + + + Bus + + + 0 + + + What bus do you want to use + + + What bus do you want to use to connect to Skype.<br>Session: Your own, other people can not get to that. (use --use-session-dbus to start skype on that bus).<br>System: This one is shared by all people on the same computer. Oddly, this one is used by default by Skype.it.<br>You have to use the same as uses Skype + + + + unnamed + + + + radioButton4 + + + Sessi&on + + + true + + + + + radioButton5 + + + S&ystem + + + + + + + textLabel1_2 + + + Note that SIM will freeze while Skype asks you if it can let SIM in. This is usual and if you allow it for ever (check that "Remember" checkbox on the Skype's dialog), it will not happen again. + + + WordBreak|AlignVCenter + + + + + spacer7_2 + + + Vertical + + + Expanding + + + + 20 + 50 + + + + + + + + TabPage + + + &Activity + + + + unnamed + + + + HitchCheck + + + Hitchhike incoming &messages + + + true + + + Show all incoming messages + + + This will show all skype incoming messages. If this is off, they are showed only if the message belongs to chat that is started by SIM. + + + + + MarkCheck + + + Mar&k as read + + + true + + + This will mark incoming messages as read so if you have Skype set up not to automatically pop-up chats, it will not flash that exclamation icon. + + + + + ScanCheck + + + Scan f&or unread + + + true + + + If this is checked, SIM will ask Skype on login, if it has any unshowed messages and show them. This is handy if you start SIM later than Skype and Skype is configured not to show incoming messages. + + + + + CallCheck + + + S&how call control + + + true + + + Show call control window for all cals + + + This will show a call control window for every call (both incoming and outgoing). If it is off, you can call from SIM, byt you have to control that call from Skype. + + + + + layout9 + + + + unnamed + + + + spacer9 + + + Horizontal + + + Fixed + + + + 20 + 20 + + + + + + AutoCloseCallCheck + + + Autoc&lose + + + true + + + Auto close the call control window + + + This will close tha call control window automatically when the call finishes + + + + + spacer14 + + + Horizontal + + + Expanding + + + + 361 + 20 + + + + + + + + layout8 + + + + unnamed + + + + spacer10 + + + Horizontal + + + Expanding + + + + 31 + 20 + + + + + + textLabel1_3 + + + + 5 + 0 + 0 + 0 + + + + Timeout: + + + + + CloseTimeoutSpin + + + + 7 + 0 + 0 + 0 + + + + 120 + + + 1 + + + 5 + + + + + textLabel2_2 + + + + 5 + 0 + 0 + 0 + + + + s + + + + + spacer12 + + + Horizontal + + + Expanding + + + + 301 + 20 + + + + + + + + PingsCheck + + + Pi&ng Skype + + + true + + + If this is enabled, SIM keeps track of wether the Skype is running. + + + This keeps track of wether Skype is running. Turning this off makes only sence it you're trying to get some not-flooded debug output. + + + + + LeaveCheck + + + Leave on e&xit + + + true + + + Leave a chat on window exit + + + Leave a chat when it's chat window is closed. Makes difference only with multi-user chats, if it is unchecked, you will continue receiving messages from that chat even after closing the window. + + + + + spacer13 + + + Vertical + + + Expanding + + + + 20 + 70 + + + + + + + + TabPage + + + &Calls + + + + unnamed + + + + StartCallCommandCheck + + + E&xecute before call + + + + + layout7 + + + + unnamed + + + + spacer12_2 + + + Horizontal + + + Fixed + + + + 20 + 20 + + + + + + StartCallCommandEdit + + + false + + + + + + + layout8 + + + + unnamed + + + + spacer13_2 + + + Horizontal + + + Fixed + + + + 20 + 20 + + + + + + WaitForStartCallCommandCheck + + + false + + + Wait for fi&nish + + + This will wait before making/accepting the call for the command to finish + + + This will wait for the command to finish before accepting/making the call.<br> +Note that it will freeze SIM for the time. + + + + + + + EndCallCommandCheck + + + Execute after call + + + + + + + + layout9 + + + + unnamed + + + + spacer14_2 + + + Horizontal + + + Fixed + + + + 20 + 20 + + + + + + EndCallCommandEdit + + + false + + + + + + + layout10 + + + + unnamed + + + + spacer15 + + + Horizontal + + + Fixed + + + + 20 + 20 + + + + + + OnlyLastCallCommandCheck + + + false + + + Onl&y for last call + + + Ususally makes no difference, just when there are some other calls on hold, it is executend only for the last ended one. + + + + + + + IncomingCommandCheck + + + Execute on inco&ming call + + + + + layout12 + + + + unnamed + + + + spacer15_2 + + + Horizontal + + + Fixed + + + + 20 + 20 + + + + + + IncomingCommandEdit + + + false + + + + + + + textLabel1_6 + + + If you have problems with arts while calling, you can use this to turn off arts for the call (I bundled scripts doing that, somewhere in kde_folder/share/apps/skype, names call_start and call_end) + + + WordBreak|AlignVCenter + + + + + spacer16 + + + Vertical + + + Expanding + + + + 21 + 20 + + + + + + + + + + + AuthorCheck + toggled(bool) + AuthorEdit + setEnabled(bool) + + + CallCheck + toggled(bool) + AutoCloseCallCheck + setEnabled(bool) + + + AutoCloseCallCheck + toggled(bool) + CloseTimeoutSpin + setEnabled(bool) + + + CallCheck + toggled(bool) + AutoCloseCallCheck + setChecked(bool) + + + StartCallCommandCheck + toggled(bool) + StartCallCommandEdit + setEnabled(bool) + + + StartCallCommandCheck + toggled(bool) + WaitForStartCallCommandCheck + setEnabled(bool) + + + EndCallCommandCheck + toggled(bool) + EndCallCommandEdit + setEnabled(bool) + + + EndCallCommandCheck + toggled(bool) + OnlyLastCallCommandCheck + setEnabled(bool) + + + IncomingCommandCheck + toggled(bool) + IncomingCommandEdit + setEnabled(bool) + + + + diff --git a/plugins/skype/skypeeditaccountwidget.cpp b/plugins/skype/skypeeditaccountwidget.cpp new file mode 100644 index 0000000..b742e2d --- /dev/null +++ b/plugins/skype/skypeeditaccountwidget.cpp @@ -0,0 +1,17 @@ +// +// C++ Implementation: $MODULE$ +// +// Description: +// +// +// Author: SIM Developers , (C) 2005 +// +// Copyright: See COPYING file that comes with this distribution +// +// +#include "skypeeditaccountwidget.h" + +skypeEditAccountWidget::skypeEditAccountWidget(QWidget *parent, const char *name):skypeEditAccountWidget(parent, name) { +} + +#include "skypeeditaccountwidget.moc" diff --git a/plugins/skype/skypeprotocol.cpp b/plugins/skype/skypeprotocol.cpp new file mode 100644 index 0000000..3b7d026 --- /dev/null +++ b/plugins/skype/skypeprotocol.cpp @@ -0,0 +1,194 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Michal Vaner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ +#include "skypeprotocol.h" +#include "skypeeditaccount.h" +#include "skypeaccount.h" +#include "skypeaddcontact.h" +#include "skypecontact.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef KGenericFactory SkypeProtocolFactory; +K_EXPORT_COMPONENT_FACTORY( skype, SkypeProtocolFactory( "skype" ) ) + +class SkypeProtocolPrivate { + private: + public: + ///The "call contact" action + KAction *callContactAction; + ///Pointer to the account + SkypeAccount *account; + ///Constructor + SkypeProtocolPrivate() { + account = 0L;//no account yet + callContactAction = 0L; + } +}; + +SkypeProtocol::SkypeProtocol(QObject *parent, const char *name, const QStringList &) : + SIM::Protocol(SkypeProtocolFactory::instance(), parent, name),//create the parent + Offline(SIM::OnlineStatus::Offline, 0, this, 1, QString::null, i18n("Offline"), i18n("Offline"), SIM::OnlineStatusManager::Offline),//and online statuses + Online(SIM::OnlineStatus::Online, 1, this, 2, QString::null, i18n("Online"), i18n("Online"), SIM::OnlineStatusManager::Online), + SkypeMe(SIM::OnlineStatus::Online, 0, this, 3, "contact_ffc_overlay", i18n("Skype Me"), i18n("Skype Me"), SIM::OnlineStatusManager::FreeForChat), + Away(SIM::OnlineStatus::Away, 2, this, 4, "contact_away_overlay", i18n("Away"), i18n("Away"), SIM::OnlineStatusManager::Away), + NotAvailable(SIM::OnlineStatus::Away, 1, this, 5, "contact_xa_overlay", i18n("Not Available"), i18n("Not Available"), SIM::OnlineStatusManager::Away), + DoNotDisturb(SIM::OnlineStatus::Away, 0, this, 6, "contact_busy_overlay", i18n("Do Not Disturb"), i18n("Do Not Disturb"), SIM::OnlineStatusManager::Busy), + Invisible(SIM::OnlineStatus::Invisible, 0, this, 7, "contact_invisible_overlay", i18n("Invisible"), i18n("Invisible"), SIM::OnlineStatusManager::Invisible), + Connecting(SIM::OnlineStatus::Connecting, 0, this, 8, "skype_connect", i18n("Connecting")), + NotInList(SIM::OnlineStatus::Offline, 0, this, 9, "contact_unknown_overlay", i18n("Not in skype list")), + NoAuth(SIM::OnlineStatus::Offline, 0, this, 10, "contact_unknown_overlay", i18n("Not authorized")), + Phone(SIM::OnlineStatus::Online, 0, this, 11, "contact_phone_overlay", i18n("SkypeOut contact")), + /** Contact property templates */ + propFullName(SIM::Global::Properties::self()->fullName()), + propPrivatePhone(SIM::Global::Properties::self()->privatePhone()), + propPrivateMobilePhone(SIM::Global::Properties::self()->privateMobilePhone()), + propWorkPhone(SIM::Global::Properties::self()->workPhone()), + propLastSeen(SIM::Global::Properties::self()->lastSeen()) + +{ + kdDebug(14311) << k_funcinfo << endl;//some debug info + //create the d pointer + d = new SkypeProtocolPrivate(); + //add address book field + addAddressBookField("messaging/skype", SIM::Plugin::MakeIndexField); + + setXMLFile("skypeui.rc"); + + d->callContactAction = new KAction(i18n("Call (by Skype)"), QString::fromLatin1("call"), 0, this, SLOT(callContacts()), actionCollection(), "callSkypeContact"); + + updateCallActionStatus(); + connect(SIM::ContactList::self(), SIGNAL(metaContactSelected(bool)), this, SLOT(updateCallActionStatus())); +} + +SkypeProtocol::~SkypeProtocol() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + //release the memory + delete d; +} + +SIM::Account *SkypeProtocol::createNewAccount(const QString &) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + //just create one + return new SkypeAccount(this); +} + +AddContactPage *SkypeProtocol::createAddContactWidget(QWidget *parent, SIM::Account *account) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + return new SkypeAddContact(this, parent, (SkypeAccount *)account, 0L); +} + +SIMEditAccountWidget *SkypeProtocol::createEditAccountWidget(SIM::Account *account, QWidget *parent) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + return new skypeEditAccount(this, account, parent);//create the widget and return it +} + +void SkypeProtocol::registerAccount(SkypeAccount *account) { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + d->account = account; +} + +void SkypeProtocol::unregisterAccount() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + d->account = 0L;//forget everything about the account +} + +bool SkypeProtocol::hasAccount() const { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + return (d->account); +} + +SIM::Contact *SkypeProtocol::deserializeContact(SIM::MetaContact *metaContact, const QMap &serializedData, const QMap &) { + kdDebug(14311) << k_funcinfo << "Name: " << serializedData["contactId"] << endl;//some debug info + + QString contactID = serializedData["contactId"];//get the contact ID + + if (!d->account) { + kdDebug(14311) << "Account does not exists, skiping contact creation" << endl;//write error for debugging + return 0L;//create nothing + } + + return new SkypeContact(d->account, contactID, metaContact);//create the contact +} + +void SkypeProtocol::updateCallActionStatus() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + bool enab = false; + + if ((SIM::ContactList::self()->selectedMetaContacts().count() != 1) && ((!d->account) || (!d->account->ableMultiCall()))) { + d->callContactAction->setEnabled(false); + return; + } + + //Run trough all selected contacts and find if there is any skype contact + const QPtrList &selected = SIM::ContactList::self()->selectedMetaContacts(); + for (QPtrList::const_iterator met = selected.begin(); met != selected.end(); ++met) { + const QPtrList &metaCont = (*met)->contacts(); + for (QPtrList::const_iterator con = metaCont.begin(); con != metaCont.end(); ++con) { + if ((*con)->protocol() == this) {//This is skype contact, ask it if it can be called + SkypeContact *thisCont = static_cast (*con); + if (thisCont->canCall()) { + enab = true; + goto OUTSIDE; + } + } + } + } + OUTSIDE: + d->callContactAction->setEnabled(enab); +} + +void SkypeProtocol::callContacts() { + kdDebug(14311) << k_funcinfo << endl;//some debug info + + QString list; + + const QPtrList &selected = SIM::ContactList::self()->selectedMetaContacts(); + for (QPtrList::const_iterator met = selected.begin(); met != selected.end(); ++met) { + const QPtrList &metaCont = (*met)->contacts(); + for (QPtrList::const_iterator con = metaCont.begin(); con != metaCont.end(); ++con) { + if ((*con)->protocol() == this) {//This is skype contact, ask it if it can be called + SkypeContact *thisCont = static_cast (*con); + if (thisCont->canCall()) { + if (!list.isEmpty()) + list += ", "; + list += thisCont->contactId(); + } + } + } + } + + if (!list.isEmpty()) { + d->account->makeCall(list); + } +} + +#include "skypeprotocol.moc" diff --git a/plugins/skype/skypeprotocol.h b/plugins/skype/skypeprotocol.h new file mode 100644 index 0000000..cc24d68 --- /dev/null +++ b/plugins/skype/skypeprotocol.h @@ -0,0 +1,133 @@ +/* This file is part of the KDE project + Copyright (C) 2005 Michal Vaner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +#ifndef SKYPEPROTOCOL_H +#define SKYPEPROTOCOL_H + +#include "SIMprotocol.h" +#include + +class SkypeAccount; +class SkypeProtocolPrivate; + +namespace SIM { + class OnlineStatus; +}; + +#define LAUNCH_ALLWAYS 0 +#define LAUNCH_NEEDED 1 +#define LAUNCH_NEVER 2 + +/** + * @author Michal Vaner + * @short Protocol to use external skype + * This protocol is only binding for exteral skype program. The reason to write this was I did not like the skype as it was. + */ +class SkypeProtocol : public SIM::Protocol +{ + Q_OBJECT + private: + SkypeProtocolPrivate *d; + public: + const SIM::OnlineStatus Offline; + const SIM::OnlineStatus Online; + const SIM::OnlineStatus SkypeMe; + const SIM::OnlineStatus Away; + const SIM::OnlineStatus NotAvailable; + const SIM::OnlineStatus DoNotDisturb; + const SIM::OnlineStatus Invisible; + const SIM::OnlineStatus Connecting; + const SIM::OnlineStatus NotInList; + const SIM::OnlineStatus NoAuth; + const SIM::OnlineStatus Phone; + // contact properties +/* const SIM::ContactPropertyTmpl propAwayMessage; + const SIM::ContactPropertyTmpl propFirstName; + const SIM::ContactPropertyTmpl propLastName;*/ + const SIM::ContactPropertyTmpl propFullName; +// const SIM::ContactPropertyTmpl propEmailAddress; + const SIM::ContactPropertyTmpl propPrivatePhone; + const SIM::ContactPropertyTmpl propPrivateMobilePhone; + const SIM::ContactPropertyTmpl propWorkPhone; +// const SIM::ContactPropertyTmpl propWorkMobilePhone; + const SIM::ContactPropertyTmpl propLastSeen; + /** + * Constructor. This is called automatically on library load. + * @param parent Parent of the object. + * @param name Name of the object. + * @param args Arguments to allow creation by KGenericFactory. + * @see KGenericFactory + */ + SkypeProtocol(QObject *parent, const char *name, const QStringList &args); + /** + * Destructor. + */ + ~SkypeProtocol(); + /** + * Reimplementation of the methot that creates a new skype account. + * @param accountID ID of the account. + * @return At the moment NULL, but it will change soon. + */ + virtual SIM::Account *createNewAccount(const QString &accountID); + /** + * Reimplementation of the method that creates widget for adding contact to skype account. + * @param parent Parent widget. It will be showed inside. + * @param account Account to witch it aplies. + * @return At the moment NULL, but it will change soon. + */ + virtual AddContactPage *createAddContactWidget(QWidget *parent, SIM::Account *account); + /** + * Reimplementation of the method that creates widget for editing/creation of the skype account. + * @param account Account to what it applies. (0 means we create a new one) + * @param parent Parent widget. It will be showed inside it. + * @return NULL at the moment, but it will change soon. + */ + virtual SIMEditAccountWidget* createEditAccountWidget(SIM::Account *account, QWidget *parent); + /** + * Skype plugin allows only one skype account at once. This answers weather one exists or not. + * @return true if some account exists and false if not + */ + bool hasAccount() const; + /** + * Tells skype to remember this account + * @param account Pointer to the instance of the account + */ + void registerAccount(SkypeAccount *account); + /** + * Removes account is some exists + */ + void unregisterAccount(); + /** + * Creates a contact from provided data + * @param metaContact Metacontact to add the contact into + * @param serializedData Some data to store the contact + * @param addressBookData Data inside the address book + * @return Brand new loaded contact + */ + virtual SIM::Contact *deserializeContact(SIM::MetaContact *metaContact, const QMap &serializedData, const QMap &addressBokkData); + public slots: + /** + * This enables or disables the "Call by skype" action depending on weather a contact(s) are selected and have skype contacts + */ + void updateCallActionStatus(); + /** + * This calls all selected skype contacts + */ + void callContacts(); +}; + +#endif diff --git a/plugins/sms/CMakeLists.txt b/plugins/sms/CMakeLists.txt new file mode 100644 index 0000000..bf5328a --- /dev/null +++ b/plugins/sms/CMakeLists.txt @@ -0,0 +1,31 @@ +############### +# sms library # +############### +IF(BUILD_DROPPED) +SET(sms_SRCS + gsm_ta.cpp + serial.cpp + sms.cpp + smssetup.cpp +) + +SET(sms_HDRS + gsm_ta.h + serial.h + sms.h + smssetup.h +) + +SET(sms_UICS + smssetupbase.ui +) + +SET(sms_LIBS + _core +) + +# some needed include dirs +INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR}/plugins/_core) + +SIM_ADD_PLUGIN(sms) +ENDIF(BUILD_DROPPED) diff --git a/plugins/sms/gsm_ta.cpp b/plugins/sms/gsm_ta.cpp new file mode 100644 index 0000000..b45c5db --- /dev/null +++ b/plugins/sms/gsm_ta.cpp @@ -0,0 +1,680 @@ +/*************************************************************************** + gsm_ta.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + + Based on gsmlib by Peter Hofmann (software@pxh.de) + + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include + +#include + +#include "log.h" + +#include "gsm_ta.h" +#include "serial.h" +#include "sms.h" + +using namespace std; +using namespace SIM; + +const unsigned PING_TIMEOUT = 20000; +const unsigned UNKNOWN = (unsigned)(-1); + +const unsigned OP_PHONEBOOK = 0; +const unsigned OP_PHONEBOOK_ENTRY = 1; + +GsmTA::GsmTA(QObject *parent) + : QObject(parent) +{ + m_state = None; + m_bPing = false; + m_port = new SerialPort(this); + m_timer = new QTimer(this); + connect(m_timer, SIGNAL(timeout()), this, SLOT(ping())); + connect(m_port, SIGNAL(write_ready()), this, SLOT(write_ready())); + connect(m_port, SIGNAL(read_ready()), this, SLOT(read_ready())); + connect(m_port, SIGNAL(error()), this, SLOT(port_error())); +} + +GsmTA::~GsmTA() +{ +} + +bool GsmTA::open(const char *device, int baudrate, bool bXonXoff) +{ + m_state = Open; + return m_port->openPort(device, baudrate, bXonXoff, 100); +} + +void GsmTA::write_ready() +{ + switch (m_state){ + case Open: + at("Z"); + m_state = Init; + break; + default: + break; + } +} + +void GsmTA::read_ready() +{ + QByteArray line = m_port->readLine(); + if (!line.isEmpty() && (line[(int)line.length() - 1] == '\r')) + line = line.left(line.length() - 1); + if (!line.isEmpty()){ + Buffer b(line); + EventLog::log_packet(b, false, SMSPlugin::SerialPacket); + } + OpInfo opInfo; + unsigned value1; + unsigned value2; + switch (m_state){ + case Init: + if (!isOK(line)) + return; + m_state = Init2; + at("E0"); + break; + case Init2: + if (!isOK(line)) + return; + m_state = Init3; + at("+CMEE=1"); + break; + case Init3: + if (!isChatOK(line, "", true, true)) + return; + m_state = Init4; + at("+CMGF=0"); + break; + case Init4: + if (!isChatOK(line)) + return; + m_state = Init5; + at("+CLIP=1"); + break; + case Init5: + if (!isChatOK(line)) + return; + m_state = Init6; + at("+CBC"); + break; + case Init6: + if (!isChatResponse(line, "+CBC:", false)) + return; + value1 = normalize(getToken(m_response, ',')).toUInt(); + value2 = normalize(m_response).toUInt(); + emit charge(value1 != 0, value2); + m_state = Init7; + at("+CSQ"); + break; + case Init7: + if (!isChatResponse(line, "+CSQ:", false)) + return; + value1 = normalize(m_response).toUInt(); + if (value1 == 99) + value1 = 0; + emit quality(value1); + m_state = Info1; + at("+CGMI"); + break; + case Info1: + if (!isChatResponse(line, "+CGMI:", false)) + return; + m_manufacturer = m_response; + m_state = Info2; + at("+CGMM"); + break; + case Info2: + if (!isChatResponse(line, "+CGMM:", false)) + return; + m_model = m_response; + m_state = Info3; + at("+CGMR"); + break; + case Info3: + if (!isChatResponse(line, "+CGMR:", false)) + return; + m_revision = m_response; + m_state = Info4; + at("+CGSN"); + break; + case Info4: + if (!isChatResponse(line, "+CGSN:", false)) + return; + m_serialNumber = m_response; + m_state = Charset1; + at("+CSCS=\"UCS2\""); + break; + case Charset1: + if (!isChatResponse(line, "+CSCS:", false)) + return; + m_state = Charset2; + at("+CSCS?"); + break; + case Charset2: + if (!isChatResponse(line, "+CSCS:", false)) + return; + m_charset = normalize(m_response); + if (m_charset.length() && (m_charset[0] == '\"')){ + getToken(m_charset, '\"'); + m_charset = getToken(m_charset, '\"'); + } + m_state = OpInfo1; + at("+COPS=3,0"); + break; + case OpInfo1: + if (!isChatOK(line, "", true, true)) + return; + m_state = OpInfo2; + at("+COPS?"); + break; + case OpInfo2: + if (!isChatResponse(line, "+COPS:", false)) + return; + getToken(m_response, ','); + getToken(m_response, ','); + if (m_response.length() && (m_response[0] == '"')){ + getToken(m_response, '\"'); + m_operator = getToken(m_response, '\"'); + } + m_port->setTimeout(~0U); + m_state = Connected; + emit init_done(); + processQueue(); + break; + case Connected: + if (isError(line)) + return; + break; + case Ping: + if (m_bPing){ + if (!isChatResponse(line, "+CBC:", false)) + return; + value1 = normalize(getToken(m_response, ',')).toUInt(); + value2 = normalize(m_response).toUInt(); + emit charge(value1 != 0, value2); + m_bPing = false; + }else{ + if (!isChatResponse(line, "+CSQ:", false)) + return; + value1 = normalize(m_response).toUInt(); + if (value1 == 99) + value1 = 0; + emit quality(value1); + m_bPing = true; + } + m_port->setTimeout((unsigned)(-1)); + m_state = Connected; + processQueue(); + break; + case PhoneBook: + if (!isChatOK(line, "", true, true)) + return; + m_state = PhoneBook1; + at("+CPBS?"); + break; + case PhoneBook1: + if (!isChatResponse(line, "+CPBS:")) + return; + m_state = PhoneBook2; + getToken(m_response, ','); + m_book->m_used = normalize(getToken(m_response, ',')).toUInt(); + m_book->m_size = normalize(getToken(m_response, ',')).toUInt(); + at("+CPBR=?"); + break; + case PhoneBook2: + if (!isChatResponse(line, "+CPBR:")) + return; + parseEntriesList(getToken(m_response, ',')); + if (m_book->m_entries.empty() && m_book->m_size){ + for (unsigned i = 0; i < m_book->m_size; i++) + m_book->m_entries.push_back(true); + } + m_book->m_size = 0; + m_book->m_numberSize = getToken(m_response, ',').toUInt(); + m_book->m_nameSize = m_response.toUInt(); + if (m_queue.empty()){ + getNextEntry(); + break; + } + opInfo.oper = OP_PHONEBOOK_ENTRY; + m_queue.push_back(opInfo); + m_state = Connected; + processQueue(); + break; + case PhoneBook3: + if (!isChatResponse(line, "+CPBR:")) + return; + parseEntry(m_response); + if (m_queue.empty()){ + getNextEntry(); + break; + } + opInfo.oper = OP_PHONEBOOK_ENTRY; + m_queue.push_back(opInfo); + m_state = Connected; + processQueue(); + break; + default: + break; + } +} + +void GsmTA::ping() +{ + if (m_state != Connected) + return; + m_timer->stop(); + m_state = Ping; + if (m_bPing){ + at("+CBC"); + }else{ + at("+CSQ"); + } +} + +void GsmTA::port_error() +{ + m_timer->stop(); + emit error(); +} + +void GsmTA::at(const QByteArray &str, unsigned timeout) +{ + QByteArray cmd = "AT"; + cmd += str; + m_cmd = cmd; + Buffer b(cmd); + EventLog::log_packet(b, true, SMSPlugin::SerialPacket); + cmd += "\r\n"; + m_tries = 5; + m_response = ""; + m_port->writeLine(cmd.data(), timeout); +} + +bool GsmTA::isOK(const QByteArray &answer) +{ + if (isIncoming(answer)) + return false; + if (answer == "OK" || answer.contains("CABLE: GSM")) + return true; + if (--m_tries == 0) + emit error(); + return false; +} + +QByteArray GsmTA::normalize(const QByteArray &ans) +{ + QByteArray answer = ans; + size_t start = 0, end = answer.length(); + bool changed = true; + while (start < end && changed){ + changed = false; + if (isspace(answer[(int)start])){ + ++start; + changed = true; + }else if (isspace(answer[(int)end - 1])){ + --end; + changed = true; + } + } + answer = answer.mid(start, end - start); + return answer; +} + +bool GsmTA::isError(const QByteArray &ans) +{ + if (isIncoming(ans)) + return false; + QByteArray answer = normalize(ans); + if (answer.isEmpty()) + return false; + if (matchResponse(answer, "+CME ERROR:") || + matchResponse(answer, "+CMS ERROR:") || + matchResponse(answer, "ERROR")){ + emit error(); + return true; + } + return false; +} + +bool GsmTA::isChatOK(const QByteArray &ans, const char *response, bool bIgnoreErrors, bool bAcceptEmptyResponse) +{ + if (isIncoming(ans)) + return false; + QByteArray answer = normalize(ans); + if (answer.isEmpty() || (answer == m_cmd)) + return false; + if (matchResponse(answer, "+CME ERROR:") || + matchResponse(answer, "+CMS ERROR:") || + matchResponse(answer, "ERROR")){ + if (bIgnoreErrors) + return true; + emit error(); + return false; + } + if (bAcceptEmptyResponse && (answer == "OK")) + return true; + if (response == NULL){ + if (answer == "OK") + return true; + log(L_DEBUG, "Unexpected answer %s", answer.data()); + emit error(); + return false; + } + if (matchResponse(answer, response)) + return true; + log(L_DEBUG, "Unexpected answer %s", answer.data()); + emit error(); + return false; +} + +bool GsmTA::isChatResponse(const QByteArray &ans, const char *response, bool bIgnoreErrors) +{ + if (isIncoming(ans)) + return false; + QByteArray answer = normalize(ans); + if (answer.isEmpty() || (answer == m_cmd)) + return false; + if (matchResponse(answer, "+CME ERROR:") || + matchResponse(answer, "+CMS ERROR:") || + matchResponse(answer, "ERROR")){ + if (bIgnoreErrors) + return true; + emit error(); + return false; + } + if (answer == "OK") + return true; + if (answer.isEmpty()) + return false; + matchResponse(answer, response); + if (!m_response.isEmpty()) + m_response += "\n"; + m_response += answer; + return false; +} + +bool GsmTA::isIncoming(const QByteArray &ans) +{ + QByteArray answer = normalize(ans); + if (matchResponse(answer, "+CLIP:")){ + QString number = getToken(answer, ','); + if (!number.isEmpty() && (number[0] == '\"')){ + getToken(number, '\"'); + number = getToken(number, '\"'); + } + unsigned type = answer.toUInt(); + if (type) + emit phoneCall(number); + return true; + } + return false; +} + +bool GsmTA::matchResponse(QByteArray &answer, const char *responseToMatch) +{ + if (answer.left(strlen(responseToMatch)) == responseToMatch){ + answer = normalize(answer.data() + strlen(responseToMatch)); + return true; + } + return false; +} + +QByteArray GsmTA::model() const +{ + QByteArray res = m_manufacturer; + if (!m_model.isEmpty()){ + if (!res.isEmpty()) + res += " "; + res += m_model; + } + return res; +} + +QByteArray GsmTA::oper() const +{ + return m_operator; +} + +void GsmTA::processQueue() +{ + if (m_queue.empty()){ + m_timer->setSingleShot( true ); + m_timer->start( PING_TIMEOUT ); + return; + } + m_timer->stop(); + list::iterator it = m_queue.begin(); + OpInfo info = *it; + m_queue.erase(it); + switch (info.oper){ + case OP_PHONEBOOK: + getPhoneBook(); + break; + case OP_PHONEBOOK_ENTRY: + getNextEntry(); + break; + default: + log(L_DEBUG, "Unknown oper"); + break; + } +} + +void GsmTA::getNextEntry() +{ + for (; m_book->m_size < m_book->m_entries.size(); m_book->m_size++){ + if (!m_book->m_entries[m_book->m_size]) + continue; + m_state = PhoneBook3; + QString cmd = "+CPBR="; + cmd += QString::number(m_book->m_size); + at(cmd.toLatin1(), 20000); + m_book->m_size++; + return; + } + if (m_bookType == 0){ + m_bookType = 1; + m_state = PhoneBook; + m_book = m_books + 1; + at("+CPBS=ME"); + return; + } + m_port->setTimeout((unsigned)(-1)); + m_state = Connected; + processQueue(); +} + +void GsmTA::parseEntry(const QByteArray &answ) +{ + QByteArray answer = normalize(answ); + unsigned index = getToken(answer, ',').toUInt(); + answer = normalize(answer); + if (answer.isEmpty()) + return; + QByteArray phone; + if (answer[0] == '\"'){ + getToken(answer, '\"'); + phone = getToken(answer, '\"'); + getToken(answer, ','); + }else{ + phone = getToken(answer, ','); + } + if (phone.isEmpty() || (phone == "EMPTY")) + return; + answer = normalize(answer); + getToken(answer, ','); + answer = normalize(answer); + QByteArray name; + if (answer[0] == '\"'){ + getToken(answer, '\"'); + name = getToken(answer, '\"'); + }else{ + name = getToken(name, ','); + } + QString nameString; + if (m_charset == "UCS2"){ + for (; name.length() >= 4; ){ + unsigned short unicode = (fromHex(name[0]) << 12) + + (fromHex(name[1]) << 8) + + (fromHex(name[2]) << 4) + + fromHex(name[3]); + name = name.mid(4); + nameString += QChar(unicode); + } + }else if (m_charset == "GSM"){ + nameString = gsmToLatin1(name); + }else{ + nameString = name; + } + if (nameString.isEmpty()) + return; + emit phonebookEntry(index, m_bookType, phone, nameString); +} + +void GsmTA::getPhoneBook() +{ + if (m_state != Connected){ + OpInfo info; + info.oper = OP_PHONEBOOK; + m_queue.push_back(info); + return; + } + m_bookType = 0; + m_timer->stop(); + m_state = PhoneBook; + m_book = m_books; + at("+CPBS=SM"); +} + +void GsmTA::parseEntriesList(const QByteArray &str) +{ + for (int i = 0; i < str.length(); i++){ + char c = str[i]; + if ((c >= '0') && (c <= '9')){ + unsigned n = c - '0'; + unsigned n1 = 0; + for (i++; str[i]; i++){ + c = str[i]; + if ((c < '0') || (c >= '9')) + break; + n = (n * 10) + (c - '0'); + } + if (str[i] == '-'){ + for (i++; str[i]; i++){ + c = *str; + if ((c < '0') || (c >= '9')) + break; + n1 = (n1 * 10) + (c - '0'); + } + }else{ + n1 = n; + } + if (n1 >= n){ + for (; n <= n1; n++){ + while (m_book->m_entries.size() <= n) + m_book->m_entries.push_back(false); + m_book->m_entries[n] = true; + } + } + } + } +} + +Phonebook::Phonebook() +{ + m_size = 0; + m_used = 0; + m_numberSize = 0; + m_nameSize = 0; +} + +// Latin-1 undefined character (code 172 (Latin-1 boolean not, "¬")) +const unsigned char NOP = 172; + +// GSM undefined character (code 16 (GSM Delta)) +const unsigned char GSM_NOP = 16; + +static unsigned char gsmToLatin1Table[] = + { + '@', 163, '$', 165, 232, 233, 249, 236, + 242, 199, 10, 216, 248, 13, 197, 229, + NOP, '_', NOP, NOP, NOP, NOP, NOP, NOP, + NOP, NOP, NOP, NOP, 198, 230, 223, 201, + ' ', '!', '"', '#', 164, '%', '&', '\'', + '(', ')', '*', '+', ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', ':', ';', '<', '=', '>', '?', + 161, 'A', 'B', 'C', 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 196, 214, 209, 220, 167, + 191, 'a', 'b', 'c', 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', + 'x', 'y', 'z', 228, 246, 241, 252, 224 + }; + +class GsmLatin1 +{ +public: + GsmLatin1(); + unsigned char latin1ToGsmTable[256]; +}; + +GsmLatin1::GsmLatin1() +{ + memset(latin1ToGsmTable, GSM_NOP, 256); + for (unsigned char i = 0; i < 128; i++){ + if (gsmToLatin1Table[i] == NOP) + continue; + latin1ToGsmTable[gsmToLatin1Table[i]] = i; + } +} + +static GsmLatin1 gsmTable; + +QByteArray GsmTA::gsmToLatin1(const QByteArray &str) +{ + QByteArray res; + for (unsigned char *p = (unsigned char*)str.data(); *p; p++){ + if (*p >= 0x80) + continue; + unsigned char c = gsmToLatin1Table[*p]; + if (c == NOP) + continue; + res += (char)c; + } + return res; +} + +QByteArray GsmTA::latin1ToGsm(const QByteArray &str) +{ + QByteArray res; + for (unsigned char *p = (unsigned char*)str.data(); *p; p++){ + unsigned char c = gsmTable.latin1ToGsmTable[*p]; //warning C6385: Invalid data: accessing 'gsmTable.latin1ToGsmTable', the readable size is '256' bytes, but '1001' bytes might be read: Lines: 671, 672, 673 + if (c == GSM_NOP) + continue; + res += (char)c; + } + return res; +} + diff --git a/plugins/sms/gsm_ta.h b/plugins/sms/gsm_ta.h new file mode 100644 index 0000000..a9b6ee1 --- /dev/null +++ b/plugins/sms/gsm_ta.h @@ -0,0 +1,137 @@ +/*************************************************************************** + gsm_ta.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _GSM_TA_H +#define _GSM_TA_H + +#include +#include +#include +#include +#include +#include "simapi.h" + +using namespace std; + +class SerialPort; +class QTimer; + +struct OpInfo +{ + unsigned oper; + string param; +}; + +class Phonebook +{ +public: + Phonebook(); + unsigned m_size; + unsigned m_used; + unsigned m_numberSize; + unsigned m_nameSize; + vector m_entries; +}; + +class GsmTA : public QObject +{ + Q_OBJECT +public: + GsmTA(QObject *parent); + ~GsmTA(); + bool open(const char *device, int baudrate, bool bXonXoff); + QByteArray model() const; + QByteArray oper() const; + void getPhoneBook(); + void setPhoneBookEntry(unsigned index, const QString &phone, const QString &name); +signals: + void init_done(); + void error(); + void phoneCall(const QString &phone); + void phonebookEntry(int index, int type, const QString &phone, const QString &name); + void quality(unsigned); + void charge(bool, unsigned); +protected slots: + void write_ready(); + void read_ready(); + void port_error(); + void ping(); +protected: + enum State + { + None, + Open, + Init, + Init2, + Init3, + Init4, + Init5, + Init6, + Init7, + Info1, + Info2, + Info3, + Info4, + Charset1, + Charset2, + OpInfo1, + OpInfo2, + Connected, + Ping, + PhoneBook, + PhoneBook1, + PhoneBook2, + PhoneBook3, + PhoneBookStore + }; + unsigned m_tries; + void at(const QByteArray &str, unsigned timeout=10000); + bool isOK(const QByteArray &answer); + bool isError(const QByteArray &answer); + bool isChatOK(const QByteArray &answer, const char *response = NULL, + bool bIgnoreErrors = false, bool bAcceptEmptyResponse = false); + bool isChatResponse(const QByteArray &answer, const char *response = NULL, + bool bIgnoreErrors = false); + bool isIncoming(const QByteArray &answer); + bool matchResponse(QByteArray &answer, const char *responseToMatch); + void processQueue(); + void parseEntriesList(const QByteArray &answ); + void parseEntry(const QByteArray &answ); + void getNextEntry(); + QByteArray normalize(const QByteArray &answ); + QByteArray gsmToLatin1(const QByteArray &str); + QByteArray latin1ToGsm(const QByteArray &str); + State m_state; + QByteArray m_cmd; + QByteArray m_manufacturer; + QByteArray m_model; + QByteArray m_revision; + QByteArray m_serialNumber; + QByteArray m_operator; + QByteArray m_response; + QByteArray m_charset; + listm_queue; + Phonebook m_books[2]; + Phonebook *m_book; + bool m_bPing; + unsigned m_bookType; + QTimer *m_timer; + SerialPort *m_port; +}; + +#endif + diff --git a/plugins/sms/serial.cpp b/plugins/sms/serial.cpp new file mode 100644 index 0000000..6dfab93 --- /dev/null +++ b/plugins/sms/serial.cpp @@ -0,0 +1,646 @@ +/*************************************************************************** + serial.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +//#ifdef HAVE_UNISTD_H +#include +//#endif + +#include "buffer.h" +#include "log.h" +#include "serial.h" + +using namespace SIM; + +#ifdef WIN32 + +#include + +const unsigned SERIAL_TIMEOUT = 1000; + +class SerialEvent : public QEvent +{ +public: + SerialEvent(unsigned reason); + unsigned reason() { return m_reason; } +protected: + unsigned m_reason; +}; + +SerialEvent::SerialEvent(unsigned reason) + : QEvent(User) +{ + m_reason = reason; +} + +const unsigned SerialEventComplete = 0; +const unsigned SerialEventError = 1; +const unsigned SerialEventTimeout = 2; + +enum PortState +{ + None, + Read, + Write, + StartRead, + StartWrite, + Setup, + Close +}; + +class SerialPortPrivate +{ +public: + SerialPortPrivate(SerialPort *port); + ~SerialPortPrivate(); + void close(); + Qt::HANDLE hPort; + Qt::HANDLE hEvent; + Qt::HANDLE hThread; + OVERLAPPED over; + QTimer *m_timer; + SerialPort *m_port; + int m_baudrate; + bool m_bXonXoff; + QByteArray m_line; + PortState m_state; + Buffer m_buff; + int m_time; + int m_read_time; + char m_char; +}; + +static DWORD __stdcall SerialThread(LPVOID lpParameter) +{ + log(L_DEBUG, "SerialThread: %X", (unsigned int)GetCurrentThreadId()); + SerialPortPrivate *p = (SerialPortPrivate*)lpParameter; + DWORD timeout = INFINITE; + for (;;){ + DWORD res = WaitForSingleObject(p->hEvent, timeout); + if ((res == WAIT_ABANDONED) || (p->m_state == Close)) + break; + timeout = INFINITE; + switch (p->m_state){ + case StartRead:{ + DWORD bytesReadn = 0; + memset(&p->over, 0, sizeof(p->over)); + p->over.hEvent = p->hEvent; + p->m_state = Read; + if (ReadFile(p->hPort, &p->m_char, 1, &bytesReadn, &p->over)) + break; + DWORD err = GetLastError(); + if (err != ERROR_IO_PENDING){ + p->m_state = None; + QApplication::postEvent(p->m_port, new SerialEvent(SerialEventError)); + }else{ + timeout = p->m_read_time; + } + break; + } + case StartWrite:{ + DWORD bytesWritten = 0; + memset(&p->over, 0, sizeof(p->over)); + p->over.hEvent = p->hEvent; + p->m_state = Write; + if (WriteFile(p->hPort, p->m_line.data(), p->m_line.length(), &bytesWritten, &p->over)) + break; + DWORD err = GetLastError(); + if (err != ERROR_IO_PENDING){ + p->m_state = None; + QApplication::postEvent(p->m_port, new SerialEvent(SerialEventError)); + }else{ + timeout = SERIAL_TIMEOUT; + } + break; + } + case Read: + case Write: + if (res == WAIT_TIMEOUT){ + QApplication::postEvent(p->m_port, new SerialEvent(SerialEventTimeout)); + }else{ + QApplication::postEvent(p->m_port, new SerialEvent(SerialEventComplete)); + } + break; + default: + break; + } + } + return 0; +} + +SerialPort::SerialPort(QObject *parent) + : QObject(parent) +{ + d = new SerialPortPrivate(this); + connect(d->m_timer, SIGNAL(timeout()), this, SLOT(timeout())); +} + +SerialPortPrivate::SerialPortPrivate(SerialPort *port) +{ + hPort = INVALID_HANDLE_VALUE; + hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + m_timer = new QTimer(NULL); + m_port = port; + m_state = None; + DWORD threadId; + hThread = CreateThread(NULL, 0, SerialThread, this, 0, &threadId); +} + +SerialPortPrivate::~SerialPortPrivate() +{ + close(); + delete m_timer; + m_state = Close; + SetEvent(hEvent); + CloseHandle(hEvent); + WaitForSingleObject(hThread, INFINITE); +} + +void SerialPortPrivate::close() +{ + if (hPort != INVALID_HANDLE_VALUE){ + CloseHandle(hPort); + hPort = INVALID_HANDLE_VALUE; + m_buff.init(0); + } + m_state = None; +} + +SerialPort::~SerialPort() +{ + delete d; +} + +void SerialPort::close() +{ + d->close(); +} + +void SerialPort::readReady(int) +{ +} + +bool SerialPort::openPort(const char *device, int baudrate, bool bXonXoff, int DTRtime) +{ + close(); + d->m_time = DTRtime; + d->m_baudrate = baudrate; + d->m_bXonXoff = bXonXoff; + QByteArray port; // = "\\\\.\\"; + port += device; + port += ":"; + d->hPort = CreateFileA(port.data(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); + if (d->hPort == INVALID_HANDLE_VALUE){ + close(); + log(L_WARN, "Can' open %s", port.data()); + return false; + } + FlushFileBuffers(d->hPort); + if (!EscapeCommFunction(d->hPort, CLRDTR)){ + close(); + log(L_WARN, "Clear DTR error"); + return false; + } + d->m_timer->setSingleShot(true); + d->m_timer->start(d->m_time); + return true; +} + +void SerialPort::timeout() +{ + if (d->m_state == Setup){ + if (!SetupComm(d->hPort, 1024, 1024)){ + log(L_WARN, "SetupComm error"); + close(); + emit error(); + return; + } + PurgeComm(d->hPort, PURGE_RXABORT | PURGE_RXCLEAR); + d->m_state = None; + emit write_ready(); + return; + } + if (!EscapeCommFunction(d->hPort, SETDTR)){ + log(L_WARN, "Set DTR error"); + close(); + emit error(); + return; + } + DCB dcb; + memset(&dcb, 0, sizeof(dcb)); + dcb.DCBlength = sizeof(dcb); + if (GetCommState(d->hPort, &dcb) == 0){ + log(L_WARN, "Get status error"); + close(); + emit error(); + return; + } + dcb.fBinary = TRUE; + dcb.BaudRate = d->m_baudrate; + dcb.fParity = FALSE; + dcb.Parity = 0; + dcb.ByteSize = 8; + dcb.StopBits = 0; + if (!d->m_bXonXoff) + { + dcb.fInX = FALSE; + dcb.fOutX = FALSE; + dcb.fOutxDsrFlow = FALSE; + dcb.fOutxCtsFlow = FALSE; + } + else + { + dcb.fInX = TRUE; + dcb.fOutX = TRUE; + dcb.fOutxDsrFlow = FALSE; + dcb.fOutxCtsFlow = FALSE; + } + dcb.fDtrControl = DTR_CONTROL_ENABLE; + dcb.fRtsControl = RTS_CONTROL_ENABLE; + if (SetCommState(d->hPort, &dcb) == 0){ + log(L_WARN, "Set status error"); + close(); + emit error(); + return; + } + d->m_state = Setup; + d->m_timer->setSingleShot(true); + d->m_timer->start(d->m_time); +} + +void SerialPort::writeLine(const char *data, unsigned read_time) +{ + if (d->hPort == INVALID_HANDLE_VALUE){ + emit error(); + return; + } + switch (d->m_state){ + case Read: + case Write: + CancelIo(d->hPort); + break; + default: + break; + } + d->m_state = StartWrite; + d->m_line = data; + d->m_read_time = read_time; + FlushFileBuffers(d->hPort); + SetEvent(d->hEvent); +} + +void SerialPort::setTimeout(unsigned read_time) +{ + switch (d->m_state){ + case Read: + case Write: + CancelIo(d->hPort); + break; + default: + break; + } + d->m_state = StartRead; + d->m_read_time = read_time; + SetEvent(d->hEvent); +} + +QByteArray SerialPort::readLine() +{ + QByteArray res; + if (d->hPort == INVALID_HANDLE_VALUE) + return res; + if (d->m_buff.scan("\n", res)){ + if (d->m_buff.readPos() == d->m_buff.writePos()) + d->m_buff.init(0); + } + return res; +} + +bool SerialPort::event(QEvent *e) +{ + if (e->type() != QEvent::User) + return QObject::event(e); + switch (static_cast(e)->reason()){ + case SerialEventComplete:{ + DWORD bytes; + if (GetOverlappedResult(d->hPort, &d->over, &bytes, true)){ + if (d->m_state == Read){ + d->m_buff.pack(&d->m_char, 1); + if (d->m_char == '\n') + emit read_ready(); + } + if (d->m_state == Write){ + emit write_ready(); + d->m_state = Read; + } + if (d->m_state == Read){ + d->m_state = StartRead; + SetEvent(d->hEvent); + } + break; + } + close(); + emit error(); + break; + } + case SerialEventTimeout:{ + log(L_WARN, "IO timeout"); + CancelIo(d->hPort); + close(); + emit error(); + break; + } + case SerialEventError:{ + log(L_WARN, "IO error"); + close(); + emit error(); + } + } + return true; +} + +void SerialPort::readTimeout() +{ +} + +QStringList SerialPort::devices() +{ + QStringList res; + for (unsigned i = 1; i <= 8; i++){ + QString port = "COM" + QString::number(i); + QString fullPort = "\\\\.\\" + port; + Qt::HANDLE hPort = CreateFile((LPCWSTR)fullPort.utf16(),GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL ); + if (hPort == INVALID_HANDLE_VALUE) + continue; + res.append(port); + CloseHandle(hPort); + } + return res; +} + +#else + +#include +#include +#include +#include +#include +#include + +enum PortState +{ + None, + Setup +}; + +class SerialPortPrivate +{ +public: + SerialPortPrivate(SerialPort*); + ~SerialPortPrivate(); + void close(); + QTimer *m_timer; + QTimer *m_readTimer; + QSocketNotifier *m_notify; + int fd; + int m_time; + int m_timeout; + int m_baudrate; + bool m_bXonXoff; + Buffer m_buf; + PortState m_state; +}; + +SerialPortPrivate::SerialPortPrivate(SerialPort *port) +{ + fd = -1; + m_timer = new QTimer(port); + m_readTimer = new QTimer(port); + m_timeout = 0; + m_notify = NULL; + m_state = None; +} + +SerialPortPrivate::~SerialPortPrivate() +{ + close(); +} + +void SerialPortPrivate::close() +{ + if (m_notify){ + delete m_notify; + m_notify = NULL; + } + if (fd == -1) + return; + ::close(fd); + fd = -1; +} + +SerialPort::SerialPort(QObject *parent) + : QObject(parent) +{ + d = new SerialPortPrivate(this); + connect(d->m_timer, SIGNAL(timeout()), this, SLOT(timeout())); + connect(d->m_readTimer, SIGNAL(timeout()), this, SLOT(readTimeout())); +} + +SerialPort::~SerialPort() +{ + delete d; +} + +bool SerialPort::openPort(const char *device, int baudrate, bool bXonXoff, int DTRtime) +{ + close(); + QByteArray fname = "/dev/"; + fname += device; + d->m_time = DTRtime; + d->m_baudrate = baudrate; + d->m_bXonXoff = bXonXoff; + d->fd = open(fname.data(), O_RDWR | O_NOCTTY | O_NONBLOCK); + if (d->fd == -1){ + log(L_WARN, "Can't open %s: %s", fname.data(), strerror(errno)); + return false; + } + int fdFlags; + if ((fdFlags = fcntl(d->fd, F_GETFL)) == -1){ + log(L_WARN, "Can't get flags %s: %s", fname.data(), strerror(errno)); + close(); + return false; + } + fdFlags &= ~O_NONBLOCK; + if (fcntl(d->fd, F_SETFL, fdFlags) == -1){ + log(L_WARN, "Can't set flags %s: %s", fname.data(), strerror(errno)); + close(); + return false; + } + int mctl = TIOCM_DTR; + if (ioctl(d->fd, TIOCMBIC, &mctl) < 0){ + log(L_WARN, "Clear failed %s: %s", fname.data(), strerror(errno)); + close(); + return false; + } + d->m_timer->setSingleShot( true ); + d->m_timer->start( d->m_time ); + return true; +} + +void SerialPort::readReady(int) +{ + d->m_readTimer->stop(); + for (;;){ + char c; + int res = read(d->fd, &c, 1); + if ((res < 0) && (errno == EAGAIN)) + return; + if (res <= 0){ + log(L_DEBUG, "Read serial error: %s", (res < 0) ? strerror(errno) : "connection closed"); + close(); + emit error(); + return; + } + d->m_readTimer->setSingleShot( true ); + d->m_readTimer->start( d->m_timeout ); + d->m_buf.pack(&c, 1); + if (c == '\n') + emit read_ready(); + } +} + +void SerialPort::close() +{ + d->close(); +} + +void SerialPort::writeLine(const char *data, unsigned timeRead) +{ + d->m_readTimer->stop(); + int res = write(d->fd, data, strlen(data)); + if (res < 0){ + log(L_DEBUG, "Write serial error: %s", strerror(errno)); + close(); + emit error(); + return; + } + d->m_timeout = timeRead; + d->m_readTimer->setSingleShot( true ); + d->m_readTimer->start( d->m_timeout ); +} + +void SerialPort::setTimeout(unsigned timeRead) +{ + d->m_readTimer->stop(); + d->m_timeout = timeRead; + d->m_readTimer->setSingleShot( true ); + d->m_readTimer->start( d->m_timeout ); +} + +QByteArray SerialPort::readLine() +{ + QByteArray res; + if (d->fd == -1) + return res; + if (d->m_buf.scan("\n", res)){ + if (d->m_buf.readPos() == d->m_buf.writePos()) + d->m_buf.init(0); + } + return res; +} + +void SerialPort::readTimeout() +{ + close(); + emit error(); +} + +void SerialPort::timeout() +{ + if (d->m_state == Setup){ + tcflush(d->fd, TCIFLUSH); + d->m_state = None; + d->m_notify = new QSocketNotifier(d->fd, QSocketNotifier::Read, this); + connect(d->m_notify, SIGNAL(activated(int)), this, SLOT(readReady(int))); + emit write_ready(); + return; + } + int mctl = TIOCM_DTR; + if (ioctl(d->fd, TIOCMBIS, &mctl) < 0){ + log(L_WARN, "setting DTR failed: %s", strerror(errno)); + close(); + return; + } + + struct termios t; + if (tcgetattr(d->fd, &t) < 0){ + log(L_WARN, "Getattr failed: %s", strerror(errno)); + close(); + return; + } + cfsetispeed(&t, d->m_baudrate); + cfsetospeed(&t, d->m_baudrate); + + t.c_iflag |= IGNPAR | (d->m_bXonXoff ? IXON | IXOFF : 0); + t.c_iflag &= ~(INPCK | ISTRIP | IMAXBEL | + (d->m_bXonXoff ? 0 : IXON | IXOFF) + | IXANY | IGNCR | ICRNL | IMAXBEL | INLCR | IGNBRK); + t.c_oflag &= ~(OPOST); + t.c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD | + (d->m_bXonXoff ? CRTSCTS : 0 )); + t.c_cflag |= CS8 | CREAD | HUPCL | (d->m_bXonXoff ? 0 : CRTSCTS) | CLOCAL; + t.c_lflag &= ~(ECHO | ECHOE | ECHOPRT | ECHOK | ECHOKE | ECHONL | + ECHOCTL | ISIG | IEXTEN | TOSTOP | FLUSHO | ICANON); + t.c_lflag |= NOFLSH; + t.c_cc[VMIN] = 1; + t.c_cc[VTIME] = 0; + t.c_cc[VSUSP] = 0; + + if(tcsetattr (d->fd, TCSANOW, &t) < 0){ + log(L_WARN, "Setattr failed: %s", strerror(errno)); + close(); + return; + } + d->m_state = Setup; + d->m_timer->setSingleShot( true ); + d->m_timer->start( d->m_time ); +} + +bool SerialPort::event(QEvent *e) +{ + return QObject::event(e); +} + +QStringList SerialPort::devices() +{ + QStringList res; + QDir dev("/dev"); + QStringList entries = dev.entryList( QStringList( "cuaa*" ), QDir::System); + for (QStringList::Iterator it = entries.begin(); it != entries.end(); ++it) + res.append(*it); + return res; +} + +#endif + diff --git a/plugins/sms/serial.h b/plugins/sms/serial.h new file mode 100644 index 0000000..97b7fa5 --- /dev/null +++ b/plugins/sms/serial.h @@ -0,0 +1,52 @@ +/*************************************************************************** + serial.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _SERIAL_H +#define _SERIAL_H + +#include + +class SerialPortPrivate; +class QEvent; + +class SerialPort : public QObject +{ + Q_OBJECT +public: + SerialPort(QObject *parent); + ~SerialPort(); + bool openPort(const char *device, int baudrate, bool bXonXoff, int DTRtime); + void close(); + static QStringList devices(); + void writeLine(const char *data, unsigned timeRead); + void setTimeout(unsigned timeRead); + QByteArray readLine(); +signals: + void write_ready(); + void read_ready(); + void error(); +protected slots: + void timeout(); + void readReady(int); + void readTimeout(); +protected: + bool event(QEvent *e); + SerialPortPrivate *d; +}; + +#endif + diff --git a/plugins/sms/sms.cpp b/plugins/sms/sms.cpp new file mode 100644 index 0000000..ad0fc5e --- /dev/null +++ b/plugins/sms/sms.cpp @@ -0,0 +1,638 @@ +/*************************************************************************** + sms.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "sms.h" +#include "smssetup.h" +#include "serial.h" +#include "gsm_ta.h" +#include "core.h" + +#include "maininfo.h" +#include "contacts/clientdataiterator.h" +#include "contacts/contact.h" +#include "clientmanager.h" + +#include +#include +#include +#include + +using namespace SIM; + +const unsigned COL_TYPE = 3; + +static DataDef _smsUserData[] = + { + { "", DATA_ULONG, 1, DATA(6) }, // Sign + { "", DATA_ULONG, 1, 0 }, // LastSend + { "", DATA_UTF, 1, 0 }, // Name + { "", DATA_UTF, 1, 0 }, + { "", DATA_ULONG, 1, 0 }, // Index + { "", DATA_ULONG, 1, 0 }, // Type + { NULL, DATA_UNKNOWN, 0, 0 } + }; + +Plugin *createSMSPlugin(unsigned base, bool, Buffer*) +{ + Plugin *plugin = new SMSPlugin(base); + return plugin; +} + +static PluginInfo info = + { + 0, + 0, + VERSION, + createSMSPlugin, + PLUGIN_PROTOCOL + }; + +EXPORT_PROC PluginInfo* GetPluginInfo() +{ + return &info; +} + +unsigned SMSPlugin::SerialPacket = 0; + +static Message *createPhoneCall(Buffer *cfg) +{ + return new Message(MessagePhoneCall, cfg); +} + +static MessageDef defPhoneCall = + { + NULL, + NULL, + MESSAGE_INFO, + "Phone call", + "%n phone calls", + createPhoneCall, + NULL, + NULL + }; + +#if 0 +i18n("Phone call", "%n phone calls", 1); +#endif + +SMSPlugin::SMSPlugin(unsigned base) + : Plugin(base) +{ + SerialPacket = registerType(); + getContacts()->addPacketType(SerialPacket, "Serial port", true); + + Command cmd; + cmd->id = MessagePhoneCall; + cmd->text = I18N_NOOP("Phone call"); + cmd->icon = "phone"; + cmd->flags = COMMAND_DEFAULT; + cmd->param = &defPhoneCall; + EventCreateMessageType(cmd).process(); + + m_protocol = new SMSProtocol(this); + + qApp->installEventFilter(this); + setPhoneCol(); +} + +SMSPlugin::~SMSPlugin() +{ + removePhoneCol(); + delete m_protocol; + getContacts()->removePacketType(SerialPacket); + EventRemoveMessageType(MessagePhoneCall).process(); +} + +void SMSPlugin::setPhoneCol() +{ + QWidgetList list = QApplication::topLevelWidgets(); + Q_FOREACH(QWidget *w, list) { + QList l = qFindChildren(w); + Q_FOREACH(MainInfo *obj,l) { + setPhoneCol(obj); + } + } +} + +void SMSPlugin::removePhoneCol() +{ + QWidgetList list = QApplication::topLevelWidgets(); + Q_FOREACH(QWidget *w, list) { + QList l = qFindChildren(w); + Q_FOREACH(MainInfo *obj,l) { + removePhoneCol(obj); + } + } +} + +void SMSPlugin::setPhoneCol(MainInfo *w) +{ + w->lstPhones->addColumn(" "/*, 16*/); +} + +void SMSPlugin::removePhoneCol(MainInfo *w) +{ + //w->lstPhones->removeColumn(COL_TYPE); +} + +bool SMSPlugin::eventFilter(QObject *obj, QEvent *e) +{ + if (e->type() == QEvent::ChildAdded){ + QChildEvent *ce = static_cast(e); + if (ce->child()->inherits("MainInfo")) + setPhoneCol(static_cast(ce->child())); + } + return QObject::eventFilter(obj, e); +} + +SMSProtocol::SMSProtocol(Plugin *plugin) + : Protocol(plugin) +{ +} + +SMSProtocol::~SMSProtocol() +{ +} + +ClientPtr SMSProtocol::createClient(Buffer *cfg) +{ + ClientPtr sms = ClientPtr(new SMSClient(this, cfg)); + getClientManager()->addClient(sms); + return sms; +} + +static CommandDef sms_descr = + CommandDef ( + 0, + I18N_NOOP("SMS"), + "SMS", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + PROTOCOL_NOPROXY | PROTOCOL_TEMP_DATA | PROTOCOL_NODATA | PROTOCOL_NO_AUTH, + NULL, + QString::null + ); + +const CommandDef *SMSProtocol::description() +{ + return &sms_descr; +} + +static CommandDef sms_status_list[] = + { + CommandDef ( + STATUS_ONLINE, + I18N_NOOP("Online"), + "SMS_online", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + STATUS_OFFLINE, + I18N_NOOP("Offline"), + "SMS_offline", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef () + }; + +const CommandDef *SMSProtocol::statusList() +{ + return sms_status_list; +} + +const DataDef *SMSProtocol::userDataDef() +{ + return _smsUserData; +} + +static DataDef smsClientData[] = + { +#ifdef WIN32 + { "Port", DATA_STRING, 1, "COM1" }, +#else + { "Port", DATA_STRING, 1, "cuaa0" }, +#endif + { "BaudRate", DATA_ULONG, 1, DATA(19200) }, + { "XonXoff", DATA_BOOL, 1, 0 }, + { "", DATA_ULONG, 1, 0 }, // Charge + { "", DATA_BOOL, 1, 0 }, // Charging + { "", DATA_ULONG, 1, 0 }, // Quality + { NULL, DATA_UNKNOWN, 0, 0 } + }; + +SMSClient::SMSClient(Protocol *protocol, Buffer *cfg) + : TCPClient(protocol, cfg) +{ + load_data(smsClientData, &data, cfg); + m_ta = NULL; + m_call = NULL; + m_callTimer = new QTimer(this); + connect(m_callTimer, SIGNAL(timeout()), this, SLOT(callTimeout())); +} + +SMSClient::~SMSClient() +{ + free_data(smsClientData, &data); +} + +QByteArray SMSClient::getConfig() +{ + QByteArray cfg = TCPClient::getConfig(); + QByteArray my_cfg = save_data(smsClientData, &data); + if (!my_cfg.isEmpty()){ + if (!cfg.isEmpty()) + cfg += "\n"; + cfg += my_cfg; + } + return cfg; +} + +QByteArray SMSClient::model() const +{ + if (getState() == Connected) + return m_ta->model(); + return QByteArray(); +} + +QByteArray SMSClient::oper() const +{ + if (getState() == Connected) + return m_ta->oper(); + return QByteArray(); +} + +QString SMSClient::name() +{ + QString res = "SMS."; + if (getState() == Connected){ + res += model(); + res += " "; + res += oper(); + }else{ + res += getDevice(); + } + return res; +} + +QString SMSClient::dataName(void*) +{ + return QString(); +} + +bool SMSClient::isMyData(clientData*&, Contact*&) +{ + return false; +} + +bool SMSClient::createData(clientData*&, Contact*) +{ + return false; +} + +void SMSClient::setupContact(Contact*, void*) +{ +} + +bool SMSClient::send(Message*, void*) +{ + return false; +} + +bool SMSClient::canSend(unsigned type, void *data) +{ + if ((data == NULL) && (type == MessageSMS)) + return true; + return false; +} + +QWidget *SMSClient::setupWnd() +{ + return new SMSSetup(NULL, this); +} + +const unsigned MAIN_INFO = 1; + +static CommandDef cfgSmsWnd[] = + { + CommandDef ( + MAIN_INFO, + " ", + "SMS", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef () + }; + +CommandDef *SMSClient::configWindows() +{ + QString title = name(); + int n = title.indexOf('.'); + if (n > 0) + title = title.left(n) + ' ' + title.mid(n + 1); + cfgSmsWnd[0].text_wrk = title; + return cfgSmsWnd; +} + +QWidget *SMSClient::configWindow(QWidget *parent, unsigned id) +{ + if (id == MAIN_INFO) + return new SMSSetup(parent, this); + return NULL; +} + +void SMSClient::packet_ready() +{ +} + +void SMSClient::disconnected() +{ + setStatus(STATUS_OFFLINE); +} + +void SMSClient::setStatus(unsigned status) +{ + if (status == STATUS_OFFLINE){ + Contact *contact; + ContactList::ContactIterator it; + while ((contact = ++it) != NULL) + contact->clientData.freeClientData(this); + if (m_ta){ + delete m_ta; + m_ta = NULL; + } + return; + } + if (m_ta) + return; + m_ta = new GsmTA(this); + connect(m_ta, SIGNAL(init_done()), this, SLOT(init())); + connect(m_ta, SIGNAL(error()), this, SLOT(error())); + connect(m_ta, SIGNAL(phonebookEntry(int, int, const QString&, const QString&)), this, SLOT(phonebookEntry(int, int, const QString&, const QString&))); + connect(m_ta, SIGNAL(charge(bool, unsigned)), this, SLOT(charge(bool, unsigned))); + connect(m_ta, SIGNAL(quality(unsigned)), this, SLOT(quality(unsigned))); + connect(m_ta, SIGNAL(phoneCall(const QString&)), this, SLOT(phoneCall(const QString&))); + if (!m_ta->open(qPrintable(getDevice()), getBaudRate(), getXonXoff())){ + error_state("Can't open port", 0); + return; + } +} + +void SMSClient::phonebookEntry(int index, int type, const QString &phone, const QString &name) +{ + bool bNew = false; + Contact *contact; + ContactList::ContactIterator it; + while ((contact = ++it) != NULL){ + smsUserData *data; + ClientDataIterator itd(contact->clientData); + while ((data = tosmsUserData(++itd)) != NULL){ + if (name == data->Name.str()) + break; + } + if (data) + break; + } + if (contact == NULL){ + contact = getContacts()->contactByPhone(phone); + if (contact->getFlags() & CONTACT_TEMPORARY){ + bNew = true; + contact->setFlags(contact->getFlags() & ~CONTACT_TEMPORARY); + contact->setName(name); + } + } + QString phones = contact->getPhones(); + bool bFound = false; + while (!phones.isEmpty()){ + QString item = getToken(phones, ';', false); + QString number = getToken(item, ','); + if (number == phone){ + bFound = true; + break; + } + } + if (!bFound){ + phones = contact->getPhones(); + if (!phones.isEmpty()) + phones += ";"; + contact->setPhones(phones + phone + ",,2/-"); + } + smsUserData *data = tosmsUserData((SIM::clientData*)contact->clientData.createData(this)); // FIXME unsafe type conversion + data->Phone.str() = phone; + data->Name.str() = name; + data->Index.asULong() = index; + data->Type.asULong() = type; + if (bNew){ + EventContact e(contact, EventContact::eChanged); + e.process(); + } +} + +QString SMSClient::getServer() const +{ + return QString::null; +} + +unsigned short SMSClient::getPort() const +{ + return 0; +} + +void SMSClient::socketConnect() +{ + connect_ready(); + setStatus(STATUS_ONLINE); +} + +void SMSClient::error() +{ + QTimer::singleShot(0, this, SLOT(ta_error())); +} + +void SMSClient::ta_error() +{ + error_state(I18N_NOOP("Port error"), 0); +} + +void SMSClient::init() +{ + m_status = STATUS_ONLINE; + setState(Connected); + m_ta->getPhoneBook(); +} + +void SMSClient::charge(bool bCharge, unsigned capacity) +{ + bool bChange = false; + if (bCharge != getCharging()){ + bChange = true; + setCharging(bCharge); + } + if (capacity != getCharge()){ + bChange = true; + setCharge(capacity); + } + if (bChange){ + EventClientChanged(this).process(); + } +} + +void SMSClient::quality(unsigned quality) +{ + if (quality != getQuality()){ + setQuality(quality); + EventClientChanged(this).process(); + } +} + +void SMSClient::phoneCall(const QString &number) +{ + if (m_call && (number == m_callNumber)) + return; + if (m_call){ + m_callTimer->stop(); + EventMessageDeleted(m_call).process(); + delete m_call; + m_call = NULL; + } + m_callNumber = number; + m_call = new Message(MessagePhoneCall); + if (!number.isEmpty()){ + bool bNew = false; + Contact *contact = getContacts()->contactByPhone(number); + if (contact->getFlags() & CONTACT_TEMPORARY){ + bNew = true; + contact->setFlags(contact->getFlags() & ~CONTACT_TEMPORARY); + contact->setName(number); + } + QString phones = contact->getPhones(); + bool bFound = false; + while (!phones.isEmpty()){ + QString item = getToken(phones, ';', false); + QString phone = getToken(item, ','); + if (number == phone){ + bFound = true; + break; + } + } + if (!bFound){ + phones = contact->getPhones(); + if (!phones.isEmpty()) + phones += ";"; + contact->setPhones(phones + number + ",,2/-"); + } + if (bNew){ + EventContact e(contact, EventContact::eChanged); + e.process(); + } + m_call->setContact(contact->id()); + } + m_call->setFlags(MESSAGE_RECEIVED | MESSAGE_TEMP); + EventMessageReceived e(m_call); + if (e.process()){ + m_call = NULL; + return; + } + m_bCall = false; + m_callTimer->start(12000); +} + +void SMSClient::callTimeout() +{ + if (m_bCall){ + m_bCall = false; + return; + } + if (m_call == NULL) + return; + EventMessageDeleted(m_call).process(); + delete m_call; + m_call = NULL; + m_callTimer->stop(); + m_callNumber = ""; +} + +smsUserData* SMSClient::tosmsUserData(SIM::clientData * data) +{ + // This function is used to more safely preform type conversion from SIM::clientData* into smsUserData* + // It will at least warn if the content of the structure is not smsUserData + // Brave wariors may uncomment abort() function call to know for sure about wrong conversion ;-) + if (! data) return NULL; + if (data->Sign.asULong() != SMS_SIGN) + { + QString Signs[] = { + "Unknown(0)" , // 0x0000 + "ICQ_SIGN", // 0x0001 + "JABBER_SIGN", // 0x0002 + "MSN_SIGN", // 0x0003 + "Unknown(4)" // 0x0004 + "LIVEJOURNAL_SIGN",// 0x0005 + "SMS_SIGN", // 0x0006 + "Unknown(7)", // 0x0007 + "Unknown(8)", // 0x0008 + "YAHOO_SIGN" // 0x0009 + }; + QString Sign; + if (data->Sign.toULong()<=9) // is always >=0 as it is unsigned int + Sign = Signs[data->Sign.toULong()]; + else + Sign = QString("Unknown(%1)").arg(Sign.toULong()); + + log(L_ERROR, + "ATTENTION!! Unsafly converting %s user data into SMS_SIGN", + qPrintable(Sign)); +// abort(); + } + return (smsUserData*) data; +} + +QWidget *SMSClient::searchWindow(QWidget*) +{ + return NULL; +} + diff --git a/plugins/sms/sms.h b/plugins/sms/sms.h new file mode 100644 index 0000000..862ed57 --- /dev/null +++ b/plugins/sms/sms.h @@ -0,0 +1,133 @@ +/*************************************************************************** + sms.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _SMS_H +#define _SMS_H + +#include "contacts/client.h" +#include "log.h" +#include "socket/socket.h" +#include "socket/tcpclient.h" + +class SMSProtocol; +class GsmTA; +class MainInfo; + +const unsigned long SMSCmdBase = 0x00080000; +const unsigned long MessagePhoneCall = SMSCmdBase; + +class SMSPlugin : public QObject, public SIM::Plugin +{ + Q_OBJECT +public: + SMSPlugin(unsigned); + virtual ~SMSPlugin(); + static unsigned SerialPacket; + void setPhoneCol(); + void setPhoneCol(MainInfo *w); + void removePhoneCol(); + void removePhoneCol(MainInfo *w); +protected: + bool eventFilter(QObject *obj, QEvent *e); + SMSProtocol *m_protocol; +}; + +class SMSProtocol : public SIM::Protocol +{ +public: + SMSProtocol(SIM::Plugin *plugin); + ~SMSProtocol(); + SIM::ClientPtr createClient(Buffer *cfg); + const SIM::CommandDef *description(); + const SIM::CommandDef *statusList(); + const SIM::DataDef *userDataDef(); +}; + +struct SMSClientData +{ + SIM::Data Device; + SIM::Data BaudRate; + SIM::Data XonXoff; + SIM::Data Charge; + SIM::Data Charging; + SIM::Data Quality; +}; + +const unsigned SMS_SIGN = 6; + +struct smsUserData : public SIM::clientData +{ + SIM::Data Name; + SIM::Data Phone; + SIM::Data Index; + SIM::Data Type; +}; + +class SMSClient : public SIM::TCPClient +{ + Q_OBJECT +public: + SMSClient(SIM::Protocol *protocol, Buffer *cfg); + ~SMSClient(); + PROP_STR(Device); + PROP_ULONG(BaudRate); + PROP_BOOL(XonXoff); + PROP_ULONG(Charge); + PROP_BOOL(Charging); + PROP_ULONG(Quality); + QByteArray model() const; + QByteArray oper() const; + smsUserData* tosmsUserData(SIM::clientData * data); +protected slots: + void error(); + void init(); + void ta_error(); + void charge(bool, unsigned); + void quality(unsigned); + void phoneCall(const QString&); + void phonebookEntry(int, int, const QString&, const QString&); + void callTimeout(); +protected: + virtual QString getServer() const; + virtual unsigned short getPort() const; + virtual void setStatus(unsigned status); + virtual void disconnected(); + virtual QByteArray getConfig(); + virtual QString name(); + virtual QString dataName(void*); + virtual bool isMyData(SIM::clientData*&, SIM::Contact*&); + virtual bool createData(SIM::clientData*&, SIM::Contact*); + virtual void setupContact(SIM::Contact*, void *data); + virtual bool send(SIM::Message*, void *data); + virtual bool canSend(unsigned type, void *data); + virtual void packet_ready(); + virtual void socketConnect(); + virtual SIM::CommandDef *configWindows(); + virtual QWidget *configWindow(QWidget *parent, unsigned id); + virtual QWidget *setupWnd(); + virtual QWidget *searchWindow(QWidget*); + virtual void contactInfo(void *,unsigned long &,unsigned int &,QString &,QSet *) {} + QString m_callNumber; + QTimer *m_callTimer; + SIM::Message *m_call; + bool m_bCall; + GsmTA *m_ta; + SMSClientData data; +}; + +#endif + diff --git a/plugins/sms/sms.rc b/plugins/sms/sms.rc new file mode 100644 index 0000000..45f7abe --- /dev/null +++ b/plugins/sms/sms.rc @@ -0,0 +1,97 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,9,6,0 + PRODUCTVERSION 0,9,6,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Vladimir Shutoff\0" + VALUE "FileDescription", "SMS plugin\0" + VALUE "FileVersion", "0, 9, 6, 0\0" + VALUE "InternalName", "sms\0" + VALUE "LegalCopyright", "Copyright © 2002-2003\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "sms.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "SIM\0" + VALUE "ProductVersion", "0, 9, 6, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/sms/sms.vcproj b/plugins/sms/sms.vcproj new file mode 100644 index 0000000..90cec8c --- /dev/null +++ b/plugins/sms/sms.vcproj @@ -0,0 +1,550 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/sms/smssetup.cpp b/plugins/sms/smssetup.cpp new file mode 100644 index 0000000..9a1e8d1 --- /dev/null +++ b/plugins/sms/smssetup.cpp @@ -0,0 +1,89 @@ +/************************************************************************** + smssetup.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "misc.h" + +#include "sms.h" +#include "smssetup.h" +#include "serial.h" + +using namespace SIM; + +SMSSetup::SMSSetup(QWidget *parent, SMSClient *client) : QWidget(parent) +{ + setupUi(this); + m_client = client; + QStringList res = SerialPort::devices(); + unsigned n = 0; + unsigned cur = 0; + if (m_client->getState() == Client::Connected){ + cmbPort->insertItem(INT_MAX,m_client->getDevice()); + cur = 0; + n++; + } + for (QStringList::Iterator it = res.begin(); it != res.end(); ++it, n++){ + if ((*it) == m_client->getDevice()) + cur = cmbPort->count(); + cmbPort->insertItem(INT_MAX,*it); + } + cmbPort->setCurrentIndex(cur); + for (unsigned i = 0; i < (unsigned)(cmbBaud->count()); i++){ + if (cmbBaud->itemText(i).toULong() == m_client->getBaudRate()){ + cmbBaud->setCurrentIndex(i); + } + } + chkXonXoff->setChecked(m_client->getXonXoff()); + if (client->getState() == Client::Connected){ + if (client->getCharging()){ + lblCharge->setText(i18n("Charging:")); + }else{ + lblCharge->setText(i18n("Battery:")); + } + barCharge->setValue(client->getCharge()); + barQuality->setValue(client->getQuality()); + edtModel->setReadOnly(true); + edtModel->setText(client->model()); + edtOper->setText(client->oper()); + }else{ + tabSMS->removeTab(tabSMS->indexOf(tabPhone)); + } + QTimer::singleShot(0, this, SLOT(init())); +} + +void SMSSetup::apply() +{ + m_client->setDevice(cmbPort->currentText()); + m_client->setBaudRate(cmbBaud->currentText().toULong()); + m_client->setXonXoff(chkXonXoff->isChecked()); +} + +void SMSSetup::apply(Client*, void*) +{ +} + +void SMSSetup::init() +{ + emit okEnabled(true); +} + diff --git a/plugins/sms/smssetup.h b/plugins/sms/smssetup.h new file mode 100644 index 0000000..37db944 --- /dev/null +++ b/plugins/sms/smssetup.h @@ -0,0 +1,45 @@ +/*************************************************************************** + smssetup.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _SMSSETUP_H +#define _SMSSETUP_H + +#include + +#include "contacts.h" + +#include "ui_smssetupbase.h" + +class SMSClient; + +class SMSSetup : public QWidget, public Ui::SMSSetup +{ + Q_OBJECT +public: + SMSSetup(QWidget*, SMSClient*); +signals: + void okEnabled(bool); +public slots: + void init(); + void apply(); + void apply(SIM::Client*, void*); +protected: + SMSClient *m_client; +}; + +#endif + diff --git a/plugins/sms/smssetupbase.ui b/plugins/sms/smssetupbase.ui new file mode 100644 index 0000000..b2429f4 --- /dev/null +++ b/plugins/sms/smssetupbase.ui @@ -0,0 +1,304 @@ + + + SMSSetup + + + + 0 + 0 + 334 + 241 + + + + SMSSetup + + + + 6 + + + 11 + + + + + + Hand&y + + + + 11 + + + 6 + + + + + Port: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + Baudrate: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + 6 + + + 0 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + + 6 + + + 0 + + + + + + 115200 + + + + + 38400 + + + + + 19200 + + + + + 9600 + + + + + 4800 + + + + + 2400 + + + + + 1200 + + + + + 600 + + + + + 300 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + Software handshake + + + + + + + + &Phone + + + + 11 + + + 6 + + + + + Model: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + Signal quality: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + Operator: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + 0 + + + + + + + + + + 0 + + + + + + + + + + + + + + + diff --git a/plugins/sms/xpm/simcard.xpm b/plugins/sms/xpm/simcard.xpm new file mode 100644 index 0000000..abe9981 --- /dev/null +++ b/plugins/sms/xpm/simcard.xpm @@ -0,0 +1,23 @@ +/* XPM */ +static const char *simcard[]={ +"16 16 4 1", +"# c #040000", +". c None", +"b c #dcd620", +"a c #ffffff", +"................", +"....#########...", +"...#aaaaaaaa#...", +"..#aaaaaaaaa#...", +"..#aaaaaaaaa#...", +"..#aabbbbbaa#...", +"..#aab...baa#...", +"..#aabbbbbaa#...", +"..#aab...baa#...", +"..#aabbbbbaa#...", +"..#aaaaaaaaa#...", +"..#aaaaaaaaa#...", +"..#aaaaaaaaa#...", +"..#aaaaaaaaa#...", +"..###########...", +"................"}; diff --git a/plugins/sound/CMakeLists.txt b/plugins/sound/CMakeLists.txt new file mode 100644 index 0000000..13f1729 --- /dev/null +++ b/plugins/sound/CMakeLists.txt @@ -0,0 +1,53 @@ +################# +# sound library # +################# +SET(sound_SRCS + sound.cpp + soundconfig.cpp + sounduser.cpp +) + +SET(sound_HDRS + sound.h + soundconfig.h + sounduser.h +) + +SET(sound_UICS + soundconfigbase.ui + sounduserbase.ui +) + +SET(sound_LIBS + ${QT_PHONON_LIBRARY} +) + +REMOVE_DEFINITIONS(-DQT3_SUPPORT) +REMOVE_DEFINITIONS(-DQT_3SUPPORT_LIB) +REMOVE_DEFINITIONS(-DQT3_SUPPORT_WARNINGS) +IF(QT_PHONON_FOUND) + SIM_ADD_PLUGIN(sound) +ELSE(QT_PHONON_FOUND) + MESSAGE(STATUS "Cannot build sound plugin because Phonon is missing on your system") +ENDIF(QT_PHONON_FOUND) + +# install new sounds with known licence +INSTALL(FILES sounds/added.ogg DESTINATION ${SIM_SOUND_DIR}) +INSTALL(FILES sounds/alert.ogg DESTINATION ${SIM_SOUND_DIR}) +INSTALL(FILES sounds/auth.ogg DESTINATION ${SIM_SOUND_DIR}) +INSTALL(FILES sounds/authrequest.ogg DESTINATION ${SIM_SOUND_DIR}) +INSTALL(FILES sounds/contacts.ogg DESTINATION ${SIM_SOUND_DIR}) +INSTALL(FILES sounds/contactrequest.ogg DESTINATION ${SIM_SOUND_DIR}) +INSTALL(FILES sounds/deleted.ogg DESTINATION ${SIM_SOUND_DIR}) +INSTALL(FILES sounds/error.ogg DESTINATION ${SIM_SOUND_DIR}) +INSTALL(FILES sounds/file.ogg DESTINATION ${SIM_SOUND_DIR}) +INSTALL(FILES sounds/filedone.ogg DESTINATION ${SIM_SOUND_DIR}) +INSTALL(FILES sounds/mailpager.ogg DESTINATION ${SIM_SOUND_DIR}) +INSTALL(FILES sounds/message.ogg DESTINATION ${SIM_SOUND_DIR}) +INSTALL(FILES sounds/msgsent.ogg DESTINATION ${SIM_SOUND_DIR}) +INSTALL(FILES sounds/refused.ogg DESTINATION ${SIM_SOUND_DIR}) +INSTALL(FILES sounds/sms.ogg DESTINATION ${SIM_SOUND_DIR}) +INSTALL(FILES sounds/startup.ogg DESTINATION ${SIM_SOUND_DIR}) +INSTALL(FILES sounds/url.ogg DESTINATION ${SIM_SOUND_DIR}) +INSTALL(FILES sounds/vip-online.ogg DESTINATION ${SIM_SOUND_DIR}) +INSTALL(FILES sounds/web.ogg DESTINATION ${SIM_SOUND_DIR}) diff --git a/plugins/sound/ogg.rules b/plugins/sound/ogg.rules new file mode 100644 index 0000000..7c80c05 --- /dev/null +++ b/plugins/sound/ogg.rules @@ -0,0 +1,19 @@ + + + + + + + + + diff --git a/plugins/sound/sound.cpp b/plugins/sound/sound.cpp new file mode 100644 index 0000000..6bf564c --- /dev/null +++ b/plugins/sound/sound.cpp @@ -0,0 +1,287 @@ +/*************************************************************************** + sound.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include "simapi.h" + +#include "exec.h" +#include "log.h" +#include "core.h" + +#include "sound.h" +#include "soundconfig.h" +#include "sounduser.h" +#include "contacts/contact.h" +#include "contacts/group.h" +#include "profile.h" +#include "profilemanager.h" + +using namespace std; +using namespace SIM; + +const unsigned CHECK_SOUND_TIMEOUT = 200; +const unsigned WAIT_SOUND_TIMEOUT = 1000; + +Plugin *createSoundPlugin(unsigned base, bool bFirst, Buffer *config) +{ + return new SoundPlugin(base, bFirst, config); +} + +static PluginInfo info = + { + I18N_NOOP("Sound"), + I18N_NOOP("Plugin provides sounds on any events"), + VERSION, + createSoundPlugin, + PLUGIN_DEFAULT + }; + +EXPORT_PROC PluginInfo* GetPluginInfo() +{ + return &info; +} + +static SoundPlugin *soundPlugin = NULL; + +static QWidget *getSoundSetup(QWidget *parent, SIM::PropertyHubPtr data) +{ + return new SoundUserConfig(parent, data, soundPlugin); +} + +SoundPlugin::SoundPlugin(unsigned base, bool bFirst, Buffer *config) + : QObject(), Plugin(base) +{ + m_propertyHub = SIM::PropertyHub::create("sound"); + soundPlugin = this; + m_media = Phonon::createPlayer(Phonon::NotificationCategory); + + CmdSoundDisable = 1000022; // FIXME + + Command cmd; + cmd->id = 0; + cmd->flags = COMMAND_CONTACT; + cmd->text = I18N_NOOP("&Sound"); + cmd->icon = "sound"; + cmd->accel = "sound"; + cmd->icon_on = QString(); + cmd->param = (void*)getSoundSetup; + EventAddPreferences(cmd).process(); + + cmd->id = CmdSoundDisable; + cmd->text = I18N_NOOP("&Sound"); + cmd->icon = "nosound"; + cmd->icon_on = "sound"; + cmd->bar_id = ToolBarMain; + cmd->bar_grp = 0; + cmd->menu_id = 0; + cmd->menu_grp = 0; + cmd->flags = COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); +} + +SoundPlugin::~SoundPlugin() +{ + soundPlugin = NULL; +} + +QWidget *SoundPlugin::createConfigWindow(QWidget *parent) +{ + return new SoundConfig(parent, this); +} + +bool SoundPlugin::processEvent(SIM::Event *e) +{ + switch (e->type()) + { + case eEventLoginStart: + { + playSound(value("StartUp").toString()); + break; + } + case eEventPluginLoadConfig: + { + PropertyHubPtr hub = ProfileManager::instance()->getPropertyHub("sound"); + if(!hub.isNull()) + setPropertyHub(hub); + if(!value("StartUp").isValid()) + setValue("StartUp", "sounds/startup.ogg"); + if(!value("MessageSent").isValid()) + setValue("MessageSent", "sounds/msgsent.ogg"); + if(!value("FileDone").isValid()) + setValue("FileDone", "sounds/filedone.ogg"); + break; + } + case eEventContact: + { + EventContact *ec = static_cast(e); + if(ec->action() != EventContact::eOnline) + break; + Contact *contact = ec->contact(); + bool disable = contact->getUserData()->root()->value("sound/Disable").toBool(); + QString alert = contact->getUserData()->root()->value("sound/Alert").toString(); + if(alert.isEmpty()) + alert = getContacts()->getUserData()->root()->value("sound/Alert").toString(); + if (!alert.isEmpty() && !disable) + { + EventPlaySound(alert).process(); + } + break; + } + case eEventMessageSent: + { + EventMessage *em = static_cast(e); + Message *msg = em->msg(); + QString err = msg->getError(); + if (!err.isEmpty()) + return false; + QString sound; + if (msg->type() == MessageFile) + { + sound = value("FileDone").toString(); + } + else if ((msg->getFlags() & MESSAGE_NOHISTORY) == 0) + { + if ((msg->getFlags() & MESSAGE_MULTIPLY) && ((msg->getFlags() & MESSAGE_LAST) == 0)) + return false; + sound = value("MessageSent").toString(); + } + if (!sound.isEmpty()) + { + EventPlaySound(sound).process(); + } + break; + } + case eEventMessageReceived: + { + EventMessage *em = static_cast(e); + Message *msg = em->msg(); + if(msg->type() == MessageStatus) + return false; + Contact *contact = getContacts()->contact(msg->contact()); + bool nosound, disable; + if(contact) + { + nosound = contact->getUserData()->root()->value("sound/NoSoundIfActive").toBool(); + disable = contact->getUserData()->root()->value("sound/Disable").toBool(); + } + else + { + nosound = getContacts()->getUserData()->root()->value("sound/NoSoundIfActive").toBool(); + disable = getContacts()->getUserData()->root()->value("sound/Disable").toBool(); + } + if(!disable && nosound) + { + EventActiveContact e; + e.process(); + if (e.contactID() == contact->id()) + disable = true; + } + if(!disable) + { + QString sound = messageSound(msg->baseType(), contact->id()); + playSound(sound); + } + break; + } + case eEventPlaySound: + { + EventPlaySound *s = static_cast(e); + playSound(s->sound()); + return true; + } + default: + break; + } + return false; +} + +void SoundPlugin::playSound(const QString& path) +{ + QString snd; + log(L_DEBUG, "Sound: %s", qPrintable(path)); + QDir d(path); + if(d.isRelative()) + snd = app_file(path); + else + snd = path; + m_media->setCurrentSource(Phonon::MediaSource(snd)); + Phonon::State state = m_media->state(); + if( state == Phonon::ErrorState ) { + QString sError = m_media->errorString(); + log(L_DEBUG, "Sound playing error: %s", qPrintable(sError)); + return; + } + m_media->play(); +} + +QString SoundPlugin::messageSound(unsigned type, unsigned long contact_id) +{ + SIM::PropertyHubPtr data; + if(!contact_id) + { + data = getContacts()->userdata(); + } + else + { + Contact* c = getContacts()->contact(contact_id); + if(c) + { + data = c->getUserData()->root(); + if(!data->value("sound/override").toBool()) + { + Group* g = getContacts()->group(c->getGroup(), false); + if(g->userdata()->value("sound/override").toBool()) + data = g->userdata(); + else + data = getContacts()->userdata(); + } + } + } + QString sound; + if(data) + { + sound = data->value("sound/Receive" + QString::number(type)).toString(); + } + if(sound == "(nosound)") + { + return QString(); + } + return sound; +} + +void SoundPlugin::setPropertyHub(SIM::PropertyHubPtr hub) +{ + m_propertyHub = hub; +} + +SIM::PropertyHubPtr SoundPlugin::propertyHub() +{ + return m_propertyHub; +} + +QVariant SoundPlugin::value(const QString& key) +{ + return m_propertyHub->value(key); +} + +void SoundPlugin::setValue(const QString& key, const QVariant& v) +{ + m_propertyHub->setValue(key, v); +} + +// vim : expandtab + diff --git a/plugins/sound/sound.h b/plugins/sound/sound.h new file mode 100644 index 0000000..5c70513 --- /dev/null +++ b/plugins/sound/sound.h @@ -0,0 +1,69 @@ +/*************************************************************************** + sound.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _SOUND_H +#define _SOUND_H + +#include "simapi.h" + +#include "cfg.h" +#include "event.h" +#include "plugins.h" +#include "propertyhub.h" + +#include +#include +#include +#include "phonon/mediaobject.h" +#include "phonon/audiooutput.h" + + +class CorePlugin; +class QTimer; +class QSound; + +class SoundPlugin : public QObject, public SIM::Plugin, public SIM::EventReceiver +{ + Q_OBJECT +public: + SoundPlugin(unsigned, bool, Buffer*); + virtual ~SoundPlugin(); + + void playSound(const QString& path); + + SIM::SIMEvent EventSoundChanged; + + void setPropertyHub(SIM::PropertyHubPtr hub); + SIM::PropertyHubPtr propertyHub(); + QVariant value(const QString& key); + void setValue(const QString& key, const QVariant& v); +protected: + QString messageSound(unsigned type, unsigned long contact_id); + virtual bool processEvent(SIM::Event *e); + virtual QWidget *createConfigWindow(QWidget *parent); + friend class SoundConfig; + friend class SoundUserConfig; + +private: + Phonon::MediaObject* m_media; + unsigned long CmdSoundDisable; + SIM::PropertyHubPtr m_propertyHub; + +}; + +#endif + diff --git a/plugins/sound/sound.rc b/plugins/sound/sound.rc new file mode 100644 index 0000000..f734180 --- /dev/null +++ b/plugins/sound/sound.rc @@ -0,0 +1,97 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,9,6,0 + PRODUCTVERSION 0,9,6,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Vladimir Shutoff\0" + VALUE "FileDescription", "Sound plugin\0" + VALUE "FileVersion", "0, 9, 6, 0\0" + VALUE "InternalName", "sound\0" + VALUE "LegalCopyright", "Copyright © 2002-2003\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "sound.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "SIM\0" + VALUE "ProductVersion", "0, 9, 6, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/sound/sound.vcproj b/plugins/sound/sound.vcproj new file mode 100644 index 0000000..5d4c4df --- /dev/null +++ b/plugins/sound/sound.vcproj @@ -0,0 +1,613 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/sound/soundconfig.cpp b/plugins/sound/soundconfig.cpp new file mode 100644 index 0000000..5efdd27 --- /dev/null +++ b/plugins/sound/soundconfig.cpp @@ -0,0 +1,78 @@ +/*************************************************************************** + soundconfig.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "simapi.h" + +#include + +#include +#include + +#include "simgui/editfile.h" +#include "contacts.h" +#include "misc.h" + +#include "soundconfig.h" +#include "sounduser.h" +#include "sound.h" + +using SIM::getContacts; + +SoundConfig::SoundConfig(QWidget *parent, SoundPlugin *plugin) + : QWidget(parent) + , m_plugin(plugin) + , user_cfg(NULL) +{ + setupUi(this); + + edtStartup->setText(plugin->value("StartUp").toString()); + edtFileDone->setText(plugin->value("FileDone").toString()); + edtSent->setText(plugin->value("MessageSent").toString()); + + for (QObject *p = parent; p != NULL; p = p->parent()) + { + QTabWidget *tab = qobject_cast(p); + if (!tab) + continue; + + user_cfg = new SoundUserConfig(tab, getContacts()->userdata(), plugin); + tab->addTab(user_cfg, i18n("Events")); + tab->adjustSize(); + break; + } +} + +SoundConfig::~SoundConfig() +{ +} + +void SoundConfig::apply() +{ + if(user_cfg) + { + SIM::PropertyHubPtr data = getContacts()->userdata(); + user_cfg->apply(data, true); + } + m_plugin->setValue("StartUp", edtStartup->text()); + m_plugin->setValue("FileDone", edtFileDone->text()); + m_plugin->setValue("MessageSent", edtSent->text()); +} + +void SoundConfig::artsToggled(bool) +{ +} + diff --git a/plugins/sound/soundconfig.h b/plugins/sound/soundconfig.h new file mode 100644 index 0000000..ef54b06 --- /dev/null +++ b/plugins/sound/soundconfig.h @@ -0,0 +1,44 @@ +/*************************************************************************** + soundconfig.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _SOUNDCONFIG_H +#define _SOUNDCONFIG_H + +#include "ui_soundconfigbase.h" + +class SoundUserConfig; +class SoundPlugin; + +class SoundConfig : public QWidget, public Ui::SoundConfigBase +{ + Q_OBJECT +public: + SoundConfig(QWidget *parent, SoundPlugin *plugin); + ~SoundConfig(); +signals: + void addTab(const char *text, QWidget *w); +public slots: + void apply(); +protected slots: + void artsToggled(bool); +protected: + SoundPlugin *m_plugin; + SoundUserConfig *user_cfg; +}; + +#endif + diff --git a/plugins/sound/soundconfigbase.ui b/plugins/sound/soundconfigbase.ui new file mode 100644 index 0000000..6cb986a --- /dev/null +++ b/plugins/sound/soundconfigbase.ui @@ -0,0 +1,98 @@ + + + SoundConfigBase + + + + 0 + 0 + 409 + 204 + + + + Form1 + + + + 11 + + + 6 + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + File transfer done: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + Message sent: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + Sound on startup: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + + + + + + + + EditSound + QWidget +
simgui/editfile.h
+
+
+ + +
diff --git a/plugins/sound/sounds/added.ogg b/plugins/sound/sounds/added.ogg new file mode 100644 index 0000000..501a635 Binary files /dev/null and b/plugins/sound/sounds/added.ogg differ diff --git a/plugins/sound/sounds/alert.ogg b/plugins/sound/sounds/alert.ogg new file mode 100644 index 0000000..155dae8 Binary files /dev/null and b/plugins/sound/sounds/alert.ogg differ diff --git a/plugins/sound/sounds/auth.ogg b/plugins/sound/sounds/auth.ogg new file mode 100644 index 0000000..660b6bf Binary files /dev/null and b/plugins/sound/sounds/auth.ogg differ diff --git a/plugins/sound/sounds/authrequest.ogg b/plugins/sound/sounds/authrequest.ogg new file mode 100644 index 0000000..09df55e Binary files /dev/null and b/plugins/sound/sounds/authrequest.ogg differ diff --git a/plugins/sound/sounds/contactrequest.ogg b/plugins/sound/sounds/contactrequest.ogg new file mode 100644 index 0000000..d252dca Binary files /dev/null and b/plugins/sound/sounds/contactrequest.ogg differ diff --git a/plugins/sound/sounds/contacts.ogg b/plugins/sound/sounds/contacts.ogg new file mode 100644 index 0000000..7f299ea Binary files /dev/null and b/plugins/sound/sounds/contacts.ogg differ diff --git a/plugins/sound/sounds/deleted.ogg b/plugins/sound/sounds/deleted.ogg new file mode 100644 index 0000000..bef5864 Binary files /dev/null and b/plugins/sound/sounds/deleted.ogg differ diff --git a/plugins/sound/sounds/error.ogg b/plugins/sound/sounds/error.ogg new file mode 100644 index 0000000..64f823d Binary files /dev/null and b/plugins/sound/sounds/error.ogg differ diff --git a/plugins/sound/sounds/file.ogg b/plugins/sound/sounds/file.ogg new file mode 100644 index 0000000..3e10e05 Binary files /dev/null and b/plugins/sound/sounds/file.ogg differ diff --git a/plugins/sound/sounds/filedone.ogg b/plugins/sound/sounds/filedone.ogg new file mode 100644 index 0000000..71b60d2 Binary files /dev/null and b/plugins/sound/sounds/filedone.ogg differ diff --git a/plugins/sound/sounds/mailpager.ogg b/plugins/sound/sounds/mailpager.ogg new file mode 100644 index 0000000..130e388 Binary files /dev/null and b/plugins/sound/sounds/mailpager.ogg differ diff --git a/plugins/sound/sounds/message.ogg b/plugins/sound/sounds/message.ogg new file mode 100644 index 0000000..712c0bb Binary files /dev/null and b/plugins/sound/sounds/message.ogg differ diff --git a/plugins/sound/sounds/msgsent.ogg b/plugins/sound/sounds/msgsent.ogg new file mode 100644 index 0000000..e269a0a Binary files /dev/null and b/plugins/sound/sounds/msgsent.ogg differ diff --git a/plugins/sound/sounds/refused.ogg b/plugins/sound/sounds/refused.ogg new file mode 100644 index 0000000..892ae77 Binary files /dev/null and b/plugins/sound/sounds/refused.ogg differ diff --git a/plugins/sound/sounds/sms.ogg b/plugins/sound/sounds/sms.ogg new file mode 100644 index 0000000..274d071 Binary files /dev/null and b/plugins/sound/sounds/sms.ogg differ diff --git a/plugins/sound/sounds/startup.ogg b/plugins/sound/sounds/startup.ogg new file mode 100644 index 0000000..e0ea14a Binary files /dev/null and b/plugins/sound/sounds/startup.ogg differ diff --git a/plugins/sound/sounds/startup2.ogg b/plugins/sound/sounds/startup2.ogg new file mode 100644 index 0000000..9183caf Binary files /dev/null and b/plugins/sound/sounds/startup2.ogg differ diff --git a/plugins/sound/sounds/startup3.ogg b/plugins/sound/sounds/startup3.ogg new file mode 100644 index 0000000..b6bb1c4 Binary files /dev/null and b/plugins/sound/sounds/startup3.ogg differ diff --git a/plugins/sound/sounds/url.ogg b/plugins/sound/sounds/url.ogg new file mode 100644 index 0000000..a6fb26f Binary files /dev/null and b/plugins/sound/sounds/url.ogg differ diff --git a/plugins/sound/sounds/vip-online.ogg b/plugins/sound/sounds/vip-online.ogg new file mode 100644 index 0000000..b91b459 Binary files /dev/null and b/plugins/sound/sounds/vip-online.ogg differ diff --git a/plugins/sound/sounds/web.ogg b/plugins/sound/sounds/web.ogg new file mode 100644 index 0000000..294ccf9 Binary files /dev/null and b/plugins/sound/sounds/web.ogg differ diff --git a/plugins/sound/sounduser.cpp b/plugins/sound/sounduser.cpp new file mode 100644 index 0000000..b8d3e1b --- /dev/null +++ b/plugins/sound/sounduser.cpp @@ -0,0 +1,139 @@ +/*************************************************************************** + sounduser.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "icons.h" +#include "sounduser.h" +#include "sound.h" +#include "simgui/editfile.h" +#include "core.h" +#include "log.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace SIM; + +unsigned ONLINE_ALERT = 0x10000; + +static void addRow(QTableWidget *lstSound, int row, const QIcon &icon, const QString &text, + quint64 id, const QString &sound) +{ + QTableWidgetItem *item; + lstSound->setRowCount(row+1); + + item = new QTableWidgetItem(icon, text); + item->setData(Qt::UserRole, id); + item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled); + lstSound->setItem(row, 0, item); + + item = new QTableWidgetItem(sound); + item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled|Qt::ItemIsEditable); + lstSound->setItem(row, 1, item); +} + +SoundUserConfig::SoundUserConfig(QWidget *parent, SIM::PropertyHubPtr data, SoundPlugin *plugin) + : QWidget(parent) + , m_plugin(plugin) +{ + setupUi(this); + + setProperty("override", data->value("sound/override").toBool()); + + int row = 0; + addRow(lstSound, row, Icon("SIM"), i18n("Online alert"), ONLINE_ALERT, data->value("sound/Alert").toString()); + + // Well, basically, this mess means that core plugin shouldn't keep messageTypes + PluginPtr coreplugin = getPluginManager()->plugin("_core"); + CorePlugin* core = static_cast(coreplugin.data()); + CommandDef *cmd; + CommandsMapIterator it(core->messageTypes); + while((cmd = ++it) != NULL) + { + MessageDef *def = (MessageDef*)(cmd->param); + if ((def == NULL) || (cmd->icon.isEmpty()) || + (def->flags & (MESSAGE_HIDDEN | MESSAGE_SENDONLY | MESSAGE_CHILD))) + { + continue; + } + if ((def->singular == NULL) || (def->plural == NULL) || + (*def->singular == 0) || (*def->plural == 0)) + { + continue; + } + QString type = i18n(def->singular, def->plural, 1); + int pos = type.indexOf("1 "); + if (pos == 0){ + type = type.mid(2); + }else if (pos > 0){ + type = type.left(pos); + } + type = type.left(1).toUpper() + type.mid(1); + + row++; + addRow(lstSound, row, Icon(cmd->icon), type, cmd->id, m_plugin->messageSound(cmd->id, data->value("id").toUInt())); + } + chkActive->setChecked(data->value("sound/NoSoundIfActive").toBool()); + chkDisable->setChecked(data->value("sound/Disable").toBool()); + connect(chkDisable, SIGNAL(toggled(bool)), this, SLOT(toggled(bool))); + toggled(data->value("sound/Disable").toBool()); + lstSound->resizeColumnsToContents(); + lstSound->setItemDelegate(new EditSoundDelegate(1, lstSound)); + lstSound->sortByColumn(0, Qt::AscendingOrder); +} + +void SoundUserConfig::apply(SIM::PropertyHubPtr data, bool override) +{ + for(int row = 0; row < lstSound->rowCount(); ++row) + { + quint64 id = lstSound->item(row, 0)->data(Qt::UserRole).toULongLong(); + QString text = lstSound->item(row, 1)->data(Qt::EditRole).toString(); + if (text.isEmpty()) + text = "(nosound)"; + if (id == ONLINE_ALERT) + { + data->setValue("sound/Alert", text); + } + else + { + data->setValue("sound/Receive" + QString::number(id), text); + } + } + data->setValue("sound/NoSoundIfActive", chkActive->isChecked()); + data->setValue("sound/Disable", chkDisable->isChecked()); + data->setValue("sound/override", override); + Event e(m_plugin->EventSoundChanged); + e.process(); +} + +void SoundUserConfig::resizeEvent(QResizeEvent *e) +{ + QWidget::resizeEvent(e); + lstSound->resizeRowsToContents(); + lstSound->resizeColumnsToContents(); +} + +void SoundUserConfig::toggled(bool bState) +{ + lstSound->setEnabled(!bState); +} + diff --git a/plugins/sound/sounduser.h b/plugins/sound/sounduser.h new file mode 100644 index 0000000..dc1bbae --- /dev/null +++ b/plugins/sound/sounduser.h @@ -0,0 +1,44 @@ +/*************************************************************************** + sounduser.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _SOUNDUSER_H +#define _SOUNDUSER_H + +#include "ui_sounduserbase.h" +#include "propertyhub.h" + +class SoundPlugin; + +class SoundUserConfig : public QWidget, public Ui::SoundUserConfigBase +{ + Q_OBJECT +public: + SoundUserConfig(QWidget *parent, SIM::PropertyHubPtr data, SoundPlugin *plugin); + +public slots: + void apply(SIM::PropertyHubPtr data, bool override); + void toggled(bool); + +protected: + void resizeEvent(QResizeEvent*); + +private: + SoundPlugin* m_plugin; +}; + +#endif + diff --git a/plugins/sound/sounduserbase.ui b/plugins/sound/sounduserbase.ui new file mode 100644 index 0000000..a4a705b --- /dev/null +++ b/plugins/sound/sounduserbase.ui @@ -0,0 +1,89 @@ + + + SoundUserConfigBase + + + + 0 + 0 + 350 + 187 + + + + Form1 + + + + 11 + + + + + &Disable all sounds + + + + + + + No sound if windows has &focus + + + + + + + true + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + false + + + true + + + false + + + 2 + + + true + + + false + + + 25 + + + 25 + + + + Sound + + + + + File + + + + + + + + chkDisable + chkActive + + + + diff --git a/plugins/spell/CMakeLists.txt b/plugins/spell/CMakeLists.txt new file mode 100644 index 0000000..baecae5 --- /dev/null +++ b/plugins/spell/CMakeLists.txt @@ -0,0 +1,53 @@ +IF(BUILD_DROPPED) +IF(ASPELL_FOUND AND NOT ENABLE_KDE3) + + ################# + # spell library # + ################# + SET(spell_SRCS + spell.cpp + spellcfg.cpp + speller.cpp + spellhighlight.cpp + ) + + SET(spell_HDRS + spell.h + spellcfg.h + speller.h + spellhighlight.h + ) + + IF(WIN32) + SET(spell_SRCS + ${spell_SRCS} + spellfind.cpp + ) + SET(spell_HDRS + ${spell_HDRS} + spellfind.h + ) + ENDIF(WIN32) + + SET(spell_UICS + spellcfgbase.ui + spellfindbase.ui + ) + + SET(spell_LIBS + ${ASPELL_LIBRARIES} + ) + + # some needed include dirs + INCLUDE_DIRECTORIES(${ASPELL_INCLUDE_DIR}) + + SIM_ADD_PLUGIN(spell) + +ELSE(ASPELL_FOUND AND NOT ENABLE_KDE3) + IF(ENABLE_KDE3) + MESSAGE(STATUS "Spell plugin is disabled when building with KDE") + ELSE(ENABLE_KDE3) + MESSAGE(STATUS "Cannot build spell plugin because aspell is missing on your system") + ENDIF(ENABLE_KDE3) +ENDIF(ASPELL_FOUND AND NOT ENABLE_KDE3) +ENDIF(BUILD_DROPPED) diff --git a/plugins/spell/configure.in.in b/plugins/spell/configure.in.in new file mode 100644 index 0000000..eaccb91 --- /dev/null +++ b/plugins/spell/configure.in.in @@ -0,0 +1,17 @@ +compile_plugin="no" +if test "$use_kde" != "yes" ; then + AC_CHECK_HEADER(aspell.h, compile_plugin="yes") +fi + +if test "x$compile_plugin" = "xyes"; then + compile_plugin="no" + AC_CHECK_LIB(aspell, get_aspell_dict_info_list, [compile_plugin="yes"; LIB_ASPELL="-laspell"]) + AC_SUBST(LIB_ASPELL) +fi + +if test "$kde_use_qt_win" = "yes"; then + SPELL_OBJ=spellfind.lo + AC_SUBST([SPELL_OBJ]) +fi +AM_CONDITIONAL(ENABLE_SPELL, test "x$compile_plugin" != "xno") + diff --git a/plugins/spell/spell.cpp b/plugins/spell/spell.cpp new file mode 100644 index 0000000..7b0a62f --- /dev/null +++ b/plugins/spell/spell.cpp @@ -0,0 +1,330 @@ +/*************************************************************************** + spell.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "spell.h" +#include "spellcfg.h" +#include "speller.h" +#include "spellhighlight.h" +#include "core.h" + +#include "profile.h" +#include "profilemanager.h" + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace SIM; + +class PSpellHighlighter : public SpellHighlighter +{ +public: + PSpellHighlighter(QTextEdit *edit, SpellPlugin *plugin); + ~PSpellHighlighter(); +}; + +PSpellHighlighter::PSpellHighlighter(QTextEdit *edit, SpellPlugin *plugin) + : SpellHighlighter(edit, plugin) +{ +} + +PSpellHighlighter::~PSpellHighlighter() +{ +} + +SIM::Plugin *createSpellPlugin(unsigned base, bool, Buffer *config) +{ + SIM::Plugin *plugin = new SpellPlugin(base, config); + return plugin; +} + +static SIM::PluginInfo info = + { + I18N_NOOP("Spell check"), + I18N_NOOP("Plugin provides check spelling"), + VERSION, + createSpellPlugin, + SIM::PLUGIN_DEFAULT + }; + +EXPORT_PROC SIM::PluginInfo* GetPluginInfo() +{ + return &info; +} + +SpellPlugin::SpellPlugin(unsigned base, Buffer *config) + : QObject(), Plugin(base) + , EventReceiver() + , m_bActive (false) + , m_base (NULL) +{ + m_propertyHub = SIM::PropertyHub::create("replace"); + + CmdSpell = registerType(); + + SIM::Command cmd; + cmd->id = CmdSpell; + cmd->text = "_"; + cmd->menu_id = MenuTextEdit; + cmd->menu_grp = 0x0100; + cmd->flags = SIM::COMMAND_CHECK_STATE; + EventCommandCreate(cmd).process(); +} + +SpellPlugin::~SpellPlugin() +{ + EventCommandRemove(CmdSpell).process(); + deactivate(); + while( !m_spellers.empty() ) { + delete m_spellers.first(); + m_spellers.removeFirst(); + } + delete m_base; +} + +void SpellPlugin::reset() +{ + while( !m_spellers.empty() ) { + delete m_spellers.first(); + m_spellers.removeFirst(); + } + if (m_base) + delete m_base; +#ifdef WIN32 + m_base = new SpellerBase(value("Path").toString()); +#else + m_base = new SpellerBase(QString()); +#endif + SpellerConfig cfg(*m_base); + QString ll = value("Lang").toString(); + while (!ll.isEmpty()){ + QString l = SIM::getToken(ll, ';'); + cfg.setKey("lang", l); + cfg.setKey("encoding", "utf-8"); + Speller *speller = new Speller(&cfg); + if (speller->created()){ + m_spellers.push_back(speller); + continue; + } + delete speller; + } + if (m_spellers.empty()){ + deactivate(); + }else{ + activate(); + } + configChanged(); +} + +void SpellPlugin::activate() +{ + if( m_bActive ) + return; + m_bActive = true; + qApp->installEventFilter(this); + QWidgetList list = QApplication::allWidgets(); + foreach( QWidget *w, list ) { + if (w->inherits("TextEdit")) + new PSpellHighlighter(static_cast(w), this); + } +} + +void SpellPlugin::deactivate() +{ + if (!m_bActive) + return; + m_bActive = false; + qApp->removeEventFilter(this); +} + +QByteArray SpellPlugin::getConfig() +{ + return QByteArray(); +} + +QWidget *SpellPlugin::createConfigWindow(QWidget *parent) +{ + return new SpellConfig(parent, this); +} + +bool SpellPlugin::processEvent(SIM::Event* e) +{ + if(e->type() == eEventPluginLoadConfig) + { + PropertyHubPtr hub = ProfileManager::instance()->getPropertyHub("spell"); + if(!hub.isNull()) + setPropertyHub(hub); + reset(); + } + return false; +} + +class NewChildEvent : public QEvent +{ +public: + NewChildEvent() : QEvent( (QEvent::Type)( QEvent::User + 100 ) ) {}; +}; + +bool SpellPlugin::eventFilter(QObject *o, QEvent *e) +{ + if (e->type() == QEvent::ChildAdded){ + QChildEvent *ce = static_cast(e); + QObject *pChild = ce->child(); + connect( pChild, SIGNAL(destroyed(QObject*)), SLOT(tempChildDestroyed(QObject*)) ); + m_listTempChilds.push_back( pChild ); + QApplication::postEvent( this, new NewChildEvent() ); + } + return QObject::eventFilter(o, e); +} + +void SpellPlugin::tempChildDestroyed( QObject *pObject ) { + int index = m_listTempChilds.indexOf( pObject ); + if( -1 != index ) { + m_listTempChilds.removeAt( index ); + pObject->disconnect( this ); + } +} + +bool SpellPlugin::event( QEvent *e ) { + if( ( e->type() == ( QEvent::User + 100 ) ) && ( m_listTempChilds.count() > 0 ) ) { + QObject *pChild = m_listTempChilds.first(); + pChild->disconnect( this ); + m_listTempChilds.pop_front(); + if( pChild->inherits( "MsgTextEdit" ) ) { + QTextEdit *edit = static_cast( pChild ); + new PSpellHighlighter(edit, this); + } + return true; + } + QObject::event( e ); + return false; +} + +void SpellPlugin::textEditFinished(QTextEdit *edit) +{ +} + +bool SpellPlugin::check(const QString &word) +{ + if( -1 != m_listIgnore.indexOf( word ) ) + return true; + + foreach( Speller *pSpeller, m_spellers ) { + if( pSpeller->check(word.toUtf8()) == 1 ) + return true; + } + + return false; +} + +void SpellPlugin::add(const QString &word) +{ + foreach( Speller *pSpeller, m_spellers ) { + if( pSpeller->add(word.toUtf8()) ) + return; + } +} + +void SpellPlugin::ignore(const QString &word) { + if( -1 != m_listIgnore.indexOf( word ) ) + m_listIgnore.push_back( word ); +} + +struct WordWeight +{ + QString word; + unsigned weight; +}; + +bool operator < (const WordWeight &w1, const WordWeight &w2) { return w1.weight > w2.weight; } + +static unsigned weight(const QString &s1, const QString &s2) +{ + QString s = s2; + unsigned res = 0; + for (int i = 0; i < (int)(s1.length()); i++){ + for (int j = 0; j < (int)(s.length()); j++){ + if (s1[i] == s[j]){ + s = s.left(j) + s.mid(j + 1); + res++; + break; + } + } + } + return res; +} + +QStringList SpellPlugin::suggestions(const QString &word) +{ + QStringList res; + foreach( Speller *pSpeller, m_spellers ) { + QStringList wl = pSpeller->suggestions(word.toUtf8()); + for (QStringList::Iterator it = wl.begin(); it != wl.end(); ++it){ + QString wrd = (*it); + QStringList::Iterator itr; + for (itr = res.begin(); itr != res.end(); ++itr){ + if ((*itr) == wrd) + break; + } + if (itr == res.end()) + res.append(wrd); + } + } + std::vector words; + for (QStringList::Iterator itw = res.begin(); itw != res.end(); ++itw){ + unsigned w = weight(word, *itw); + if (w == 0) + continue; + WordWeight ww; + ww.word = *itw; + ww.weight = w; + words.push_back(ww); + } + sort(words.begin(), words.end()); + unsigned size = words.size(); + if (size > 15) + size = 15; + res.clear(); + for (unsigned i = 0; i < size; i++) + res.append(words[i].word); + return res; +} + +void SpellPlugin::setPropertyHub(SIM::PropertyHubPtr hub) +{ + m_propertyHub = hub; +} + +SIM::PropertyHubPtr SpellPlugin::propertyHub() +{ + return m_propertyHub; +} + +QVariant SpellPlugin::value(const QString& key) +{ + return m_propertyHub->value(key); +} + +void SpellPlugin::setValue(const QString& key, const QVariant& v) +{ + m_propertyHub->setValue(key, v); +} diff --git a/plugins/spell/spell.h b/plugins/spell/spell.h new file mode 100644 index 0000000..01a39d0 --- /dev/null +++ b/plugins/spell/spell.h @@ -0,0 +1,87 @@ +/*************************************************************************** + spell.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _SPELL_H +#define _SPELL_H + +#include "cfg.h" +#include "event.h" +#include "misc.h" +#include "plugins.h" +#include "propertyhub.h" + +#include +#include +#include +#include + +class QTextEdit; +class QSyntaxHighlighter; +class SpellerBase; +class Speller; + +typedef QMap MAP_BOOL; + +class SpellPlugin : public QObject, public SIM::Plugin, public SIM::EventReceiver +{ + Q_OBJECT +public: + SpellPlugin(unsigned, Buffer*); + virtual ~SpellPlugin(); + + void reset(); + + unsigned CmdSpell; + + QStringList suggestions(const QString &word); + void add(const QString &word); + bool check(const QString &word); + void ignore(const QString &word); + + void setPropertyHub(SIM::PropertyHubPtr hub); + SIM::PropertyHubPtr propertyHub(); + QVariant value(const QString& key); + void setValue(const QString& key, const QVariant& v); + +signals: + void misspelling(const QString &word); + void configChanged(); + +protected slots: + void textEditFinished(QTextEdit*); + void tempChildDestroyed(QObject*); + +protected: + bool eventFilter(QObject *o, QEvent *e); + virtual bool event( QEvent *e ); + virtual bool processEvent(SIM::Event *e); + virtual QByteArray getConfig(); + virtual QWidget *createConfigWindow(QWidget *parent); + void activate(); + void deactivate(); + bool m_bActive; + SpellerBase *m_base; + QList m_spellers; + QList m_listTempChilds; + QStringList m_listIgnore; + +private: + SIM::PropertyHubPtr m_propertyHub; +}; + +#endif + diff --git a/plugins/spell/spell.rc b/plugins/spell/spell.rc new file mode 100644 index 0000000..95f9f4c --- /dev/null +++ b/plugins/spell/spell.rc @@ -0,0 +1,97 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,0,9,2 + PRODUCTVERSION 0,0,9,2 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Vladimir Shutoff\0" + VALUE "FileDescription", "Core plugin\0" + VALUE "FileVersion", "0, 0, 9, 4\0" + VALUE "InternalName", "spell\0" + VALUE "LegalCopyright", "Copyright © 2002-2003\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "spell.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "SIM\0" + VALUE "ProductVersion", "0, 0, 9, 4\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/spell/spell.vcproj b/plugins/spell/spell.vcproj new file mode 100644 index 0000000..7fd5d42 --- /dev/null +++ b/plugins/spell/spell.vcproj @@ -0,0 +1,596 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/spell/spellcfg.cpp b/plugins/spell/spellcfg.cpp new file mode 100644 index 0000000..a8aa10d --- /dev/null +++ b/plugins/spell/spellcfg.cpp @@ -0,0 +1,137 @@ +/*************************************************************************** + spellcfg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "spellcfg.h" +#include "spell.h" +#include "speller.h" +#ifdef WIN32 +#include "spellfind.h" +#endif + +#include "log.h" +#include "simgui/editfile.h" + +using namespace SIM; + +SpellConfig::SpellConfig(QWidget *parent, SpellPlugin *plugin) : QWidget(parent) +{ + setupUi(this); + m_plugin = plugin; +#ifdef WIN32 + edtPath->setText(m_plugin->value("Path").toString()); + edtPath->setFilter(i18n("ASpell(aspell.exe)")); + m_find = NULL; +#else + lblPath->hide(); + edtPath->hide(); +#endif + connect(edtPath, SIGNAL(textChanged(const QString&)), this, SLOT(textChanged(const QString&))); + connect(btnFind, SIGNAL(clicked()), this, SLOT(find())); + textChanged(edtPath->text()); +} + +SpellConfig::~SpellConfig() +{ +#ifdef WIN32 + delete m_find; +#endif +} + +void SpellConfig::apply() +{ +#ifdef WIN32 + m_plugin->setValue("Path", edtPath->text()); +#endif + QString lang; + for(int c = 0; c < lstLang->count(); c++) + { + QListWidgetItem *item = lstLang->item( c ); + if (item->checkState() == Qt::Unchecked) + continue; + if (!lang.isEmpty()) + lang += ';'; + lang += item->text(); + } + m_plugin->setValue("Lang", lang); + m_plugin->reset(); +} + +void SpellConfig::textChanged(const QString &str) +{ + QString langs; +#ifdef WIN32 + if (str.isEmpty()){ + lnkAspell->show(); + btnFind->show(); + }else{ +#endif + lnkAspell->hide(); + btnFind->hide(); + SpellerBase base(str); + SpellerConfig cfg(base); + langs = cfg.getLangs(); +#ifdef WIN32 + } +#endif + lstLang->clear(); + if (langs.isEmpty()){ + lblLang->setEnabled(false); + lstLang->setEnabled(false); + }else{ + lblLang->setEnabled(true); + lstLang->setEnabled(true); + int r = 0; + while (!langs.isEmpty()){ + QString l = SIM::getToken(langs, ';'); + bool bCheck = false; + QString ll = m_plugin->value("Lang").toString(); + while (!ll.isEmpty()){ + QString lc = SIM::getToken(ll, ';'); + if (l == lc){ + bCheck = true; + break; + } + } + QListWidgetItem* item = new QListWidgetItem(); + item->setText(l); + item->setFlags( item->flags() | Qt::ItemIsUserCheckable ); + item->setCheckState( bCheck ? Qt::Checked : Qt::Unchecked ); + lstLang->insertItem( r, item ); + r++; + } + } +} + +void SpellConfig::find() +{ +#ifdef WIN32 + if (m_find == NULL){ + m_find = new SpellFind(edtPath); + connect(m_find, SIGNAL(finished()), this, SLOT(findFinished())); + } + raiseWindow(m_find); +#endif +} + +void SpellConfig::findFinished() +{ +#ifdef WIN32 + m_find = NULL; +#endif +} + +// vim: set expandtab: diff --git a/plugins/spell/spellcfg.h b/plugins/spell/spellcfg.h new file mode 100644 index 0000000..22e99ab --- /dev/null +++ b/plugins/spell/spellcfg.h @@ -0,0 +1,48 @@ +/*************************************************************************** + spellcfg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _SPELLCFG_H +#define _SPELLCFG_H + +#include "ui_spellcfgbase.h" + +class SpellPlugin; + +#ifdef WIN32 +class SpellFind; +#endif + +class SpellConfig : public QWidget, public Ui::SpellConfigBase +{ + Q_OBJECT +public: + SpellConfig(QWidget *parent, SpellPlugin*); + ~SpellConfig(); +public slots: + void apply(); + void find(); + void findFinished(); + void textChanged(const QString &str); +protected: +#ifdef WIN32 + SpellFind *m_find; +#endif + SpellPlugin *m_plugin; +}; + +#endif + diff --git a/plugins/spell/spellcfgbase.ui b/plugins/spell/spellcfgbase.ui new file mode 100644 index 0000000..dcdf48e --- /dev/null +++ b/plugins/spell/spellcfgbase.ui @@ -0,0 +1,98 @@ + + + SpellConfigBase + + + + 0 + 0 + 420 + 212 + + + + Form1 + + + + 11 + + + + + Path: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + 0 + 0 + + + + + + + + Language: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + false + + + + + + + + + + 0 + 0 + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://aspell.net/win32/"><span style=" text-decoration: underline; color:#0000ff;">Download ASpell</span></a></p></body></html> + + + + + + + &Find + + + + + + + + + + + + + EditFile + QWidget +
simgui/editfile.h
+
+
+ + +
diff --git a/plugins/spell/speller.cpp b/plugins/spell/speller.cpp new file mode 100644 index 0000000..4755345 --- /dev/null +++ b/plugins/spell/speller.cpp @@ -0,0 +1,229 @@ +/*************************************************************************** + speller.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "speller.h" + +#include "log.h" + +#include +#include + +#ifdef Q_OS_WIN + +#include + +SpellerBase::SpellerBase(const QString &path) +{ + init(); + QString p = path; + int n = p.lastIndexOf('\\'); + if (n >= 0) + p = p.left(n); + p += "\\aspell-15.dll"; + m_aspellLib = new QLibrary(p); + + if (m_aspellLib->load() && m_aspellLib->isLoaded()){ + (void*&)_new_aspell_config = m_aspellLib->resolve("new_aspell_config"); + (void*&)_delete_aspell_config = m_aspellLib->resolve("new_aspell_config"); + (void*&)_get_aspell_dict_info_list = m_aspellLib->resolve("get_aspell_dict_info_list"); + (void*&)_aspell_dict_info_list_elements = m_aspellLib->resolve("aspell_dict_info_list_elements"); + (void*&)_delete_aspell_dict_info_enumeration = m_aspellLib->resolve("delete_aspell_dict_info_enumeration"); + (void*&)_aspell_dict_info_enumeration_next = m_aspellLib->resolve("aspell_dict_info_enumeration_next"); + (void*&)_aspell_config_replace = m_aspellLib->resolve("aspell_config_replace"); + (void*&)_new_aspell_speller = m_aspellLib->resolve("new_aspell_speller"); + (void*&)_to_aspell_speller = m_aspellLib->resolve("to_aspell_speller"); + (void*&)_delete_aspell_speller = m_aspellLib->resolve("delete_aspell_speller"); + (void*&)_aspell_error_message = m_aspellLib->resolve("aspell_error_message"); + (void*&)_aspell_error = m_aspellLib->resolve("aspell_error"); + (void*&)_delete_aspell_can_have_error = m_aspellLib->resolve("delete_aspell_can_have_error"); + (void*&)_aspell_speller_check = m_aspellLib->resolve("aspell_speller_check"); + (void*&)_aspell_speller_suggest = m_aspellLib->resolve("aspell_speller_suggest"); + (void*&)_aspell_word_list_elements = m_aspellLib->resolve("aspell_word_list_elements"); + (void*&)_aspell_string_enumeration_next = m_aspellLib->resolve("aspell_string_enumeration_next"); + (void*&)_aspell_speller_add_to_personal = m_aspellLib->resolve("aspell_speller_add_to_personal"); + if ((_new_aspell_config == NULL) || + (_delete_aspell_config == NULL) || + (_get_aspell_dict_info_list == NULL) || + (_aspell_dict_info_list_elements == NULL) || + (_delete_aspell_dict_info_enumeration == NULL) || + (_aspell_dict_info_enumeration_next == NULL) || + (_aspell_config_replace == NULL) || + (_new_aspell_speller == NULL) || + (_to_aspell_speller == NULL) || + (_delete_aspell_speller == NULL) || + (_aspell_error_message == NULL) || + (_aspell_error == NULL) || + (_delete_aspell_can_have_error == NULL) || + (_aspell_speller_check == NULL) || + (_aspell_speller_suggest == NULL) || + (_aspell_word_list_elements == NULL) || + (_aspell_string_enumeration_next == NULL) || + (_aspell_speller_add_to_personal == NULL)){ + delete m_aspellLib; + m_aspellLib = NULL; + init(); + } + } +} + +SpellerBase::~SpellerBase() +{ + delete m_aspellLib; +} + +void SpellerBase::init() +{ + _new_aspell_config = NULL; + _delete_aspell_config = NULL; + _get_aspell_dict_info_list = NULL; + _aspell_dict_info_list_elements = NULL; + _delete_aspell_dict_info_enumeration = NULL; + _aspell_dict_info_enumeration_next = NULL; + _aspell_config_replace = NULL; + _new_aspell_speller = NULL; + _to_aspell_speller = NULL; + _delete_aspell_speller = NULL; + _aspell_error_message = NULL; + _aspell_error = NULL; + _delete_aspell_can_have_error = NULL; + _aspell_speller_check = NULL; + _aspell_speller_suggest = NULL; + _aspell_word_list_elements = NULL; + _aspell_string_enumeration_next = NULL; + _aspell_speller_add_to_personal = NULL; +} + +#define new_aspell_config() m_base._new_aspell_config() +#define delete_aspell_config(cfg) m_base._delete_aspell_config(cfg) +#define get_aspell_dict_info_list(cfg) m_base._get_aspell_dict_info_list(cfg) +#define aspell_dict_info_list_elements(dlist) m_base._aspell_dict_info_list_elements(dlist) +#define delete_aspell_dict_info_enumeration(dlist) m_base._delete_aspell_dict_info_enumeration(dlist) +#define aspell_dict_info_enumeration_next(dlist) m_base._aspell_dict_info_enumeration_next(dlist) +#define aspell_config_replace(c, k, v) m_base._aspell_config_replace(c, k, v) +#define new_aspell_speller(dlist) m_base._new_aspell_speller(dlist) +#define to_aspell_speller(dlist) m_base._to_aspell_speller(dlist) +#define delete_aspell_speller(dlist) m_base._delete_aspell_speller(dlist) +#define aspell_error_message(dlist) m_base._aspell_error_message(dlist) +#define aspell_error(dlist) m_base._aspell_error(dlist) +#define delete_aspell_can_have_error(dlist) m_base._delete_aspell_can_have_error(dlist) +#define aspell_speller_check(c, v, s) m_base._aspell_speller_check(c, v, s) +#define aspell_speller_suggest(c, v, s) m_base._aspell_speller_suggest(c, v, s) +#define aspell_word_list_elements(c) m_base._aspell_word_list_elements(c) +#define aspell_string_enumeration_next(c) m_base._aspell_string_enumeration_next(c) +#define aspell_speller_add_to_personal(c, v, s) m_base._aspell_speller_suggest(c, v, s) + +#else + +SpellerBase::SpellerBase(const QString &) +{} + +SpellerBase::~SpellerBase() +{} + +#endif + + +SpellerConfig::SpellerConfig(SpellerBase &base) + : m_base(base) +{ +#ifdef WIN32 + cfg = NULL; + if (m_base._new_aspell_config) + cfg = new_aspell_config(); +#else + cfg = new_aspell_config(); +#endif +} + +SpellerConfig::~SpellerConfig() +{ + if (cfg) + delete_aspell_config(cfg); +} + +QString SpellerConfig::getLangs() +{ + QString res; + if (cfg == NULL) + return res; + AspellDictInfoList *dlist = get_aspell_dict_info_list(cfg); + AspellDictInfoEnumeration *dels = aspell_dict_info_list_elements(dlist); + const AspellDictInfo *entry; + while ((entry = aspell_dict_info_enumeration_next(dels)) != NULL){ + if (!res.isEmpty()) + res += ';'; + res += entry->name; + } + delete_aspell_dict_info_enumeration(dels); + return res; +} + +int SpellerConfig::setKey(const char *key, const QString &val) +{ + if (cfg == NULL) + return -1; + return aspell_config_replace(cfg, key, val.toUtf8()); +} + +Speller::Speller(SpellerConfig *cfg) + : m_base(cfg->m_base) +{ + speller = NULL; + if (cfg->cfg){ + AspellCanHaveError *ret = new_aspell_speller(cfg->cfg); + if (aspell_error(ret) != 0){ + SIM::log(SIM::L_WARN, "Spell: %s", aspell_error_message(ret)); + delete_aspell_can_have_error(ret); + return; + } + speller = to_aspell_speller(ret); + } +} + +Speller::~Speller() +{ + if (speller) + delete_aspell_speller(speller); +} + +int Speller::check(const char *word) +{ + if (speller == NULL) + return -1; + return aspell_speller_check(speller, word, strlen(word)); +} + +bool Speller::add(const char *word) +{ + if (speller == NULL) + return false; + return aspell_speller_check(speller, word, strlen(word)) != 0; +} + +QStringList Speller::suggestions(const char *word) +{ + QStringList res; + const AspellWordList *wl = aspell_speller_suggest(speller, word, -1); + if (wl){ + AspellStringEnumeration *els = aspell_word_list_elements(wl); + const char *word; + while ((word = aspell_string_enumeration_next(els)) != NULL) { + res.append(QString::fromUtf8(word)); + } + } + return res; +} diff --git a/plugins/spell/speller.h b/plugins/spell/speller.h new file mode 100644 index 0000000..e21c30c --- /dev/null +++ b/plugins/spell/speller.h @@ -0,0 +1,88 @@ +/*************************************************************************** + speller.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _SPELLER_H +#define _SPELLER_H + +#include "simapi.h" + +#include +#include +#include + +class SpellerBase +{ +public: + SpellerBase(const QString &path); + ~SpellerBase(); + +#ifdef WIN32 + struct AspellConfig *(*_new_aspell_config)(); + void (*_delete_aspell_config)(struct AspellConfig * ths); + struct AspellDictInfoList *(*_get_aspell_dict_info_list)(struct AspellConfig * config); + struct AspellDictInfoEnumeration *(*_aspell_dict_info_list_elements)(const struct AspellDictInfoList * ths); + void (*_delete_aspell_dict_info_enumeration)(struct AspellDictInfoEnumeration * ths); + const struct AspellDictInfo *(*_aspell_dict_info_enumeration_next)(struct AspellDictInfoEnumeration * ths); + int (*_aspell_config_replace)(struct AspellConfig * ths, const char * key, const char * value); + struct AspellCanHaveError *(*_new_aspell_speller)(struct AspellConfig * config); + struct AspellSpeller *(*_to_aspell_speller)(struct AspellCanHaveError * obj); + void (*_delete_aspell_speller)(struct AspellSpeller * ths); + const char *(*_aspell_error_message)(const struct AspellCanHaveError * ths); + const struct AspellError *(*_aspell_error)(const struct AspellCanHaveError * ths); + void (*_delete_aspell_can_have_error)(struct AspellCanHaveError * ths); + int (*_aspell_speller_check)(struct AspellSpeller * ths, const char * word, int word_size); + const struct AspellWordList *(*_aspell_speller_suggest)(struct AspellSpeller * ths, const char * word, int word_size); + struct AspellStringEnumeration *(*_aspell_word_list_elements)(const struct AspellWordList * ths); + const char *(*_aspell_string_enumeration_next)(struct AspellStringEnumeration * ths); + int (*_aspell_speller_add_to_personal)(struct AspellSpeller * ths, const char * word, int word_size); +protected: + void init(); + class QLibrary *m_aspellLib; +#endif +}; + +class SpellerConfig +{ + COPY_RESTRICTED(SpellerConfig); +public: + SpellerConfig(SpellerBase &base); + ~SpellerConfig(); + QString getLangs(); + int setKey(const char *key, const QString &val); +protected: + struct AspellConfig *cfg; + SpellerBase &m_base; + friend class Speller; +}; + +class Speller +{ + COPY_RESTRICTED(Speller); +public: + Speller(SpellerConfig *cfg); + ~Speller(); + bool created() { return speller != NULL; } + int check(const char *word); + QStringList suggestions(const char *word); + bool add(const char *word); +protected: + struct AspellSpeller *speller; + SpellerBase &m_base; +}; + +#endif + diff --git a/plugins/spell/spellfind.cpp b/plugins/spell/spellfind.cpp new file mode 100644 index 0000000..77bd876 --- /dev/null +++ b/plugins/spell/spellfind.cpp @@ -0,0 +1,121 @@ +/*************************************************************************** + spellfind.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include + +#include "simgui/editfile.h" +#include "icons.h" +#include "misc.h" + +#include "spellfind.h" + +using namespace std; +using namespace SIM; + +SpellFind::SpellFind(EditFile *edt) + : QDialog(NULL) + , m_edit(edt) +{ + setupUi(this); + setModal(false); + setAttribute(Qt::WA_DeleteOnClose); + SET_WNDPROC("find") + setWindowIcon(Icon("find")); + setButtonsPict(this); + connect(btnCancel, SIGNAL(clicked()), this, SLOT(close())); + m_drives = QDir::drives(); + m_drive = m_drives.first(); + QTimer::singleShot(0, this, SLOT(next())); +} + +SpellFind::~SpellFind() +{ + emit finished(); +} + +void SpellFind::next() +{ + if (!m_tree.empty()){ + QStringList &subDirs = m_tree.top(); + int pos = (int)m_pos.top(); + if (pos >= subDirs.count()){ + m_tree.pop(); + m_pos.pop(); + m_path = m_path.left(m_path.length() - 1); + m_path = m_path.left(m_path.lastIndexOf('\\') + 1); + QTimer::singleShot(0, this, SLOT(next())); + return; + } + QString subDir = subDirs[pos++]; + m_pos.pop(); + m_pos.push(pos); + if (!subDir.startsWith(".")){ + m_path += subDir; + m_path += '\\'; + if (checkPath()) + return; + } + QTimer::singleShot(0, this, SLOT(next())); + return; + } + m_path = m_drive.absoluteFilePath(); + m_path = m_path.replace('/', '\\'); + if ((GetDriveTypeW((LPCWSTR)m_path.utf16()) == DRIVE_FIXED) && checkPath()) + return; + m_drives.removeFirst(); + if(m_drives.count() == 0) { + close(); + return; + } + m_drive = m_drives.first(); + QTimer::singleShot(0, this, SLOT(next())); +} + +bool SpellFind::checkPath() +{ + QDir d(m_path); + if (!d.exists()) + return false; + QString p = m_path; + if (p.length() > 40){ + p = "..."; + p += m_path.mid(m_path.length() - 38); + } + lblPath->setText(p); + QFile f(m_path + "aspell.exe"); + if (f.exists()){ + m_edit->setText(m_path + "aspell.exe"); + QTimer::singleShot(0, this, SLOT(close())); + return true; + } + QStringList subDirs = d.entryList(QDir::Dirs); + if (!subDirs.isEmpty()){ + m_tree.push(subDirs); + m_pos.push(0); + }else{ + m_path = m_path.left(m_path.lastIndexOf('\\')); + } + return false; +} + diff --git a/plugins/spell/spellfind.h b/plugins/spell/spellfind.h new file mode 100644 index 0000000..ae80f4f --- /dev/null +++ b/plugins/spell/spellfind.h @@ -0,0 +1,48 @@ +/*************************************************************************** + spellfind.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _SPELLFIND_H +#define _SPELLFIND_H + +#include +#include +#include "ui_spellfindbase.h" + +class EditFile; + +class SpellFind : public QDialog, public Ui::SpellFindBase +{ + Q_OBJECT +public: + SpellFind(EditFile *edt); + ~SpellFind(); +signals: + void finished(); +protected slots: + void next(); +protected: + bool checkPath(); + QString m_path; + std::stack m_tree; + std::stack m_pos; + QFileInfoList m_drives; + QFileInfo m_drive; + EditFile *m_edit; +}; + +#endif + diff --git a/plugins/spell/spellfindbase.ui b/plugins/spell/spellfindbase.ui new file mode 100644 index 0000000..178cb68 --- /dev/null +++ b/plugins/spell/spellfindbase.ui @@ -0,0 +1,86 @@ + + + + + SpellFindBase + + + + 0 + 0 + 354 + 97 + + + + Find ASpell + + + true + + + + 11 + + + 6 + + + + + + 1 + 7 + + + + + + + false + + + + + + + &Cancel + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Horizontal + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Horizontal + + + + + + qPixmapFromMimeSource + diff --git a/plugins/spell/spellhighlight.cpp b/plugins/spell/spellhighlight.cpp new file mode 100644 index 0000000..e653ffd --- /dev/null +++ b/plugins/spell/spellhighlight.cpp @@ -0,0 +1,158 @@ +/*************************************************************************** + spellhighlight.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "log.h" +#include "simgui/textshow.h" + +#include "spellhighlight.h" +#include "spell.h" +#include "msgedit.h" + +#include +#include + +using namespace std; +using namespace SIM; +const unsigned ErrorColor = 0xFF0101; + +SpellHighlighter::SpellHighlighter(QTextEdit *edit, SpellPlugin *plugin) + : QSyntaxHighlighter(edit) + , EventReceiver(SIM::HighPriority) + , m_plugin( plugin ) +{ +} + +SpellHighlighter::~SpellHighlighter() +{ +} + +void SpellHighlighter::highlightBlock( const QString &sText ) +{ + QTextCharFormat format; + format.setUnderlineColor( Qt::red ); + format.setUnderlineStyle( QTextCharFormat::SpellCheckUnderline ); + + QRegExp expression( "\\b(\\w+)\\W+" ); + QRegExp expression2( "\\b(\\w+)" ); + int index = expression.indexIn( sText ); + while (index >= 0) { + int length = expression.matchedLength(); + QString s = sText.mid( index, length ); + expression2.indexIn( s ); + QString sWord = s.left( expression2.matchedLength() ); + if( !m_plugin->check( sWord ) ) { + setFormat( index, expression2.matchedLength(), format ); + } + index = expression.indexIn( sText, index + length ); + } +} + +bool SpellHighlighter::processEvent(SIM::Event *e) +{ + if (e->type() == SIM::eEventCheckCommandState){ + SIM::EventCheckCommandState *ecs = static_cast(e); + SIM::CommandDef *cmd = ecs->cmd(); + if (cmd->id == m_plugin->CmdSpell){ + TextEdit *pEdit = (TextEdit*)(cmd->param); + if( pEdit->document() != document() ) + return false; + m_listSuggestions.clear(); + QTextCursor cursor = pEdit->cursorForPosition( pEdit->m_popupPos ); + cursor.select( QTextCursor::WordUnderCursor ); + QString sWord = cursor.selectedText(); + if( sWord.isEmpty() ) + return false; + if( m_plugin->check( sWord ) ) + return false; + + m_listSuggestions = m_plugin->suggestions( sWord ); + SIM::CommandDef *cmds = new SIM::CommandDef[m_listSuggestions.count() + 3]; + unsigned i = 0; + for (QStringList::Iterator it = m_listSuggestions.begin(); it != m_listSuggestions.end(); ++it, i++){ + cmds[i].id = m_plugin->CmdSpell + i + 2; + cmds[i].text = "_"; + cmds[i].text_wrk = (*it); + if (i >= 10){ + i++; + break; + } + } + cmds[i].id = m_plugin->CmdSpell; + cmds[i].text = "_"; + cmds[i].text_wrk = i18n("Add '%1'").arg( sWord ); + i++; + cmds[i].id = m_plugin->CmdSpell + 1; + cmds[i].text = "_"; + cmds[i].text_wrk = i18n("Ignore '%1'").arg( sWord ); + + cmd->param = cmds; + cmd->flags |= SIM::COMMAND_RECURSIVE; + + return true; + } + } else + if (e->type() == eEventCommandExec){ + EventCommandExec *ece = static_cast(e); + CommandDef *cmd = ece->cmd(); + if ((cmd->id >= m_plugin->CmdSpell) && (cmd->id < m_plugin->CmdSpell + m_listSuggestions.count() + 1)){ + TextEdit *pEdit = (TextEdit*)(cmd->param); + if( pEdit->document() != document() ) + return false; + QTextCursor cursor = pEdit->cursorForPosition( pEdit->m_popupPos ); + cursor.select( QTextCursor::WordUnderCursor ); + QString sWord = cursor.selectedText(); + if( sWord.isEmpty() ) + return false; + if (cmd->id == m_plugin->CmdSpell){ + m_plugin->add( sWord ); +/* + MAP_BOOL::iterator it = m_words.find(SIM::my_string( sWord )); + if (it == m_words.end()){ + m_words.insert(MAP_BOOL::value_type(SIM::my_string(m_word), true)); + }else{ + if (it->second) + return false; + it->second = true; + } + m_bDirty = true; + QTimer::singleShot(300, this, SLOT(reformat())); +*/ + }else if (cmd->id == m_plugin->CmdSpell + 1){ +/* + MAP_BOOL::iterator it = m_plugin->m_ignore.find(SIM::my_string(m_word)); + if (it == m_plugin->m_ignore.end()) + m_plugin->m_ignore.insert(MAP_BOOL::value_type(SIM::my_string(m_word), true)); + it = m_words.find(SIM::my_string(m_word)); + if (it == m_words.end()){ + m_words.insert(MAP_BOOL::value_type(SIM::my_string(m_word), true)); + }else{ + if (it->second) + return false; + it->second = true; + } + m_bDirty = true; + QTimer::singleShot(300, this, SLOT(reformat())); +*/ + }else{ + sWord = m_listSuggestions[cmd->id - m_plugin->CmdSpell - 2]; + cursor.insertText( sWord ); + } + } + } + + return false; +} diff --git a/plugins/spell/spellhighlight.h b/plugins/spell/spellhighlight.h new file mode 100644 index 0000000..7a61019 --- /dev/null +++ b/plugins/spell/spellhighlight.h @@ -0,0 +1,44 @@ +/*************************************************************************** + spellhighlight.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _SPELLHIGHLIGHT_H +#define _SPELLHIGHLIGHT_H + +#include "spell.h" + +#include +#include + +class SpellHighlighter + : public QSyntaxHighlighter + , public SIM::EventReceiver +{ + Q_OBJECT +public: + SpellHighlighter(QTextEdit *edit, SpellPlugin *m_plugin); + virtual ~SpellHighlighter(); + + virtual void highlightBlock( const QString &sText ); + +protected: + virtual bool processEvent(SIM::Event *e); + SpellPlugin *m_plugin; + QStringList m_listSuggestions; +}; + +#endif + diff --git a/plugins/splash/CMakeLists.txt b/plugins/splash/CMakeLists.txt new file mode 100644 index 0000000..c8bbe56 --- /dev/null +++ b/plugins/splash/CMakeLists.txt @@ -0,0 +1,20 @@ +################## +# splash library # +################## +IF(BUILD_DROPPED) +SET(splash_SRCS + splash.cpp +) + +SET(splash_HDRS + splash.h +) + +REMOVE_DEFINITIONS(-DQT3_SUPPORT) +REMOVE_DEFINITIONS(-DQT_3SUPPORT_LIB) +REMOVE_DEFINITIONS(-DQT3_SUPPORT_WARNINGS) +SIM_ADD_PLUGIN(splash) + +# splash.png +INSTALL(FILES splash.png DESTINATION ${SIM_PICT_DIR}) +ENDIF(BUILD_DROPPED) diff --git a/plugins/splash/SIM-IM.svg b/plugins/splash/SIM-IM.svg new file mode 100644 index 0000000..01a5315 --- /dev/null +++ b/plugins/splash/SIM-IM.svg @@ -0,0 +1,976 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Simple Instant Messenger + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + Simple Instant Messenger + Sim-IM + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/splash/simsvg-template.png b/plugins/splash/simsvg-template.png new file mode 100644 index 0000000..8c7a57e Binary files /dev/null and b/plugins/splash/simsvg-template.png differ diff --git a/plugins/splash/splash.cpp b/plugins/splash/splash.cpp new file mode 100644 index 0000000..d571c9a --- /dev/null +++ b/plugins/splash/splash.cpp @@ -0,0 +1,119 @@ +/*************************************************************************** + splash.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "aboutdata.h" +#include "misc.h" +#include "log.h" + +#include "splash.h" + + +using namespace SIM; + +Plugin *createSplashPlugin(unsigned base, bool bStart, Buffer*) +{ + Plugin *plugin = new SplashPlugin(base, bStart); + return plugin; +} + +static PluginInfo info = + { + I18N_NOOP("Splash"), + I18N_NOOP("Plugin provides splash screen"), + VERSION, + createSplashPlugin, + PLUGIN_DEFAULT + }; + +EXPORT_PROC PluginInfo* GetPluginInfo() +{ + return &info; +} + +SplashPlugin::SplashPlugin(unsigned base, bool bStart) : QObject(NULL), Plugin(base) +{ + splash = NULL; + m_bStart = bStart; + if (m_bStart) + { + QPixmap pict(app_file("pict/splash.png")); + // FIXME: better use QSplash with QSplashScreen::drawContents() + if(!pict.isNull()) + { + //KAboutData *about_data = getAboutData(); + QString text = "";// about_data->programName(); + text += " "; + //text += about_data->version(); + QPainter p(&pict); + QFont f = qApp->font(); + f.setBold(true); + p.setFont(f); + QRect rc = p.boundingRect(0, 0, pict.width(), pict.height(), Qt::AlignLeft | Qt::AlignTop, text); + int x = pict.width() - 7 - rc.width(); + int y = 7 + rc.height(); + p.setPen(QColor(0x80, 0x80, 0x80)); + p.drawText(x, y, text); + x -= 2; + y -= 2; + p.setPen(QColor(0xFF, 0xFF, 0xE0)); + p.drawText(x, y, text); + splash = new QWidget(NULL, Qt::SplashScreen); + splash->setObjectName("splash"); + + QDesktopWidget *desktop = qApp->desktop(); //QApplication::desktop(); + int desk_width = desktop->geometry().width(); + int desk_height = desktop->geometry().height(); + if ((desk_width/desk_height)==2) //widescreen or double screen + splash->move((desktop->width()/2 - pict.width()) / 2, (desktop->height() - pict.height()) / 2); + else //normal screen + splash->move((desktop->width() - pict.width()) / 2, (desktop->height() - pict.height()) / 2); + QPalette palette = splash->palette(); + palette.setBrush(splash->backgroundRole(), QBrush(pict)); + splash->setPalette(palette); + splash->resize(pict.width(), pict.height()); + splash->repaint(); + const QBitmap mask = pict.mask(); + p.end(); + if (!mask.isNull()) + splash->setMask(mask); + splash->show(); + m_timer = new QTimer(this); + connect(m_timer, SIGNAL(timeout()), this, SLOT(timeout())); + m_timer->start(5000); + } + } +} + +SplashPlugin::~SplashPlugin() +{ + delete splash; +} + +void SplashPlugin::timeout() //Anywhere is definitly a bug. Splash is going to be unloaded and not fulltime displayed... +{ + splash->hide(); +} + diff --git a/plugins/splash/splash.h b/plugins/splash/splash.h new file mode 100644 index 0000000..0c78d89 --- /dev/null +++ b/plugins/splash/splash.h @@ -0,0 +1,46 @@ +/*************************************************************************** + splash.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _SPLASH_H +#define _SPLASH_H + +#include + +#include "event.h" +#include "plugins.h" + +class QWidget; + +class SplashPlugin : public QObject, public SIM::Plugin +{ + Q_OBJECT +public: + SplashPlugin(unsigned base, bool bStart); + virtual ~SplashPlugin(); + +protected: + + QWidget *splash; + bool m_bStart; + QTimer *m_timer; +protected slots: + void timeout(); + +}; + +#endif + diff --git a/plugins/splash/splash.png b/plugins/splash/splash.png new file mode 100644 index 0000000..93160c5 Binary files /dev/null and b/plugins/splash/splash.png differ diff --git a/plugins/splash/splash.vcproj b/plugins/splash/splash.vcproj new file mode 100644 index 0000000..dd8aed9 --- /dev/null +++ b/plugins/splash/splash.vcproj @@ -0,0 +1,300 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/styles/CMakeLists.txt b/plugins/styles/CMakeLists.txt new file mode 100644 index 0000000..f940e00 --- /dev/null +++ b/plugins/styles/CMakeLists.txt @@ -0,0 +1,27 @@ +################## +# styles library # +################## + +IF(BUILD_DROPPED) +SET(styles_SRCS + fontconfig.cpp + styles.cpp + stylescfg.cpp +) + +SET(styles_HDRS + fontconfig.h + styles.h + stylescfg.h +) + +SET(styles_UICS + fontconfigbase.ui + stylescfgbase.ui +) + +REMOVE_DEFINITIONS(-DQT3_SUPPORT) +REMOVE_DEFINITIONS(-DQT_3SUPPORT_LIB) +REMOVE_DEFINITIONS(-DQT3_SUPPORT_WARNINGS) +SIM_ADD_PLUGIN(styles) +ENDIF(BUILD_DROPPED) diff --git a/plugins/styles/fontconfig.cpp b/plugins/styles/fontconfig.cpp new file mode 100644 index 0000000..57987cf --- /dev/null +++ b/plugins/styles/fontconfig.cpp @@ -0,0 +1,112 @@ +/*************************************************************************** + fontconfig.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "fontconfig.h" +#include "simgui/fontedit.h" +#include "styles.h" +#include "simgui/qcolorbutton.h" + +#include +#include +#include + +FontConfig::FontConfig(QWidget *parent, StylesPlugin *plugin) + : QWidget(parent) +{ + setupUi(this); + m_plugin = plugin; + connect(chkSystem, SIGNAL(toggled(bool)), this, SLOT(systemToggled(bool))); + connect(chkColors, SIGNAL(toggled(bool)), this, SLOT(colorsToggled(bool))); + chkSystem->setChecked(m_plugin->value("SystemFonts").toBool()); + systemToggled(chkSystem->isChecked()); + if (!chkSystem->isChecked()){ + QMenu m; + QFont base = QApplication::font(); + QFont menu = QApplication::font(&m); + base = FontEdit::str2font(m_plugin->value("BaseFont").toString(), base); + menu = FontEdit::str2font(m_plugin->value("MenuFont").toString(), menu); + edtFont->setFont(FontEdit::font2str(base, true)); + edtMenu->setFont(FontEdit::font2str(menu, true)); + } + + chkColors->setChecked(m_plugin->value("SystemColors").toBool()); + colorsToggled(chkColors->isChecked()); +} + +FontConfig::~FontConfig() +{ +} + +void FontConfig::apply() +{ + QString base; + QString menu; + if (chkSystem->isChecked()){ + m_plugin->setValue("SystemFonts", true); + }else{ + m_plugin->setValue("SystemFonts", false); + base = edtFont->getFont(); + menu = edtMenu->getFont(); + } + m_plugin->setValue("BaseFont", base); + m_plugin->setValue("MenuFont", menu); + m_plugin->setFonts(); + + bool bChanged = false; + if (chkColors->isChecked()){ + if (!m_plugin->value("SystemColors").toBool()){ + m_plugin->setValue("SystemColors", true); + bChanged = true; + } + }else{ + if (m_plugin->value("SystemColors").toBool()){ + bChanged = true; + }else{ + bChanged = ((btnBtnColor->color().rgb() & 0xFFFFFF) != m_plugin->value("BtnColor").toUInt()) || + ((btnBgColor->color().rgb() & 0xFFFFFF) != m_plugin->value("BgColor").toUInt()); + } + m_plugin->setValue("SystemColors", false); + if (bChanged){ + m_plugin->setValue("BtnColor", btnBtnColor->color().rgb() & 0xFFFFFF); + m_plugin->setValue("BgColor", btnBgColor->color().rgb() & 0xFFFFFF); + } + } + if (bChanged) + m_plugin->setColors(); +} + +void FontConfig::systemToggled(bool bState) +{ + edtFont->setEnabled(!bState); + edtMenu->setEnabled(!bState); + if (bState){ + m_plugin->setupDefaultFonts(); + edtFont->setFont(FontEdit::font2str(*m_plugin->m_saveBaseFont, true)); + edtMenu->setFont(FontEdit::font2str(*m_plugin->m_saveMenuFont, true)); + } +} + +void FontConfig::colorsToggled(bool bState) +{ + btnBtnColor->setEnabled(!bState); + btnBgColor->setEnabled(!bState); + if (!bState){ + btnBtnColor->setColor(QColor(m_plugin->value("BtnColor").toUInt() & 0xFFFFFF)); + btnBgColor->setColor(QColor(m_plugin->value("BgColor").toUInt() & 0xFFFFFF)); + } +} + diff --git a/plugins/styles/fontconfig.h b/plugins/styles/fontconfig.h new file mode 100644 index 0000000..b0073c3 --- /dev/null +++ b/plugins/styles/fontconfig.h @@ -0,0 +1,40 @@ +/*************************************************************************** + fontconfig.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _FONTCONFIG_H +#define _FONTCONFIG_H + +#include "ui_fontconfigbase.h" + +class StylesPlugin; + +class FontConfig : public QWidget, public Ui::FontConfigBase +{ + Q_OBJECT +public: + FontConfig(QWidget *parent, StylesPlugin *plugin); + ~FontConfig(); +public slots: + void apply(); + void systemToggled(bool); + void colorsToggled(bool); +protected: + StylesPlugin *m_plugin; +}; + +#endif + diff --git a/plugins/styles/fontconfigbase.ui b/plugins/styles/fontconfigbase.ui new file mode 100644 index 0000000..e7530cb --- /dev/null +++ b/plugins/styles/fontconfigbase.ui @@ -0,0 +1,151 @@ + + + FontConfigBase + + + + 0 + 0 + 365 + 244 + + + + Form1 + + + + + + Use &system fonts + + + + + + + + + Base font: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + false + + + + + + + + + + Menu font: + + + false + + + + + + + + + + + + Use system &colors + + + + + + + + + + 0 + 0 + + + + Button color: + + + false + + + + + + + + + + + 0 + 0 + + + + Background color: + + + false + + + + + + + + + + + + Qt::Horizontal + + + + 154 + 20 + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + QColorButton + QWidget +
simgui/qcolorbutton.h
+
+ + FontEdit + QWidget +
simgui/fontedit.h
+
+
+ + +
diff --git a/plugins/styles/metal/CMakeLists.txt b/plugins/styles/metal/CMakeLists.txt new file mode 100644 index 0000000..66a8935 --- /dev/null +++ b/plugins/styles/metal/CMakeLists.txt @@ -0,0 +1,31 @@ +################# +# metal library # +################# +PROJECT(metal) + +SET(metal_LIB_SRCS + metal.cpp +) + +SET(metal_LIB_HDRS + metal.h +) + +# moc, if needed +KDE3_AUTOMOC(${metal_LIB_SRCS}) + +ADD_LIBRARY(metal SHARED ${metal_LIB_SRCS} ${metal_LIB_HDRS}) + +# some needed include dirs +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) + +TARGET_LINK_LIBRARIES(metal simlib) + +SET_TARGET_PROPERTIES(metal PROPERTIES PREFIX "") + +# install target +INSTALL(TARGETS metal LIBRARY DESTINATION ${SIM_PLUGIN_DIR}/styles RUNTIME DESTINATION ${SIM_PLUGIN_DIR}/styles) + +IF(WIN32) + SET(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/plugins/styles) +ENDIF(WIN32) diff --git a/plugins/styles/metal/marble.xpm b/plugins/styles/metal/marble.xpm new file mode 100644 index 0000000..1c08049 --- /dev/null +++ b/plugins/styles/metal/marble.xpm @@ -0,0 +1,470 @@ +/* XPM */ +static const char *marble_xpm[] = { +/* width height num_colors chars_per_pixel */ +" 240 240 223 2", +/* colors */ +".. c #959595", +".# c #c5c5c5", +".a c #adadad", +".b c #dedede", +".c c #b7b7b7", +".d c #d2d2d2", +".e c #bebebe", +".f c #c9c9c9", +".g c #b8b8b8", +".h c #d6d6d6", +".i c #9e9e9e", +".j c #eaeaea", +".k c #b2b2b2", +".l c #cecece", +".m c #a5a5a5", +".n c #e4e4e4", +".o c #c4c4c4", +".p c #d9d9d9", +".q c #b1b1b1", +".r c #d8d8d8", +".s c #e0e0e0", +".t c #d6d6d6", +".u c #b6b6b6", +".v c #bfbfbf", +".w c #cbcbcb", +".x c #a5a5a5", +".y c #d1d1d1", +".z c #cdcdcd", +".A c #aaaaaa", +".B c #9a9a9a", +".C c #dedede", +".D c #aeaeae", +".E c #e6e6e6", +".F c #d3d3d3", +".G c #c8c8c8", +".H c #bababa", +".I c #c4c4c4", +".J c #cccccc", +".K c #bcbcbc", +".L c #f0f0f0", +".M c #b5b5b5", +".N c #e3e3e3", +".O c #c2c2c2", +".P c #adadad", +".Q c #c9c9c9", +".R c #e1e1e1", +".S c #a2a2a2", +".T c #d1d1d1", +".U c #bebebe", +".V c #dbdbdb", +".W c #dbdbdb", +".X c #c8c8c8", +".Y c #b9b9b9", +".Z c #a8a8a8", +".0 c #d3d3d3", +".1 c #9f9f9f", +".2 c #c1c1c1", +".3 c #ebebeb", +".4 c #b4b4b4", +".5 c #d9d9d9", +".6 c #cecece", +".7 c #e8e8e8", +".8 c #d6d6d6", +".9 c #c5c5c5", +"#. c #b0b0b0", +"## c #dadada", +"#a c #c5c5c5", +"#b c #d1d1d1", +"#c c #afafaf", +"#d c #b1b1b1", +"#e c #cbcbcb", +"#f c #c1c1c1", +"#g c #eeeeee", +"#h c #9b9b9b", +"#i c #c6c6c6", +"#j c #c0c0c0", +"#k c #cbcbcb", +"#l c #bdbdbd", +"#m c #a1a1a1", +"#n c #b7b7b7", +"#o c #a7a7a7", +"#p c #e6e6e6", +"#q c #c9c9c9", +"#r c #bbbbbb", +"#s c #e2e2e2", +"#t c #b8b8b8", +"#u c #cdcdcd", +"#v c #d3d3d3", +"#w c #cfcfcf", +"#x c #e0e0e0", +"#y c #d5d5d5", +"#z c #bdbdbd", +"#A c #cecece", +"#B c #c0c0c0", +"#C c #b7b7b7", +"#D c #e5e5e5", +"#E c #c4c4c4", +"#F c #e3e3e3", +"#G c #d3d3d3", +"#H c #dddddd", +"#I c #dddddd", +"#J c #acacac", +"#K c #a3a3a3", +"#L c #eaeaea", +"#M c #e1e1e1", +"#N c #b9b9b9", +"#O c #d5d5d5", +"#P c #bababa", +"#Q c #d7d7d7", +"#R c #b5b5b5", +"#S c #d1d1d1", +"#T c #c6c6c6", +"#U c #dcdcdc", +"#V c #b4b4b4", +"#W c #c6c6c6", +"#X c #a8a8a8", +"#Y c #a0a0a0", +"#Z c #cbcbcb", +"#0 c #bfbfbf", +"#1 c #cbcbcb", +"#2 c #a4a4a4", +"#3 c #c0c0c0", +"#4 c #bbbbbb", +"#5 c #9c9c9c", +"#6 c #a2a2a2", +"#7 c #dcdcdc", +"#8 c #c3c3c3", +"#9 c #9d9d9d", +"a. c #aaaaaa", +"a# c #d5d5d5", +"aa c #eeeeee", +"ab c #b6b6b6", +"ac c #b0b0b0", +"ad c #b3b3b3", +"ae c #c9c9c9", +"af c #e9e9e9", +"ag c #bdbdbd", +"ah c #a0a0a0", +"ai c #b0b0b0", +"aj c #e8e8e8", +"ak c #cacaca", +"al c #c3c3c3", +"am c #dbdbdb", +"an c #d0d0d0", +"ao c #d8d8d8", +"ap c #c7c7c7", +"aq c #dcdcdc", +"ar c #c7c7c7", +"as c #f0f0f0", +"at c #a3a3a3", +"au c #bfbfbf", +"av c #d9d9d9", +"aw c #dfdfdf", +"ax c #d3d3d3", +"ay c #c0c0c0", +"az c #cacaca", +"aA c #b3b3b3", +"aB c #cfcfcf", +"aC c #dadada", +"aD c #b2b2b2", +"aE c #e2e2e2", +"aF c #d7d7d7", +"aG c #c4c4c4", +"aH c #b8b8b8", +"aI c #cdcdcd", +"aJ c #a6a6a6", +"aK c #d2d2d2", +"aL c #cecece", +"aM c #acacac", +"aN c #dfdfdf", +"aO c #d5d5d5", +"aP c #c9c9c9", +"aQ c #bcbcbc", +"aR c #c6c6c6", +"aS c #cdcdcd", +"aT c #bebebe", +"aU c #f2f2f2", +"aV c #b6b6b6", +"aW c #e4e4e4", +"aX c #c3c3c3", +"aY c #e2e2e2", +"aZ c #d2d2d2", +"a0 c #dddddd", +"a1 c #dcdcdc", +"a2 c #ececec", +"a3 c #eaeaea", +"a4 c #cccccc", +"a5 c #c7c7c7", +"a6 c #c2c2c2", +"a7 c #cccccc", +"a8 c #a8a8a8", +"a9 c #e7e7e7", +"b. c #e4e4e4", +"b# c #d9d9d9", +"ba c #bababa", +"bb c #cfcfcf", +"bc c #d4d4d4", +"bd c #d0d0d0", +"be c #aeaeae", +"bf c #e1e1e1", +"bg c #d7d7d7", +"bh c #cfcfcf", +"bi c #b8b8b8", +"bj c #e6e6e6", +"bk c #c5c5c5", +"bl c #e4e4e4", +"bm c #d4d4d4", +"bn c #dfdfdf", +"bo c #dedede", +"bp c #ececec", +"bq c #bababa", +"br c #bcbcbc", +"bs c #b0b0b0", +"bt c #cccccc", +"bu c #a6a6a6", +"bv c #c1c1c1", +"bw c #bcbcbc", +"bx c #ababab", +"by c #d7d7d7", +"bz c #b7b7b7", +"bA c #b2b2b2", +"bB c #b4b4b4", +"bC c #bfbfbf", +/* pixels */ +"aYbla9a9a9.7#D.N#L#La9.7a9#D#D.7#D#D#DaY#x#xa0ama0ama0am#xbnbnbnaYaYaYaYaY#DaYaYaYbn#x#x#xaY.N#Da9a9a9a9a9a9a9a9a9.7a9a9a9#Da9#D#L#L#L#L#L#La2#La2a2a2a2a2a2#ga2#ga2#ga2a2#ga2a2#L#L#L#Lafa9a9a9bl#Dbl#Da9a9a9#L#L#Laf#L#Laf#L#L#L#L#L#L#L#L#L#La2#La2a2a2#La2#L#L#Laf#L#Laf#L#Laf#L#Laf#L#Laf#Laf#Laf#Laf#Laf#L#D#DblblaYaYaCa0.t.Fb#bnbnaCbnblblblblblaYaY.RaYblblblblblblblbla9a9a9a9a9a9#pa9a9#pa9#pa9#pa9#pa9#pa9a9bl#D#D#D#pa9#pafa9a9a9a9#L#Lafa9a9a9#D#D#pbl#U.V.Vb#.8am#xbn#IaYbl.N.N#x", +"am#I#Da9a9a9bj#D#La9.7#D#Da9#D#D#p#DaYaY#xbna0amamamb#a0a0a0a0bnawaYaYaYaYaYaYaY#xbnaY.R#xaYaY.Nafa9afa9afa9afa9.7a9.7a9bja9bja9#Lafa2afa2af#L#L.3#La2#La2bpa2#La2#ga2a2#ga2a2#g#L#Laf#L#La9afa9bl#Dbl#Da9afa9#L#Laf#L#Laf#L#Laf#L#L#L#L#L#L#L.7a2#La2a2#La2#La2#Laf#L#Laf#Laf#Lafajaf#L#Laf#L#L#Lafajafajafajaf.na9#s#Daw#xbnaCb#bg.Vbnbn.RaYaY#Mbl#pblaYblaYaYaYblblbl#D#Dbl#D#paf#pafa9#pa9afbla9#pa9#pa9#pa9#pa9#p#D#p#Da9#D#pa9#pa9#Da9#Da9af#L#La9.7#D#s#D#MaYbnaCb#aOb#aC#x#UaYaY#M#DaYbf", +"aOambn.sa9bja9.7a9.7a9#Da9bj#D#D#D#DaYaY#x#xa0amaFaFbgb#aF.Va0.VaYaYaYaYaYaYaYaYbn#xaY#xaY.N#D#Da9a9a9a9a9a9a9a9a9bja9#Da9#Da9#D#L#L#L#L#L#La2#La2afa2a2a2a2#ga2#g#La2bpa2bpa2#L#L#L#L#Lafa9a9#p#DaY#D#Da9a9.7a9af#Laf#L#Laf#Laf#L.7#L#L.7#L#L#L#La2a2a2#La2#L.3#Laf#Laf#Lajaf#Laja9#Lajaf#Lajafaja9#La9#La9#La9a9a9blaYaYaYawa0b#b#.paYaYblaY.Rbla9#pblblaYblaYa9#p#D#pa9#pa9#pa9a9a9#pa9a9#pa9bl#pa9#pa9#pa9#pa9#pa9a9#D#Dbla9a9a9a9a9#pa9a9a9#L#Lafa9a9#D#D#Da9awbn.pb#bgamaCbn#xaw#D#D#D.N#x", +"amamaC#x#D#s.7.7a9#Da9#D#D#D.N.N#xaYaYaY#xbna0a0aOaFb#aOb#bg.Vambna0bnaCa0aYaYaY#U.RaYaYaY#Dbl#Da9a9#La9af.7afa9.7a9.7a9bja9bja9#L#L.3#L.3#Laf#Lafa2#L#La2#La2bpa2a2#ga2#ga2a2#g#L#L#L#Lafa9afa9.Nblbl#Da9a9afa9#Laf#L#Laf#Laf#L#L#L#L#L#L#L.7#L#La2#L#La2aja2#Laj#Lafaj#Laf#L#Laf#Lafafajafaf#Lafaj#Lafajafaj#Laja9.n#D#MaY.R#xbga0bnbn.RaYbl#Ua9#pa9#D#Dbl#D#Dbl#Dbl#Dbla9#Da9a9#pafa9af#pa9#p#pa9#pa9#pa9#pa9#pa9#p#D#pa9#Da9a9af#pafa9af.7a9#Laf#L.7a9#s#D#saYaY#Ua0aObgao#x#IaYbl#D#s#D.sbf", +"amaOama0.N.Na9a9bja9#Dbj#D#D#DaY.N#x#x#x#xbnaCa0#H.Vbgb#b#aFbgambnbn#Ubnbnbnbnbn#xaYawaYbl#Da9#Da9a9a9a9a9a9a9a9a9bja9#Da9#sa9#D#Laf#L#L#L#La2a2a2afa2#La2#ga2a2#g#L#g#La2bpa2#L#L#L#Laf#La9a9#pbl#Dbl#Da9a9.7a9#Lajaf#Lajaf#Lajafafajafafajafaf.j#L.3a2#Laf#La2af#Laf#Laf#Laf#L.n#L.n#La9#L#Lafa9afa9aja9#La9af.7afa9#Dbl#IaYawa0a0#UbnaYblblaY#pa9#pa9#D#D#D#Dafa9afa9af#pa9#pa9afa9#pa9a9a9a9#pa9#pa9#p#pa9#pa9#pa9a9#D#Dbla9a9a9a9a9a9.7a9.7af#Laja9a9#D#D#saYawbnaCb#aobn#x.Nbl#s#D#D#D.N.N", +".CamaOao.WaY#D.7#s#Da9#D#D.NaY.N#x#I#xbn#xaY#x#U#xa0a0a0bgamb#ambga0ama0am#xa0a0.RaYaY#Dbl#Dbl#Da9a9a9a9afa9afa9.7a9#D.7#Dbja9.7af#La2#La2af#L#La2a2a2a2a2#L#g#L#ga2a2#ga2#ga2#g#L#L#L#Lafa9a9a9#Dawbl#Da9a9a9.7af#Laf#Laf#L#Laf#L#Laf#L#Laf#L#Laf#L.j#La2afajaf#Lafajaf.Eafaj#Laf#Laf#Lafaja9aj#Lajaf#Laf#Lafajafajaf.n#DblaYaYaCbn#xbnaYaYaY.Rbla9#p#Da9a9.7#La9a9a9a9a9afa9afa9a9afa9afa9afa9#p#pa9#pa9a9#pa9#pa9#p#D#pa9#Da9afafafaf.7a9a9.7#L#Lafa9.n#D#s#D#D#x#Ua0aCaC#x.saY.s#D.7a9.Ebj.N", +"#xa0.8a#.8.Cbf.N#D#D.N.NaY.N.saY#x#xaY#IaYaYaYaYaYaY#x#x#xa0aCam.Vb#bg#yb#.Va0bnaYaYblaY#Da9#D#Da9afa9af.7a9a9a9.7a9bja9#s#Da9.7ajaf#Laf#L#La2#L.3#La2#La2a2#ga2a2bpa2#L#g#La2bp#L#L#Laf#La9af#paYbl#D#Da9a9a9a9#L#L#Laf#Laf#L#Lafafafafaf#Lafaf#La2#La2afajaf#Lajaf.7af#Lafa9aja9aja9#L.n#Lafafa9#L.n#L.n#La9#Laf#La9a9#Mbl#xaY#x#IaYawaYaYaYaYblbl#pa9a9.7#L.7afaf#Laf#Lafa9afa9a9a9a9a9a9a9a9a9#pa9#pa9#pa9#pa9#pa9a9#D#D#Da9af#Lafa9a9a9.7af#Laja9a9#D#D#D#M.N#I#xaCa0#UaY#D.NaY#D.n.7bj#Dbj", +"#x#xa0#vbcaq#xbf#D#D.Nbl.s.NaYbf#x#x#xaYaYaYaYaYaY#M.NaY#x#x.Ca0b#bgb#bgbg.V.p.VawaYblbl#Dbl#Dafa9a9a9a9afa9afa9.7a9#Da9#D#s#Da9af#La2#La2#Laf#La2#La2#La2bpa2bpa2#ga2#ga2#ga2a2#L#L#L#Lafa9a9a9aYaYbl#Da9afa9a9ajaf#Lajaf#Lajafafaj#Lafajafafajafa2#La2#Laf#Lafa9#Lafaja9aj#Laf#Lafajaf#Laf.7afaj#Laf#Lafajaf.Eafajaf.n#Dbl#MaY#IaY#xaY.RaY.RaY#FaYa9a9a9#L#L#Lafa9afafa9#Laf#L#La9afa9afa9afa9#pa9#pa9#pa9#pa9#pa9#p#D#p#Da9a9afa9a9.7a9#L.7.7.naf#La9.n#D#s.N.N#x#UaCbnaY#s#DaY#sa9.7b..7#DaW", +".7aw#x.CaoaB.y.5#s.N#I.Ca0a0ama0#x.N.NaY.NaY#D#Dbl#DblaYawaY#U.CbgbmaBaSaZbma0a0blaYaY#Dbla9a9#Da9af.7afa9a9a9a9bl#D#D#D#D.N#D#D.7a9a9a9a9a9#La9afafafafafaf#Lafa2#La2#L#L#L#La2a2a2af#La9a9#D#DawaY#sbla9b..7#La9a9a9a9.7a9a9a9afa9af.nafafafafafajafajafajafajafaja9a9bl#MaY#s#Da9#Da9#sa9.na9.7af.Eaf.7af#Lafafa9a9bl#M.NaY#Ibn#UaYaYaw#Da9a9.n#p#pa9a9.7.7.7.7a9.7a9.7a9a9#Lafafaf#Lafa9a9a9#pa9a9#pa9#pa9a9a9a9afa9.7af.7.7.7afa9a9a9a9a9a9#L.na9.na9.na9.n#Maw.Nawaw.N#D#D.E.7bj.7#Dbjb.#D", +".7#D.s#x.5.y#va#.NaYbf.Ca0ao#xbn.s.N.N#D#D#Da9#Dbl#Dbl#DaYaYaYbn.p.taBan#uaZ.FbgbnawaYawbl#D#D#D#D#Dbl#D#D#D#D#D#Dblblawbl.N#D#Da9a9a9.7af.7a9a9afafafajafaf#L#L#La2a2a2a2a2#La2#La2af#La9#D#D#DaYaY#D#D#Da9a9.7a9a9.7a9a9a9.7a9#Lafafafaf#Lafafaja9af#pafa9af#pajaf.na9#s#DblaYa9a9.na9a9a9#Da9aj#Lafaj#La9aja9ajaf.nbl#DaYaw#xa0#x.b#xaY#D#D#p#p#p.na9a9a9#L.7a9a9a9a9a9.7a9#Lafafafafafafa9af#p.na9#pa9a9a9afa9af.7a9#L.7#L#La9a9.7a9a9.7.na9a9a9.na9.na9.na9#D#MaYaw.N#s#D.n.7.7.n.7.E#D#D.7", +".7a9aY#xaCam#v#vaCaqa0aqama0#UaY.NaY#D#D#D#D#D#Da9#D#D#Dbl.NaY#Ibnambm#SaZa#a#b#aCa0a0#x#x#xaYbl#D#Da9#Dbl#Dbl#DblaYaYaYaYbl#D#Da9a9a9afa9afafafafafafafafaf#Laf#L#L#Laf#Laf#Laf.j#L#L.n.7a9#s#Daw#x#M#Da9#Daj.7a9.na9.7.na9a9.naf#Lafajafafajafafafajafajafafaf#pa9bl#Mbl#Daw#D.n#Da9#D.na9.na9a9af.7afafajaf#Lafa9a9#sblaY#x#IbnbnaYaYawbla9a9#p#pbl#pa9#D.7.7a9.7a9.7a9a9#L#Lafaf#Lafafa9a9a9a9#pa9.n#pa9a9a9afa9a9#L#Laf.7afa9a9a9a9.7a9a9a9.naf.na9.na9.na9#M.Nawaw#D#s#D#Daj.7aj.7#D.7b.a9", +"a9#saY.s.Ca0aF#v#v.5#vaF.8a0#x#D#D.N#D#Da9bja9.7a9a9bl#D#DaYaY.N.R#Uama#aFaOaFaFb#b#b#a0aCa0#I#xaYblaYblbl#DblaYaw.R#IaYawaY#D#Da9a9a9a9a9a9a9a9a9#p.na9af#La9.7af#Laf#Lafajaf#L#L.3#La9#D#D.NaYaYaYbl#D#D.7a9.7a9.7a9a9a9.7a9.7a9a9a9a9.na9#pa9.n#pa9#pa9#p.na9#sbl#s#Dbl#DblaYa9a9a9.Ea9a9bja9a9.na9#sa9#Da9#Da9.nblbl#D#M#x#x#U#x#UaYaY#Da9#sa9#p.na9a9.7a9a9#La9a9#La9#L#L#L#Lafafa9#La9afa9#pa9#pa9a9a9a9.7#Laf#L#L#L.7#L.7.7a9.7.na9a9.na9.7.n#D#D#s#D#M#D#Mbl.s#D.s#Da9#D.7.na9a9.n.7#D.7", +".N.N.NaY#Uaqamaoa#aB.0a#ambn#xbl#D#D#D#D#Da9.7a9a9.7a9#D#D.s.NaYaY.RaCamamaF.5b#amaob#amama0a0a0#IaYawaYaYaYaYaYbnbnbnaYaYaYbl#D.na9a9.7afa9a9a9a9af#paf.na9afa9.n.7#La9.7a9#L#Laf#La9a9#D#D.N.NaYaY#Dbl.n#D.7af.7a9.na9.na9a9.na9.na9a9#pa9.na9a9a9.na9.na9a9a9aY#MaYbl#sbl#s#D.n#Da9#Da9#sa9.n#Da9a9.7a9.na9.na9a9#DawaY#x#x#xbnbnaYawaYbla9a9a9a9#pa9#Da9a9.7a9.7af#L#L#La9#Laf#Laja9.7a9.7a9a9.n#pa9a9.7#Da9a9#L#La9#Laf.7afa9a9a9.7a9a9bja9#sa9#D#M#D#M#D#sbl#saY#saY#s#D#s.7a9.E.7#D#D#D#D", +"#I.N#I#xamaCamaFaB.Gaz#u.8am#xaY#D#D#D.7a9bja9.7.7a9.7a9#D#D#D.N#Ubna0aCama0amao.Va0amaCama0aC.Cbnbnbnbn#x#Ubn#Uam#Ua0awaYaYaw#D#pa9a9#pa9a9a9#p.na9a9a9a9a9.7a9.7a9af.7afa9a9a9aj#La9.E#D#D#saYaY#Mbl#Dbja9.7.7a9a9a9.7a9#sa9#D#p#D#pbl#sbla9#D#sblbl#Dblbl#sblawaY.N#MaYbl#Dbla9.Ea9.na9.7a9a9#D#s#D#s#D#D#D#D#D#MaYbl.Naw#x#Ibn#I.R#xaY#Da9#Da9a9a9a9.na9a9a9.7a9a9#La9#La9a9#L#Laf#La9a9#Dbj#pa9a9a9#Da9.7.7afafa9.7a9.7#L.7a9.7a9a9#sa9.na9#D#D#D#s#D.sbl#Dawbl#saY#sbj#Da9#s#D.Nbl.saY.s.N", +".Cbf.C.Cam.5aoa#.la5.G.waZ#va0.C#D#D#D.7a9a9#L#La9#L.7.7.7#D#D#D#x#x#x#x#x#xa0bnam.Va0.Va0a0#xbnaY#x#Ia0a0aCa0aCa0ambnbnaYawblbl#Dbl#M#Dblbl#D#Mbl#pa9a9#Da9a9.7a9.7a9.7a9.7a9a9#La9.n#D#D.NaY.NaYaY#D#Da9#Daja9.7a9a9a9a9.7a9.n#D#M#D#sbl#sblbl#D#M#D#M#D#M#D#M#x#xawaY#Dawa9#Ma9#Da9#Da9#sa9#s#D#D#D#D#D#s#D#sbla9blaw#x#x#xa0#UbnaYawaYbl#D.na9a9a9a9a9#Da9#pa9#La9#L#La9.7af#L#L#L.7#L.7.7.na9a9#D#s.7#D.7.7afa9#La9af.7a9.7.na9.na9a9a9#Da9#s#Dawblaw#D.sbl#sbl.s#D#D#s#D#saY.Naw#xaYbf#x#x", +"aqaoamavam.8a##v.5#Saza7.w#u#vam#Da9#D.7a9.7a9a9.7#L.7#La9bj#D#D.Cbn#xbnaYaY#x#x.pb#.Vamaobnbn#xbnbn#xbn#xbn#xa0a0b#aCa0aw.R.Nblaw#Dbl#Dbl#Dblbl#pa9#Ma9a9.nbja9a9a9#La9a9a9.7a9.na9#D#D#DaY.N.NaYaYbl#D#sa9a9#La9.Ea9.7a9a9#Da9#M#Dbl#Mbl#sbl#s#Mbl#sbl#D#MaY#sa0#I.NaYaYblbl#Da9a9.na9.Ea9a9a9#D#D#s#D#s#D#D#D#Dbl#saY#x#xaC.Ca0#x.R#xaY#D#Da9a9a9a9a9a9#p.na9a9a9a9#La9#La9a9#L#L#L.7#La9.7.7a9a9a9#Da9.7af.7a9afa9.7a9.7#L.7a9a9bja9#s.7.na9#sbl.s.saYaw#saY#saY#saY#s#D#s#D#xaY#x.W.C.C.Waq", +"amaFaOaFaOaFama0aY#x.8.0#u#uan#uam#xaY#Da9a9.7a9#Laf#L#La9#D#D.sbl#D#sbl#xaYaw#x.Rbn#Ub#.Va0b#b##Ubnbnbnbna0#xbnbnaYaYaYbnbn#UbnaYaYblaYblawblawa9.n#p#pa9#pafafa9a9a9.na9a9a9a9bl#Dbl#Dbl#sblblawaY#D#Da9.7.7#Laf#Laf.n.7#D.7#D.NaYawaY#xbn#Ua0#U#Ubn#UbnaC#UaY#xawaY#M#D.na9ajaY.N#Dbla9a9.na9.nbl#DblaYaYaw#x#MblaYawbn#Ibna0.b#U.RawaY#Mblbl.na9a9a9a9a9afa9#Dbj#D#D#D#D#D.7#Lafa9afa9.7#Da9#sa9a9a9#Da9.7.7afa9a9a9a9#D#s#D#D#Daw.N.NaY.NaY#D#sbl#saY#saY.N.na9#D#s#DaY.N.N#I#x.CamaoaFbya#", +"bgb#amam.5aCa0.C#M#xa0aFaZ#uaB.0aO#xaY#Dafa9a9a9#L#L.7af.7#D#D#D#D#DaY#D.N.N#xaY.Cbna0a0b#aFb#aF.Vbnbna0#Ubnbn#x#U#x.R#xawaYbn#x.R#I.Raw.RaY#x.R#p#p#pbl.na9a9a9a9a9a9#Da9#s#D#M#Dblbl#sblbl#DblaY#Dbla9#Da9af.7ajaf#L.7a9.n#Da9#M#DaYaYaYaYbnaCbn.paCa0bgaoaC#UaC#I#xaY#MaYblbl#Mbl#M#D.na9a9.n#D#M#D#M#DaY#DaY#M#pawaY#Ibn.Ca0aYbnaY.RaYblbl#Da9a9.na9afa9a9af#D#D#D#D#D#Da9#Daf#L.7a9.7#Da9#D#pa9.na9a9b.a9.7.7a9.7a9bja9#D#D#D#D#DaY#Daw#Daw#D#D#M.N#saY.saY#sbl#sbl.Naw.Nawbna0aCa0.8a#aF.5", +"amamaCa0a0#x#xaYblaY#Ia0bc#u#ua#amam#x#D#Da9.7a9#Laf#La9a9.7#D#Dbl#D#D#MaYaYboaYbna0a0aoamb#aOb#b#am.Va0bnbn#Ubnbn#xaYaY.R#xawaYbn#UbnaCbn#Ubn#U.RawaYblaYblawbl#D#D#D#Dbl#Dbl#Dbl#Dblbl#Dblbl#DaYaw#D#Da9bj.7#La9#Lafa9a9bja9bj#D#MblawaYaw.R#Ubn.V.8#vaB#S#waOaoa0aC#x#x.N#I.NaY.NaY#D#D#D.n#Dbl#sbl#Dbl#saYaYblawaYaYbnbnaCbn#U.baYawaY#M#Dbla9.na9a9.na9.na9#s#D#s#D#s#D#D#D.na9a9a9a9#D#D#D#pa9a9#Da9#D#L.7a9.na9#D.n#D#D#D.saY.saY.NaY.saY#sbl#s#Daw#DaY.NaY.NaY.saY.NaY#x.Wa0a0a0aOam.8a#", +"#x#x#x#xaYaY.N.N.7#D#x#xb#aZ.ya#amaObn#Da9#Da9bj#L#L#D.7#Da9.7a9a9.nbl#D#DaYaY.NaC#xa0.Vamb#aFaF#vaFbga0a0bn#xaY#Ubn#U#xaYaYaYaYbn#xa0a0a0a0aCa0bn#Ubn.baYaYaYaYbl#D#M#Dbl#D#Dbl#Dbl#s#D#D#D#D#MaY#Dbl#D#Da9.7a9ajafaj.7a9a9#sa9a9#M#DaYaYaY.b#xbgb##vaBa7.Q.z#S.5aO.8aoao.Ca0.W#x#I.Naw.NawaY#DawaYblawaYaYawaYawaYaY#U.C#U.Ca0aY#x.RaY#xblbl#D#Dbla9a9a9a9a9a9#D#D#D.NaY.N#s#Da9a9#sa9a9#M#Dbl.na9a9a9a9bja9.7a9a9a9.7#D#D#D#saY#DaY#Daw#DaY.N#M#D#s#Dbl.s.N#M.Naw.N#xaY#x#I#x#Ua0a0aCamama0am", +"aYaYbl.s#D#D#D#Da9#D#s.N.CaOa#aF.5ao#x#Dbl#Da9#Da9a9.7a9.7a9a9.7a9a9a9#Dbl.NblaY#x#xbna0a0amaFaFbmaFaFamaCbn#U#xbnbnbnaY.b#x.R#xaYbn#xbnaCa0bna0#Ubn#Ubnbn#I#xaY.NblaYaYawaYaw#Dbl#Dbl#D#M#Dbl#DaYaY#Dbl.na9.7a9#La9#La9a9bja9#D#MaYblawaY.R#x#U#S#SaB#uaz#u#vaO.8aOaOaOaOaOaOaO.Caoa0.W.C#I#x#I#x#I#x#x#I#x.NaY#x#Ubn#UbnaCbnaC#I.R#IaYawbl.sbl#M#D#Ma9#D.n#Dbl#D#D#s#D#D#D#D#D#Ma9bl#D#D#DblaYa9#p#sa9#D.n.7.7.na9#s#D#s#D.NaY.saY.saY.NaY.saY#s#D#p.s#saYaY.N#IaYaYaw#x#IaY#I#x#x#I#x#x#x#x#x", +"#D#D#D.7.7.7.7.7.7a9a9#DaY.CaO.y.5.5bnaY#D#D#D#D#D#Da9bja9a9.7a9a9a9#Da9#sbl.N#MaYaY#xawbna0aCb#aOaFbgb#b#a0a0bn#Ibnaw#xaYaYaYaY#Ubn#IaYaYaYaYbnbn.R#xaw#x.R#Ibnaw#IaY.sbl.Nbl.N#D#M#Dbl#D#M#DblawaY#M#D#D#s.7a9aj#L.na9.n#D#s#D#DaY#IbnaY#UbnaCaB#SaB#u#uaBaO.5amaoam.8.5aO.y#1#1#u.yaOamamaoamamamaC.C.C#xbn#x#Ua0aC.CaCa0#Ia0.R#x#UaYaYblaY.N#D#p#D#sbl#Dbl#D#s#D#D#D#D#s#D#Da9#p#MblblawaYaY#Ma9bl#sa9bja9.7#Da9a9.7a9#Daw#DaY.saY#Daw#DaY#D#M#D#sbl.N#saY.saY#xbo.N.N.s.N.Naw.N#D#D#D#Da9#D", +"a9.7.7af#Lajbp#L.7#L#La9#DaYa0#va#a0a0.Cbl#D#D#Dbj#D#Da9.7a9#L#L.na9a9a9a9#D#D#Dbl#DaYaY#xaYbna0b#aFb#b#aob#aoambnbnbnbn#U#x.R#xaY.RaY.R#IaYaYawblblaYblaYaYaYawbn#I#x#UaYawbl#Daw.N#D#D.NaY.NawaY#xbl#D#D#Da9.Eafaf#La9#D#D#D#D#I#x#xaCa0aCaoaO.FaO#v#u#u#uaFbgaC.Caoa0ao.5aB.z.U.Oaz.y.y#vbm.y#v#v.5amaoamao.8amaoa0aoa0#Ua0#x#U#xbnaw.N.saY#sbl#Dbl#Dbl#D#M#D#D#D#D#D#D#D#D#D.nbl#Dbl#xaYaYaY#pbla9bl#D#s.7.7.na9#Da9#s#D.NaY.NaY.Naw.Naw.Naw#D#M#D#D#Maw.Naw#x#IaYaY#s#Da9.nbj.7.7b..7.7bp#L", +"#L.7#L#Lbpbp#Lbp.7#L#L.n#D.N.C.5a#amaCaoaY#D#D.N#Da9#Da9#La9#Lafafa9a9#Da9bl#Dbl.n#D.nblawaY#x.Ra0.Vbgamb#amaFaF#Ubn#U#xbnbnaYaYawaYawaYaYblaYaY.bblaYblblblaYaYaYaYaY#I#x#I#x#I.NaYaY.sbl.sbl.NaYaw.N#M#D#sa9.7a9a9.na9.n#D#s#D#xaCa0aoaob##SaBaOaF#S#uaB#v.5aoa0aCamaoao.8#v#v#3ar.wanazaz#3#C#3aX.w.yaOam.8amaCambga0aoa0aCbn#U#x#IaYaw.NaY.NaYaY#sbl#sbl#D#M#D#D#D#D#s#D#D#DblblaY#MaY#IaYawbl.nbl.n#D#Da9#D#Da9.Ea9#D#D#Daw#D#saY.Naw.NaY.N#M#D#s#D.saYawaY#I.N.N#sa9a9.7af#L.E#L#Laj#L#L#g", +"#L#L#L#L#La2bpa2#L.j.7.7#D.Nbf#IaFaBa7an.5a0#Daf#D.7#D.7a9a9#L#L#D#Da9#D#M#D#Dbl#Dbl#Dbl#Dbl#sblaw.RbnaCb#aOaFa#bg.VambnaCbnaw#x.RaYaYaY.baYawbl#pbl.n#Da9a9#D.7#s#D#D#D#D#D#MaYaw#IawaY#x.N#I#x#IaYaY#D#Da9.na9aja9.n#D.N.N#x.CaCb##vaB#uaBaB#v#SaOaOaOaObg.8am.W.WaCaCamaOaB#u#a#faz#Sa#aBaBaz#u#u#uaz.w.wa7#u#uaB.yao.5aC.C#Ia0.pa0aCbnawaY.sbl#saYaYaY#DaYaY#D#s#D#D#D#D#D#D#s#D#sblaY#x#I#x#D#D#D#Da9.n#D#sa9#D#D#D#s#D#D#D#sbl#s#D#saY.saY#MblaY.C.W#I.N#s#Da9#sa9.7.na9.7#L#L#L#L#L#L#L#L", +"bpaj#Lbp#Lbp#Lbpa2#L#L.7#D.Nbfbf.Va#an#uaB.8bn#D#Da9#Da9.7a9ajafa9bl#Dbl#D#D#M#D#D#Dbl#D#Dbl.NblaYawbnamb#aFbm#Sb#.Vaobn#xbnaYaY.baY#MaYblaYblaY#pbl#p.n#Da9.n#D#D#D#s#D#s#D#D#saY.s#x.s#I#x#Ibn.W#I#xaw.N#s#D#D#D#D.NaY#I#x.WaCaCaCaF#SaB#v#SaOaOaOb#aOb#bgamao#x#I.CaCao.8#u.w.OaG.G#SaBaBbmaB#v#v#va#aB#u.G.Galbk#Taz.w#v#v.5bg.5bga0ao.C#IaYaY#Dbl#DawaY#D#M.NaY#D#s#D#D#s#D#D#MaYblaY#I#x#x#M#s#D#s#D#D#D#D#Dbj#s#D#D#D#s#D#D#s#D#Daw#Daw.N#M#s#x#I.Cbf.s#D#D.n.7a9.7a9.7.E.7#L.7#L.7#L#L#L", +"#Lbp#L#g#La2bpa2a2#g#La9bj#D.Nbf.RaCaOaZ.yaFa0aY#D#D#s#Da9a9a9a9#D#Da9#Dbl#D#Dbl#D#M#D#D#M#Dbl#saY#xbnaCa0aOaF#Sb#bg.VbnaCbnaY#xaYaYaY.baYblaYbl#Ma9#p#Da9a9#D.7#D#sbl#Da9#Da9#D#D#D#saY.N#I#I#Iaoao.W#xaY.Naw.N#I#I#U.WaCaoamaobnaCaO#vaF#vaOaFbgambgambg.5.8amav.WaC.CaoaF#uaza6.OazaZaB#vaF#vaFaFam.5aF#v#SaB.G.O#3bv.G.GaPaP.w#u#vaFama0.C.C#IawaYawaY.NaYaYaY#MaYaYaYblaYawblaYaw.NaY#I#x#I#D.N#M#D#D#s#D#s#D#s#D#D#s#D#Dbl#s#p#saY#s.Naw.Nblaw#I#xaY.N.N#sa9.7a9.Ea9.Ea9#L#L#L#L#L#L#L#L#L", +"#La2bp#L#Lbp#Lbp#L#L#L.7#Dbj#D.NaYbna0aoa##vam.C#D#D#D#D.7#D.7a9a9#D#Dbl#D#Dbl#Dbl#Dbl#Dbl#D#DaYaYaYawbna0b#aO.Fbgb#ama0bnbn#IaY.bblawblaYaY#MaYa9#p#sa9a9#Da9#Da9a9a9a9a9.na9a9#s#D#D.saY.NaY#x.C.C.C.W#I#x#I.WaF.8a0a0a0a0aCa0aCaCb##vaFaO#vbgaob#aoaoamaoaCam.W.Caoa0.8#v#ubkab#aan#vaZ#vaFa#aoaobga0aoamamaOa#aBaZ#u.w.w.G#3#3#a.w.y.yaOb#aCbnbn#I#xbn#UaYawbfaYbfaw#x.s#xaY.NawaYbl#x#Ibn#I#Daw#D.s#D#s#D#D#D#D#D#D#D#D#s#D#D#Dbl#saY#saY.saYaw#xaw.N#s#D#D.7.n.7a9.7a9.7#La9aj.7#L.E#L.7#L", +"bp#L#L#g#L#g#La2#g#L#L#L.7#D#DbjawaYaCamaoa#.8aF.N.s#D#D#D.n#Da9#sbl#D#D#M#D#D#M#D#M#D#Dbl#sbl#saYaY#x#UbnaCb#b#bgb#bga0aCbn#x.RaYaYaYaYawblaYbl#p.n#pa9a9.nbja9.7a9.7#sa9#D.7.na9a9#D#D#D#saY.s#x#I#I#x.C.Wa0aoaoama0.W.C.Wa0#Ibn.paO#S#v#v#S#Sbgaoaoa0aoa0avaCaqaoavao.8#v.w#T.Y#3an#va#aOamaOa0bnaoambgamaoam.pa0bgb#aoaFaO.ybk#T.GaXaz.waBbyaCa0a0bnaCa0#Ibn#I#x#x#x#x#x#xaC#x#I#x#I#x#I.C#IaY#saY#saY#D#M#D#s#D#M#D#M#D#D#D.n#M#D.s#DawaYaw#x#IaYaw#sa9.7.n.7#L.7aj.7#L#L#L#L#L#L#L#L#L#L#L", +"#L#g#L#g#g#gbp#L#L#L#L.7af.7.7.7#D.N#xaob#.8a#a##DaY#D#D#D#Da9bjbl#D#Dbl#Dbl#D#DaY#DaY#D#M#DaYaYaYawaY#x#Ibna0aCbgb#bg.VaCbn#U#xaw.Raw#FaYblaYbl#D#p#Da9#Da9a9#Dafaj#Laf#Lajaf.7a9#Da9#sa9#D.Nbl.NaY.NaYaY#I.C.Wamaoaoaobga0aoa0aCam#vaBa##SaBaBaobgaoaoaC.Waqaoav.8ao.5aOaBazaX#4alaza##vaOam.5aC.Wa0.Wa0aob#.8bnaCaCaCaC.W.WaC.y.yaB#ubkbkaX.Oazae#vaO.5ao.pbga0a0a0#Ua0aCa0ao.CaCaCa0#IaCa0#IaYaw#D.sbl#s.N#s#Dbl#D#s#D#D#sbl#D#D#saYaw.saw.NaC#xaw#D#sa9.n.7a9aja9#La9aja9#L#L#L#L#L#L#L#L#L", +"#Lbp#ga2bpa2#L#g#L#L#L#L#L#L#LafbjaYaY#xama0.5aO.N.NaY.s#D#D#Da9#Dbl#s#Dbl#Dbl#D#M#D#M#DaYblaw#D#MaY#I.R#U#x#U#Ub#b#bga0aCa0#x.R.Raw.RaYawaYblaw#p.n#pa9.na9#Da9aja9af.Eaf#Lafajafaja9#Da9#s#Daw#D#s#D#s.NaY.NaY#U#Ua0.paobgb#bgaO#vaB#u#u.y#ua5aObgaoamaoamaoavam.8.8#v#v#u.w.GaTbw.G.0#vaFaoamaoa0aoama0aqamaoamaCaqaC.W.W#I#Iaxbgaobg#va7.Oau.U#3#3a5#uaB#vaFaoaoa0amaCamaob#aoamaoaoa0aC#Ibn.sawaY.sbl#saY#s#D#s#DaY#saY#D#D#s#p#s#DawaY#Iaw.C#I.N.naf.Ea9.7aj#L#Laj#L#L#Laj#L#L#L#L#L#L#L#L", +"a2#L#g#g#g#gbp#L#L#L#L#L.7#L.7#L.N.N.s#x#xao.5b#.NaY.N#D#D#D#D#D#M#D#Dbl#D#D#sbl#D#Dbl#Dbl.sblaY.NaY#x#I#x#U#UaC.Vbgb#bgaCaC#U#I.R#x.baY.RaYblaYa9#pa9#Da9#Da9bjaf#Laf#Laf#L#La9#La9a9a9.7#Da9#D#sa9a9a9#D.NaY.Na9#paY#Ua0aoaO.yaBaBazazan#u.Gbk.daOaO.8aoavao.8.8.8bd.yaL#uazaX#0#4#TaZaOaO.5aoa0.Camaoamaoamambcby.8.C.C.W.W.W#U.rbgaO#S.yaB#uaP#3.U#3arbk#u#vaFbgbgaob#aob#bgamaOaoaoaoaC#U#IawaY.sbl.s#D#Daw#DaY#s.N#M#D#s#D#s#D#M.NawaY.s#xaC.C#Ma9aj#L.7.naf#Laf#Lafaj#Laf#L#L#L#L#L#L#L#L", +"#g#g#Lbp#Lbp#Lbpa2a2#L#L#L#L.7#L#D.N.NaYbo.C.C.W.Vbn.N#Dbjbj.E.7#D#D#D#D#s#D#D#D#D#s#D#s#D#D#D#sawawaYaw#x#U#xaCa0aCa0aC.Vamb#a0aYaw.RaY#M#p#M#pajafaj#pa9a9#Mbl.na9a9a9a9a9a9afajafaja9#D#s#D#Dbl#D#s#D#s#D.n#Dbl#saYaYaw#x#IaCaOaB#1a5.w.wbkaV.Qbt.ybcbc.8bcbcaBaB#u#uaz.waP#T.O#zbw.6aF#vaOaFambga0amamaOaoaOaoaCa0.WaC.W.C#I.WaCaoaOaoaOaobg#v#v#S#1.Q#3agaV#1aB.8aOamaoaCbg#v.8aoa0aC#x#U#Iawaw#D.s#D#s#D#s.N#saY#s#Daw#D#Mbl#saYaw#x#I#xaC#D#sbj#D#D.7#s.7.7.E#L.7#Laf#L#La2a2a2#ga2#g#g#g", +"#gasbp#g#Lbp#Lbp#L#g#L#L#L.7af.7#D.NaYbf#x#x#x#xaCbn#I.N#Dbja9.7#D#D#D#D#D#D#D#D#D#D#D#D#D#s#D#DblawaYawbn#I.WbnaCa0.pa0aoa0aoam#UbnaYaYaYblblbl#paf#p.n#pa9bl#Da9a9a9aja9af.na9.7af.7a9a9a9#D#sa9#M#D#D#D#D#D#D#D#D#M.NaY#x#x#xa0am#vaB.z#u#Ebi#nbCaX.Q.y.y.QaXbka5#u#u.w.wbkaP.O#4#4.wa##v.5a#aoamambg.5aO.5a#aoamaC.WaC.W.W#IaCaC.WaCaoaoaoao.8bg.8#v#v#u#uaPagagaXbka5aBaBaB.y.z#S.8bgaoamaC#x#IaYaw#D#sbj#D.sbl.sbl.N#saY.s#D#MaYawaY#U#x#Ibj#s#Db.#Db.#Dbj.na9#La9aj.7#L#La2#ga2a2#g#gas#g", +"#ga2#ga2#g#g.7bpa2a2#L#L#L#L.7#L#D#D.N#M.N#I#x#xa0a0#x.s.N.N#D#D#D#s#D#D#D#D#D#s#D#s#D#D#s#D#D#M#D#MblawaYaw#x#I#Ubn#Ua0.pa0.pa0aCbn#Ubnaw.Rawbl.n#p#p#pa9a9bl#Dafa9a9#pa9a9a9afajafaja9.7#D.n#D#Dbl#D#s#D.n#D#s#D#D#DaY#saYaw.N#UbnaCaOaO#vaBbkbq#Rbqag#3.U#zaVau#Tazazbkbkbv#3#E#0ab.2#uaOaF#vaFaOaOaFaObyaO.8aCaCaC.C.W.W#I.W.WaCaC.WaC.WaCaCaCaCaoao.8.8#v#vbbbbap#3.U.U.U#4a5#E#1#SaFaOaOaFaC.W#x#IaY.s#D#saY.s#xawawaY.saY.sbl.NaY.s#x#x#Ia9.7.E.7.E.7.n.7a9#L.E#L.7#L#L.7#L#L#L#L#ga2bpbp", +"#g#g#L#gbp#g#Lbp#L#g#L#L#L#Laf.7#Da9#D#DaY.N.N.sbn#Ua0.C#x.N#s#D#D#D#D#D#s#D#D#Da9a9.na9a9a9a9#Dawbl#saYawaY#U#x#U#x#Ubn#Ibna0aCa0a0#UbnbnbnaY.Rbl.n#D#p.n#pa9bla9af.nafa9afa9a9#Laf#La9a9a9bja9a9a9.na9a9.7a9.7a9a9#s#D#DaY.Naw#xaw#xaCamaoaOaB.v.O.Obqadbx.abzbi.U#3#T#3bvagag#3#4#caT.w#vaF.y#v.5#vaOa#ao.5.5aC.CaC#I#I#I#Ibo#I#Iaw#Iawaw#I#U#7.W#IaC.WaCav.W.8#v#v.y.w.G#T#3.Oag.O.w#uaB.ya#aoamaC#x#I#x.N.s#xaw#I#x#Ibfaw.Nbl.s.Naw.NaY.saY.E.7af.Eaf.7#L.E.7aj.7#La9aj#Lafajafaja2#L#ga2#g", +"#ga2#ga2#Lbp#Lbpa2a2#L#L#L#L.7#La9.7a9#D#D#DaY.NaY#xa0#U.CaYbl#D#D#D#D#D#D#D#D#Da9a9#Da9#sa9.na9#D#M#Dbl#saYawaYawaYaYawbn#Ibn#IbnaC#xbn#Ibna0bnblblbl#Dblbla9a9.na9a9a9a9.na9a9af#L#L.na9bja9#D.na9a9a9.n.7.n.7.Ea9.7a9#s#D#D#D#sblaw#IaCaobg.d.O#ia5.G#zadadadabadaVaVbq#3#3bvbqaba8.YbkaBaO#uaFaOaFao.5aoaqaC#I#I#Iaw#I.s.sawbobo.sbo.sbobo.s#M#M.s#7aw#Iaw#I#U#IaCao.8aO#v#u.Q#3biag#3aXazaZ#vaOam.C#x#I#IaY#I#x#I#I#x#I#xaw.Naw#D#s#D#s#Da9#Laj#L#Laj#Laj#L#La9#L.E#L#L.7#Laf#Laf.7#L#L#L#L", +"a2a2#L#g#L#L#L#La2bp#L#L#L#L#L#L#L.7#La9.7#Da9#D#DaYbnama0#xaY#s#D#D#s#D#D#D#D#Daj#Lafajaf#La9a9.na9#M#D#MaY#MaYbl#MawaYaYaYaw#x.RaY.b#xbnbn#Ibnaw#xawbl#D#Ma9#pafa9afa9afa9afa9aj#Laf.7a9.n#Da9ajafa9aja9#L.7#Laf#L.E#L.7.Ea9#sblawaw#xaCaCaO.8aBazbka5.Gbk.U#3biad.a.a.DaVaVaV.M#d.S.Yaz#u.0.y#vaF.8a0.W.C#I.C#Iaw.Naw.s.s.s#s#s#s#s#s#s#s#s#s#s#s#s#M#s#s#s#s.n.n#M.raC#OaO#w#u#E.vbkazbkbkbk.w.yaOamaC.C.C#I#I#I#x#I#x#I#x#Ibf.s.N#s#D.7a9.E#L.E#L.E#L#L#L#L.7aj.7af#L#L#L#Laf.nafaj#L#L#Lbp", +"#gaa#ga2#L#L#L#Lbpa2#L#L#L.7#L.7#Laf#L#L#La9.7#D#saY#xa0ama0aYaY#D#D#D#D#Da9#D#Daf.7aja9#L.n#Laj#p.n#p#Dbl#s#DaY#sbl#D#MawaYaYaY#Mblbl.baYawbnbnaYaYaYaYbl#D#pa9a9a9a9a9a9a9a9a9afafaja9a9bja9#Dafafajaf#L.Eaf.Ea2#Lafaja9a9#s#D#sawaw#IaC.WaoaoaO#uae#1#u#uaz#u.O.Ubi.D#d.D#J.D.abu#6.Y.G.w.yaZ.8aoam.W#xaw#I.saw.saw.s.s#s#sbj.Eb.#sb.b.#sb..E#s#s#s#s.s#s.E#s#s#s#s.r#U#IaCaCbd#1#SaOao.ya5bkaza5.waOamaoaC#x.WaC.W#I#x#I#x#I.Naw#D#D#s.7#L.7#Laj#L#Laj#Laj#Laja9#L.E.7.n.7.Ea9a9a9a9a9.7#Laf", +"a2#g#L#g#L#L.7#La2#g#L#L#L#L#L#L#La2#Laf#Lbja9a9#DaY.C.VaFa0#xaw#D#D#D#D#D#D#D#Dajafaf#Laf#Lafaf#p.nbl.n#Dbl#M#D#Ma9#M#DaYaw#Dawbl#MaY#Mbn.RaYawbn#xaw#x#Mbla9.naf#paja9af.nafa9aja9#La9a9a9#s#Daja9#La9#Laf.7#L#Laj.n#L.7.n.7#s#Daw#x#I.CaC.8.8#v#v#v#vaO.z#1.z.Gbk.O#zbibBbBad.x#5#9.YaPaz.y.0bgaoam#Iaw.N#s#Dawaw.s#s#D#s#s#s.E.7.E.7.E.E.E.Eb..Eb..E.E.E.E.E.s.saw#IaC.WaC#Oam.d#vao.8aFaO.8.G#3.OaB.8amaCaCaC.Wa0#I#I#I#I#x.s.N#s#D.na9.n#Laj#L#Laj#Laj#Laj.7#L.7af#L#Laf#Lafa9a9.na9a9.7.7", +"#L#L#L#L#L#L#L#L#La2bpa2#ga2bp#L#L#L#L#L.7a9.7.7.NaY#xbnao.VaF.V#xaY#Ma9.na9a9#D#La9aja9aja9aj.7.na9.na9.na9.na9#p#s#p#D.na9a9.n#p.nbla9#sbl#saYaYaYaYaYaYaYaYaY#pa9#p#pa9#pa9.nafafaja9#D#D.N.N.nafajafaja9ajafajaf.7.na9#D.n#D#Dawaw#I.W#IaCaCaobdaO#v#v.y.y.y#u.QaX.9#TbC#r#r.aatatbB.2aX.GanaC.W#Ibobf.sbf#I#s#s#s#sb.b.bj#s.7.E.E.E.7.Ea9.Eaj#Lajajajajajaj.s#s#I.s.s#I.s.WaCaCaCaCa0.W.W.W#v#vbtbkbk#uaB.0aObgaoaoamaC.C.W.n.na9.E.7.E.7#Lbjb..Ea9aj#L#La2a2.jbpaj#L.E.7bjajaf#La9#Laf#Laf", +"#L#L#L#L#L#L#L#L#L#ga2a2bpa2a2a2#L#L#L#L#L.7#L.7#DaY#Ibnb#b#aOb##xaY#D#Da9.n.7#Dafajaf#Laf#Lafafa9aja9a9.na9.na9.na9.na9#p.na9a9afa9.n#p#D#M#DblaYawaYaw#xaw#xaY#p.na9a9a9a9#p#pafaf#pa9#D#s.N#sa9a9#La9#Laf#Laf.7aja9.n.7.n#Da9.saYaw#x#I#x.W.WaCao.8.8aObc#v.y#v#ubkbvbvaXbvbC.k.Dai.UaXbv.Ga7aOaoaNboaWbo.s.Nb.#sb.#D#s#sbjb.b.a9b.a9.E.7.Ebjajaja2aj#Laj.naj#D#s.sbo#I.sbo.saCaCaC#I#I#I.W#xavaoaO.y.z#1bkbkaBaBaO.5aoaoav.Wa9#s#L.E#L#L.7.E.7#D.7.E#L#L#Laja2bpa2#L#L#L#L.7af.7afajafaj#L#L", +"a2#La2#ga2#ga2#ga2#L#ga2a2#g#L#g#L#L#L.7af.7a9.7#Daw#x#xam#SaZa#aC#xaYa9a9a9#Da9aja9#L.n#L.n#Lajafa9.naf.na9a9.na9a9.na9.na9a9.n.na9a9.na9#D#D#saY#x.R#xaYbn#x#xblblbl#Mblbl#Dbl.n#p.nbl#D#D.N.N.naf.nafaja9#L.n#L#La9.7.n#D#s#saYaw#I#I#I#U#Ia0.Wao.8aObc.8.y.y#u#ubk#3bCapbkag.kbqaX.Q.Qbka5#u#v#vamava1bob..E.na9b..E#s.7.E.E.7.E.7.E.7.E.7.naj#L.jaja2ajajaj.n#D.s#I.s#I.saY#I#U#x#I#x#x#Ibo#x#I.CaoaO#v.y#1bkbk#u#vbcam.C#I#sa9.n.7.E#L.E.7#s#s.7.n#Lajbpa2bp.jbp.j#Laj#L#Lajafajaf#La2afa2", +"#ga2#ga2a2a2#g#La2#ga2#g#L#ga2a2#L#L#L#L.7.7#La9#D#D#xaCaF.0aZana0#xaYbla9.na9#D#Laf#Laf#Laf#La9af#L.na9af.nafa9ajaf#Laf#Lajaf#Lafajaf#L#D.n#D#DawaYaY#IaY#I#x#IaYawaYaYaYawaYawbl#Mbl#D#sbl.s#Da9.na9.7afajaf#Laf.Ea9.Ea9#sa9#s.N#I#x#I#x#Ia0#I.Wao.8.8aObc.ybba5bkaXaX#3bvag#n.c.#bt#baLbcbdaBaB.y#vam.Wbfb..7#s#s#s.7.E.E.E.7#s.E.E.7.n.7.E.7aj#g.ja2.jaja2#L.E.n#s.s.s#I.s.s#x#I#I#x.s#I.Nbo#x#I#I.CaoaoamaObkaz.Q.z#v.8.Wbf.N#s.N#s#D.sa9.E#D#D.E.7#L#Laj#Laj#g#L#g#L#gbp#L#L#L#L#L#La2bpa2", +"a2bpa2bpa2bpa2a2#g#La2bpa2a2bpa2#L#L#La9#L.7a9.E.7aYaY.Cam#vaZaZaobn#xbla9a9a9#s#L.n#L.n#L.n#Lajaf#Laf.na9a9ajaf#L#Laj#Laf#L#Laj#L#L#Laj.7a9.7a9#D#Dbl.NaYaY#xaY#xaY#x#U#xbn#IbnblaY#MaY.NaY#s#D.na9aja9af.7af.E#Laja9a9b.#D#s#Daw#x#I#I#x#I.Wbn.Wa0aoao.5.8.y.QazaX#3.O#3aVai#n#8aLax#O.W.Wao.8#1aB.y.5.Ca1bo.sbo#D#sb.#D.E.7aj.7.E#D.E.7.E.7.7.ja2.j#gbp.jaj.j.7#s#s#s#s.N.s#Iawaw#D.saw.N.s.s#D.s#x.W.WaoaC.8.0.y#v#v#v.d.8ao#I#Ibf.s#Db.bj.7#Dbj#L#Laj#L#L#La2aj#gaj#ga2asasa2a2a2a2#La2a2#g", +"#ga2a2a2#ga2a2#ga2a2#ga2a2#L#ga2#L#L#L#La9.7.7a9.7.N.s#xamaF#va#.5am#x.N#D.na9.7af#Laf#Laf#Lafa9#L.n#La9.naf#Laf#Lajaf#L#Laj#Lafa2ajaf#Laf.7.7.na9.n#D.nbl#D#DawaYawaY#U#x#U#x#UaYaw.Nblaw#D#D#sa9.na9.nafajaf#Lafaj.7.na9#sa9#saY#I#I#xaC#xao.CaCavaoao#v.yaI.Qae.O#zaV.Dah#Xag#b#O.r#7#7#7.W#QaObdaB.y#vaoaqbo#Ibobf.N.Ebj.E.7.E.E.7.E.7.E.7.Ebp.j#g#g.ja2#L.j.E.7#s.nb.#s#D.saw.Naw.s#D.s#s.N.s.sbo#I.C.Wam.8bgbgamao.C.8axbcaxaoaobo.N#s#Db.#s.7.E#L#L#L#Laj#L#g#La2#gas.jasbp.j#L#g.j#g#L#g", +"a2asa2asa2aa#ga2#g#L#g#Lbpa2#L#L#L#L#L.7.7.n.7.7a9.saYaY.Wa0amam.5am#IaYbla9a9a9aja9aja9aja9ajaf#Laf#L.na9#L.n#Lajaf#L.jafa2a2.ja2a2#Laj#Laja9#L#Laf#Lafa9.n#D#DaY#xaYaYaYawaY#U#xbnawaY.Naw#D#sa9.na9af.na9.na9.Ea9.na9.E#D#s#D#I#x#I#x.WaCaoaoao.8.8.8.y#1#1.Q#T#3bq.D#m#haibkavao#7aE.sbo.W.W.s.Wbd.GazaBbc.8##avbobfbobjbjb..7.7.E.7.E.7.E.7#g.j#g.j#g.jaja2.Eaj.n#D.nb.#sb.#D#s#s#D#s#D#s#s.s.N.N#I#x.Wam.WaC#x#I#xaCa0av.8.8.8ao.W#Ibo#s#s#Dbj.7#Lajaj#L#Laj#gaj#g#gasasaU#g#g#ga2bp#ga2#g", +"a2a2#ga2a2#ga2a2a2#ga2aja2bp.ja2#L.7#L#L.7a9.7a9bj.N.N.N#xa0a0aCaF.5bnaY#D.na9.7af#Laf#Laf#Laf#L.n#L.na9.naf#Laf#Laja2#La2aja2#La2aja2#Laf#L.E#L#Lajafaj#La9#L.nblblbl#MblaYaYawbn#U#x#xaw.N.s#D.nafa9.na9a9a9.na9aj.7#sa9#sa9#s#x#I#x.Wbnavamaoao.8aObd.ybt#ubbag.O#3bA.iaJ#3bbav.h#7b.b.boa1#IaE#I#QaB#uaPaz.Gbcbcavavbobfb.bj.E.7.E.7.7.E.7#L.j#g#g#gaj#g.jajaf.E.n#s#s#D.E#D#s#s#D.s#Db.aW#sbf.Nbo.C.Wav.Cam#Mblaw#x#Iaoaqaoaqavavaoav.s.Nb.#D#s.7.E#L#Laj#g#Lbpa2asas.jaUaU#ga2bpa2#g.jbpa2", +"#ga2#g#g#ga2#g#ga2#g#g#ga2#g#Lbpa2#L#L#L#L#La9.Ea9a9#saY#I.C.Wam#x#U#x#IaY.N#D#Daj#Laj.7.7a9.7.7a9#Laf#L#L#L.n#Lafafafajafaf#Laj#L#L#Laj#Laf#Laf.jaf#Laf#Laja9#Da9.na9#Da9.n#D#DawaYawawaYaY#MaY.7.n.7.n.7.Ea9.7ajaf.Ea9#s#D#D#D#Ibn#UaCaoao.8#vao.d.d.y.z.y#1bbagaX#3aAbx.caLav#7#I.s#7b.#sb.b..sbo#Iav#QaOaKbtau.GaZaFaq#Ibf.s.7.n#L.E#L.7aja3.Ebp.jbpbpajbpa3#s#D#s#s#s#s#D#sa9.n#D#s#D#s#D#s#x#Iaw#I.N#s#s#D#saY#saYaY#I#I#I#I#U.W#IaC.8ao.C#sa9#L.7.n#L#L#L.ja2.j#gasasas.jas#g.jas#gas#gas", +"a2#ga2#ga2#g#ga2#ga2a2bp#ga2bp#Lbpa2#L#Laja9.7#La9#D#D.N#x#x.C.CbnbnbnaYaY#D#D#D#L#La9aja9.7.E#D.nafajaf.Eafafaj#Lajaf#Lafajafaf#Lafajaf#L#Laj#L#La2afaj#La9a9.na9bja9.na9#D.na9awblaYawaYawaYawa9.na9.Ea9a9.na9ajaj#L.n#D#s#s.N#U#Ibn.WamaO.8#v#OaObdbd.yaLbb.Q#8.v#3aV.abCbd.8#7#7.sb..sb..sbj#s.s.s#I.Cav.8.8#u#uaB.ybcao.Wbf#D#s#D.7.E.7.Ea3ajbpajbpajbp#L.E#s#D#s#D#s#D#s#D.n.7#s#D#s#D.s.N#x#I.NaY.s.N#s#D#s#D#M.N.s#I#x#I#x#I#x#IaCbd.8ao#s#D#s#L.7aj#L#L.j#gas#g#g.j#gas.jas#gas#g.j#g#g", +"#g#La2#ga2#ga2bpa2bpa2#L#L#L#g#La2aj#L#L.7.7a9.7.n#D#saY.s.N#x#I#x#xawaY#Ibl.N.Naf.E#La9.7#sa9#D.n#Laf#Laf#La9afaf#Lajaf#Lafaj#Laj#L#L#Lajaf#Laf.j#Laf#Laf#La9a9a9a9.n#Da9.na9#D#D#s.N#s#D#s.N#s#D.Ea9a9.Ea9.7.na9.na9#s#D.s.N#x#Ibnbn.Waobg.8.8.d.d#vbd#v.z#1bb.QaX#3aA.kaXbcao#7.s.sb.b.b.b.#s#s#D.s.N.s#x.CavaFam#v.y#u.ybyby#Ibf.s.Nb..7.E#L.7.E#L.7.E.7.E.7#s#s#D#s#D#s#D#s#D#s#D#s#D.s.N.s#x#IaYbo.s#D#saW.n.7#s#D#s.N.s.s#I#I#I.CaCax#vaO.saw#s#D.n#Lafaja2a2.j#gas#g#g#g#g#g.j#g#gas#g.j", +"#ga2#ga2#g#L#ga2#ga2#g#L#g#L#L#L#g#L#L#L#L.n#L.7#D#D#D#DaYaY.N.NawaY#xaY#x.NaY#Ma9.7a9.Ea9#D#Da9a9af.7af.Eafaj#Lajafafafaj#Lafaf#Lafaj#Laf#Laj#La2af.j#Laf#La9.7a9.7a9.7a9#Da9a9#s#Dbl.saY#saY#s#D#s#D.na9.Ea9.7a9.n#D#s.N.s#xbobna0aCa0am.8aOaO.8#vbd#vbd.yaL#1.Qbk.Obi#R#8#v.rbo.saE#sb.#sbjb..7.E.n.E#s.s#I#xbo.Wavbc.y#u.yanaoaq.Cbo.N#D.E.7.E.7#L.E.7.E.7#s#D#s#D#s#D#s#D#D#s#s#s.N#s.Naw.N#x#xaw.N#s#D#sbj.n.7.E#DaE#saYboaCaCaoaoaoao#Oao#Iawaw#s#D.n.7a9aj#g#L#g.j#ga2#g.jas#gas.j#gasas", +"a2bp.jbpa2#ga2bpa2bpa2#L#Lbp#L#L#La2#L.7#L.7a9.7#s#D#D#D#D#s.NaYaYaY.s#x.s#xaYaY#D#s#D#D#D#s#D#sa9ajaf#Laf#La9af#Lajaf#Lafajafaj#L#Lafaj#L#L#L#L#L.jafa2#Laja9a9.na9a9.na9.na9#s#D#D#s#D#s#D#s#D#sa9#sa9#Da9.n#D#s#D#D.saY#xaY#IamaCamaobgaObcbdaOax#vbd#v#v.yaL#1.Qa5#3#R.vbc.W#7#s.sb.b.bjb.bj.E.7.Ea9bj#s#Daw#s.Nbo.C.8#van#ubc#v.8a0bf.s#D#sbj.7bj.7#D.7#sbjawaY#saY#s#D#s#Daw#DaY.saY.NaY.saY.saY.N.s#D#s#D.Ea9#s#s.N.sboawao.8.d.daoaC#I#x.sawbo#M#D#Daj.7#L#L.jbpa2bpa2#g#g#g.j#gas#gas#g", +"#ga2#ga2#g#L#g.ja2#g.jbpa2aj#Lbpaj#L#Laj#Laf.7af#D#D#s#D#D#D#D#D.N.saYaY#xaY#x#IaY.N#D#D#s#D#Da9#L.na9.na9ajafajaf#Lafajaf#Laf#Lafaj#L#Lajaf#L#La2a2a2#Laf#La9a9.7a9.7#Da9bja9a9.7#sa9#D#s#D#s#D#s#D#D#s#D#s#D#sa9#s.NawaY#I.C.WaF.8b#ao.8bg#vbd.8#vbd#vbd#v.d#v#1#1.wagbi#8ao#O.saE.sb.#sb.#s.Eaf.Ea9.E.n#D#s#Db.#s.N#Iaqambca#aB.y#vaO#I.Cbf#I#s#Db.#Db.#Dbj#saYawaw#D.saY#M.N#M.N#saY.s#x.s#x.s#x.s.N#s#Db.#D#Db..N.s.N#Ibo.W.CaoaxaoaxaCaC#I#x#I#I#Iaw#s#D.n#Laj#L#Lbp#L#L#L.j#ga2#g.ja2.j#g", +"#L#g#L#g.j#ga2bp#g#L#g#L#Lbp#L#L#La2.7#L.7.Ea9.EaY#D#D#s#D#s#D#saYbl.NawaY#UbnbnawaYawbl#D#p.na9afa9.n#La9#La9#Lajaf#Lafajafajaf#L#Laf#L#L#La2.ja2#La2#L#Laf.7a9a9a9a9.na9.na9a9.7a9#s#D.n#D#s#D#s.N#sbj#D#D#s#DblaYaw#x#I.CaCamaOaF.8.8aO#vbdaO#v.d#vaO.8aObd#v.zaBa5.O#r.Q#O.Wbo.s.sb.aEbjb.bjb.a9.E.7.n#s#D#s#D#D.s.N#Ibf.W.C#v#va#aOaF.8aoam.s#D#s#D#s#D#s.saYawaYaYawblaYaw#DaYaYaYbl.N#x#xaY.saY.N#s.N#saWawaY#I#x#I#x#IaC.C.WamaCaC.W#I#I#I#x#I#I#I.s#sa9.E#L.E#Laja2bpa2a2.j#ga2#ga2#ga2", +"aj#g.ja2#g#L#ga2#ga2#ga2bpa2#L#L#Lajaf.Eaf.7a9.7aY#s#D#D#D#Da9a9.saY.saYbn#x#xa0#I#x.NaY#M#Da9.na9aja9a9.nafajafafafajaf#Laf#Lafaj#Lajafaja2#L#La2.3#L.jaf#L.na9.7.n.7a9bja9#D.n.7#sa9.n#D#s#D#s#D#s#D#D#s#D#s#DawaY#Ibn#Ia0aoa0#v#vaOaFaObd#vax.ybc.d.8.8.8.8bd.y#1a5aX.v#1ao.W#7.saE.s#sb.#Db.#s.7.E#D#s#D#sa9#s#D#s#D#s#D.s.saFaFamaO.y#v#v.5#I#Iawbf.s#x.s#xawaYawaYblaw#DblaY#Mbl#saYaw#x#I#x.Naw.N#sbj#s#D#I.WaC.WaC.Wamao.8aoao.W#IaY.NaY.N.N.s#D.saw#s#D.n.Ea9aj#Laj#Laj#ga2#gas.j#g.j#g", +"a2#ga2#ga2aj#L#L.ja2a2aj#L.E#Laj#pa9a9#pa9.n#pa9#M#Dbl#Dbl#MaYaYaYawaYaYawaY#UaYa0.p.VbnaYawa9#La9a9ajaf#L#Lafaj#L#L#Laj#Laj#L#Laf#L#L#L#L#La2#La2a2#La2#La2#L#L#L#L#L.Ea9.7#s#D#La9.E#D.na9.na9.n#s#D#saw.Naw#xaw#I#x#I#U.CaCaoao.VaoaoaO.8aO.8#Oaoaxao.haC#Oao.daO#uagbibk#vav.W#I#s.E.Eaj.Ea3aj.n#L.E.7.nb.#s.N.saY.N#I.N#IaY#I#I.C.8#v.yaBaPaBa#aFa#.5aqaqaN#xbfbf.N.NaY.Naw.NaYaY.Naw.NbfaYawaYaYaw#x#I#xa1#U#I#U#I#x#I.N.s#D#s#D#Dbj#sbj.E.7.Ea9.7.7#L.7.7.7.7.E.7#L.7#Lbpa2.jas#g#gas#gas", +"a2.ja2#L.j#L#La2a2#g#L#Laf#L.7#La9#pa9a9#pa9#pa9bl#Dbl#sbl.NblawblaYblaY#xaYaY#Ubna0b##UbnaY.n.7#s#Da9.na9.n#Laf#Lajaf#Laf#Lafaj#Lajafaj#L#L#L.j#L.j#La2af#La9a9#L.7#L#La9.7a9#Da9.Ea9.n.7.n.7#s.na9#M#Daw#x.s#xawbn#I#U.CaCaCaCaobgaCaoaOaOax#vao.hao.W.W.Wav.haoax.y#E#zagapbc.Wbo.s#s.E.Ea3.E.7aja9.Ea9b.a9.EaY.Naw.Naw.Naw.N#I#x#Ia0amaF.yaBa7#u.ya#aoaqavaq#x.C#x#I.Naw.NaYaw#x#I#I#x.s#xboaYaY#I#x#I#x#IbfblaYbl.NaY#D.N.N#Dbj#sbj.Ebj.7bja9#L.E#Laj#Laj#L.E#L#L.7aj#La3ajas#g.jas.j#g.j#g", +"a2#gas.ja2#L#Laja2#Laj#L#L#La9.7.na9a9#Da9#Da9a9#s#D#D#s#D#s#D#Dbl#sbl#D#M#DaYaYaY#Ubga0bnaY#s#D#s#Da9a9.na9ajafaj#Laj#Laj#L#Laf#L#L#Laf#L.j#L#La2a2#La2#Lafa9a9ajafaja9a9#s#D#s#Da9.n#D#sbl#s#D#M#s#D#Maw.N#I#I#I#I#x#I#IaC.CaC.paCaCaoao#O.8ao.h.W.W.W.W.W.W.W#I#Q#v.w.Obiagbk.W.r#I#sb..E.E.Eaja9.E.n.7.n#D.saY.saY.Naw.NaY.Naw.N.s#xaCaq.8aF#Sa7a7#u.yaFam.5ao.Ca0.C#x#x#x#Ibn.R#x#x#xaY#xaY#Ibn#UaC.W#xbf.sbl#s#D#sa9.Ea9.7.E.7.7#L#L#Laj#Laj#L#L#L#L#L#L#Lbpajbp#Lbpbp#Lbp#g#gas#g#gas#gas", +"a2.ja2#La2aja2#L#L#Laf#L.Ea9aja9a9a9a9.na9a9.na9#D.n#Da9#Da9a9.na9a9#sa9#D#D#D#saY#xaCa0#U#x.N#s#D#D.na9a9.n#La9#L.n#Laf#Laf#Lajafaj#Laj#Laf#L#Lafajafafaj#L.Ea9#La9a9.n#D#D#D#D#D#s.Nbl#D#s.N#M#D#M#D.saYawaw#IaY#I#U#I#x#IaC.WaC.CaC#IaCavao.W.Wav.W.Wbo#I.W.Wbo.W#Q.y.w.Uau#3bd.8bo.s#s#sbjb.a9.E.n.7b.#sbj#s.Naw.Naw.NaY.saY#s#s#D#I#x#Ia0aoaFa#aBaBaBa##va#aoa0aoa0aoa0aC.Ca0#xaCbn#I#xaw#xa0aCa0#x.Caw.N.Na9a9a9a9.7a9.Ebj#L#Laj#L.E#L.7#L#L#Laj#L#Laj#Lajbp#L#Lbpajbpaj#Las.j#g.jas#g.j#g", +"a2a2a2.ja2#Laf#Lajaf#Laja9a9.7a9a9.na9a9a9a9a9a9.7a9.7.n.7.7a9.7.7#L.7a9#s#D#D#D#D#Mbnbn#x#xaY.N.s#D#D#sa9a9#Laj#L#L#Laj#Laj#L#L#Laf#Lafaj#Laj#La2a2afajafafa9a9a9.na9#Da9#s#D#D#MaYblawaYawaYbl.s.Naw#D.saYawawawaw.s#I#I.C.W.W#U#I#I#x.WaC.W.W.W#I#Ibo#xbo#I#Ibo.Wavbc.y#u.G#3.Qbc.Wbfaw.s#sbj.n.7.n.7#s#D.s#D.saY.NaY.N#M.NaYb.#D#s#Daw#Ia0#UaFaOamam.5.8.yaB.8aO.5ao.5amam.8amaCa0a0#x.C#I#Iaoam#I#xaY#D.N#Da9.7.7.7a9.7.7.7aj#L#L#L#L#Lajbp#Lbp#L#Laj#L#L#L#Lajbpaj#L#Lbp#L.j#gas#gas#gas#g", +"a2a2.j#La2#L#L#Laf#Lafa9a9a9#D#D.7#Laf#L#Lajafaj.7aj#L#L#L#Laj.7aj#Laj#Lbj.7.7b.a9#D#D#xaCa0.W.NaYaw#D#Da9.na9af#Lafajaf#Laf#Lafaj#Laj#L#L#Laf#L.3ajaf#La9aj.7a9a9a9a9a9bl#DblaY#DaY.NawaYblawaY.NaYaw.sbl#s#Maw.N.saw#x#I#I#I.C#I#x#I#I.W#Ibo#Ibo.Wbf#Ibo#Ibfbo#Ibo.W.8#Qbc.ybkbv.Q.8#I.s.s#s#sb..nbj#s.N#sbj#saY.Naw.saY.NaY.s#D#s.Nbo.N#I#I#xaCamao.Ca0b#aobyaOaF#v#vaB.y.ya#aOaF.5aCa0aC.CaCbn#xaY#D#D#D.7#D#Laj#L#Laj#L.7#L#Laj#L#Lajbp#Laj#L#gaja2bpa2bp#g.jas#gas#gas.j#gas#g#g#g.j#g.j#g", +"a2.ja2#L.j#Lajafajafa9a9a9#Da9.n#L#L.7#L#L#L.7#Laf#L#L#Laf#Laf#L#L#L#Laj#Laj.7.7#L.n#DaY#x.W.C.C.s.NaY#s#D#Da9#s#Laj#L#Laj#Laj#Laf#Laf#Lajafaj#Laja2afajafafa9.na9#pa9#M#Dbl#DaYaYaYawaY#xaYaYaYaw.Naw#D#sbl#s#M#s#saY.s.s#x#I#I#Iawawawbo.N.s#I.s.s.sbo.N.s.s#I#I#x#Ia1.Wao#vaLbkap.yaobo.N.N.s.7#s#sbj#s#D.sbjaY.saY.Nbl.saY.N.s.N.s.N.N#I#x.sbfbf.C.WaCaqamaq.5aoa##v.0#u#u#ua##vaOaFama0#x#xaYaY#D#Da9.7#L.Eaf#Lafaj#Lbpbp#Lbpa2bp.jbpa2#L#ga2aj#g#L.jbp.j#L#g#g.j#g.j#gas#g.j#g.jas#gas#gas", +"a2#L.ja2a2#L#L#Lafafa9.na9a9a9#D.7#L#Laj.7#L#L#L#L#Laj#L#Laj#Lajbpaj#Lbp#L.7.7bj#L.7#DaY#xa0.C.WaYaw.N#D#D#D#sa9aj#L.Eafajaf#Laf#Laj#Laj#L#L#L#L.3#L#Laf.7#La9a9a9a9#p#Dblbl.NblawaYaYaYaYawaYawaY.NaY.sbl#sa9.n#D#D#saw.s#I#I#xaw#x.saY.s.s.N.s.N.s.Naw#D.s.N.sbn#I#Iboa1#b.d.8#Tap.Qbcbo#D#sbo.nb.#D#s.Nb.#D.s.Naw.Naw.NaY.Naw.Nbf.s.N.sbfaY.N.saY.sbf.C.Waqavbga#a#a#.yaZ.0anaBbm#vaOaobn#I#xblaY#Ma9a9af#La2#L#L#Lbp#Lbpaj#L#g.ja2bpa2aj#gaja2#g#L#g#L#g#L#g.j#gas#gas#g.j#gas#gas.j#g#g.j#g", +"as.j#g#La2aj#Laja9ajaf#L#L.n#Laf#Laj#L#L#La2#ga2#ga2a2a2#ga2a2#g#L#Lbpaj#Laj#Laj#D.s#DblaY.VaObm.C#IaYaw#D#s#D#Dbl#Ma9a9af.7aj#Lajaf#Laf#Lajafaj#Lajafaj#Laj#L#Lajafa9a9.7#sa9#DaYaYaYaYaY#xaY#x.N#s#D#s#D#s#Db..n#sbj.n#D.sbfbo.s.s.N.s.N.s.s.N#s#D#s#D.s.N#Ibf.s#Ibo#I.Wav.8bcbta5.U#3aB.5.W.N#x#I#x.saY.s.N.N.s#D#Ma9b..E.7.nbfaw.NaY#xaY#Ibf#D#s.N.N#x.Waqavb#ambga#aO.0.y.yaoaCa0#x#xaY.N#D.Ebj.7.7.7.7.7.7#ga2#ga2#ga2#g#ga2#ga2aj#g#g#L#g#g#L.jbp#Lajbp#L#g.jas.jas#gas.j#ga2#ga2#g.jas#g", +".ja2#Laj#L#L.7.7af#Lafajaf#Laf#Lbpa2#La2#L#L#Lbp.ja2#g#ga2#ga2#g#L#L#L#L#L#L#L#L.7#D.NaYaYaobmaZamaCbn#x.NaY.N.N#Mbla9.nafajaf.7a9#Laj#Lajaf#L#Laf#L#L#Laf#Lafaja9af.7.n#Da9bja9#xawaYaYawaYaYaw#Dbl#s#D#D#s.7.n.7b..nbj#sbj.s.saw.s#D#saw#D.s#D#s#s.s.N.sbfawbf#Ibf.sbo#Iav.8bc#uaz#3bi.G#vaq.W#I#x#I#x#x#x.s#DaY#s#D#s#D#s#Db.aY.saY.N#I#I#x#x#I#x#I.C.WaqamamaFaObm#vaBaZ#va#bna0#xaYaw#D#D#Dbj.7.7.7.7.7.7.7#g.ja2#g.j#ga2bpa2a2a2#g#La2#L#g.j#g#gajbpbp#Lbp.j#gas#g#g.j#gas#g.j#g.ja2a2#ga2", +"#L#L#L#L#L.na9.n#Lafajaf#L#L.ja2#L#Lbp#Laj#g#L#L#gbp.j#L#gaj#ga2aj#g#Lbpajbp#Laj.7#D#sblaYb#aOa7b#amaoa0aC#x.baYbl#Mbla9#D#L.na9aj#Laf#L#Laj#Laj#Lajafaj#L#Laj#Lafajaf.7a9a9#Da9#Dblblblblblblbl#D#s#D#D.n.7.E.7.E.7.7.E#s#s#D.s.N.s#Db.#D#s#D#sbj#s#D#s.N.sbfboaYbo#Ibf.Wavbcbc.wa5au.M#3.w#v.5#Ibn#I#IaY.s.N.N#saY#s#D.s#D.s.NawaYawaY#I.C#Ibn.Wa0amamao.5.8.5#uanaB.ya#aoama0awaYaY.NaY#D#D#D#L#L#Lbp#L#L#L#Laj#gbpa2bpa2.j#g.j#L.j#L.jbp#g#Las#ga2#ga2aj#L#L#g.j#g.j#ga2#g.ja2#ga2#g#Laj#Laj", +"#D.na9#sa9#Da9#Daj#L#L#Lajaf#L#L#g.ja2#g#g#g.j#ga2a2#g#ga2#ga2bp#ga2#ga2#ga2#g#g#Lb.a9aY#UambmaZaO.t#SaFb#a0a0#UblaY#s#D.na9.7.n.7aj#Lajaf#Laf#Laf#L#Lafaj#Laf#L#Laf.7af.7.n.7#D#M#D#D#D#D#D#D#s#D#Da9#sa9.Ea9aj.7.E.E.7.7b.#sbj.s#s#D#s.N#saW#s.N#s.Nb..N.Nbo.N#xbo#x#I.Wav.8.yaz#T#3#z#z.O#uaF.CaC.C#x#I.Naw#D.sbl.saY.s.Nbo#Ibn#U#x#Ua0#Ua0aCb#am.8a##va#aBan#u#u.0aFama0#xaY.NaY#D#s#D.7.7.7#Lbpaj#Lbpajbp#Lbp#L#L#L#Lbp#L#L#L#L#Lbp#L#Lajbpas.ja2.j#ga2bp#Laja2#L#La2aja2#L#L#L#Laj#L#Laj#L", +"a9a9a9a9a9.na9a9#Lafajaf#L#La2a2aj#g#ga2#L#g#L#g.j#g#g.j#g#g.j#ga2#gaj#ga2#ga2#g#L#L#L#s#xb#aOa#.t#SaZaBbmbga0bnawaYblbl#Da9.n.7#Laf#L#Laj#Laj#L#Lajaf#L#L#Laj#Lajafajaf#La9a9a9#D#D.na9a9.na9a9a9.na9.7a9.E#L.Eafaj.7.E.7.nbj#s#Db.#Dbj#sbj#sbj#sbj#D#s.N.s.N#x.W#xbo#xavambcbb.O.O#a#a.Oba#3aBamaoa0.W#x.s.N#saY#saY#I#x#I#x#IaCa0aoamaob#aoamaF#v#vaB.0aB.0#ua#a#.5ao#xaY.Nbl#sbl#Da9.7.n.7.7aj#L#L#L#L#La2#Laj#Laj#L#g#L#L#Laj#Laj#L#L#Lbp#L.j#g#L#L#Laj.7#L#Laj#Laj#Laj#Laj.7aja9#La9aja9a9", +"#Da9#s#L.n#L#L#Laj#L#L#g#L.jbpa2#ga2#g.j#gas#gas#g#g#g#g.j#g#gas.j#g#g#g#g.jas#g#gaj#L#D#xaOaZan.FbmaBaZbmaFb##UaYblawaY#s#Da9.7.n#Laj#Laf#Lafajaf#L#Lajafajaf#L.3#Laf#La9aj.7a9#Ma9a9#Da9#Da9#Da9#D#La9aj.7aj#L.E#Laj.7.Ebj.nb.#s#D#sbj#s.N#s#D.s#D#sbj.N.sbf.s.C.Wa0.Wam.8.ybb#a.O.GaPaz.M#C.faOaoaq.W#xaw#D.s#D#I.N#I#xaCamaoaFaO#vaO#S.y#S#v#v#S#va#aOaFaOaFamaoa0#xaY#D#sa9#D#Da9.7.7#L#L#La2#L#g#L#g#Lajbp#L#Lbp#Laj#Laj#L#Laf#L#Laj#Lajbp#L#Laj#L.n.7a9#sa9.n.7.nbj.nbj.na9a9a9.na9#Da9a9", +".7#L#L#L#L#Laja2#L.jbp.j#L#g#L.j#g#g#gasas.jas#g.jas.jasasas.jas#gas.jasas#gas#gasbp#L.7awam.yan.Fbm.TaZaBaFam.R#IaYawbl.N#s#D#D#Lajaf#Laj#L#L#L#Lajaf#L#L#L#Laj#L.jafajafafafaja9#Da9a9a9a9a9.n#Lajaf.E#L#Laj.7.j#Laj#L.E.7.E#D#saW#D#sbj#sbj#Db.#DaE#D.sbf#IbfaCaq.Waoao#v.y.wbkaz.w.waz#3biau#uaOamao#xboaw.N.s#x#I#xaCambgbg#uaBa7#ua7an#ubh#vaFaOama0aCa0a0a0bn#UaY#sa9af#L#sa9.7a9aj#Lbpaj#g#L.j#gaj#g#L#Laj#Laj#L#L#Lbp#L.E#L.E#L#L#L.7#L.n.7a9#D#D.N.s.Na9#s#Da9#sa9#D.n#D#D#s#D#D#s#D.7", +"aj.7aj#gaj#gas.ja2bpa2#L#gaja2bpas.jas#gas#g.jasasasasas.jasaU.j#gas#gas#gas#gas#g.ja2#LaYa0.0aZ.Fa#aBaZa#aFbn#UaYaY.N#MaY#D#D#Daj#L#Laf#Lafajafajaf#L#Lajafaj#L.3#La2af#L.Eaf.7a9a9.n.7a9.n.7a9af#Laf#Lafaj#L#L.j#g.E#L.E.7#s.Ebj#s#sbj#D.s#Db..N#s#D.s.sbf.s#Iaqa0ao.C.8#vbbaPbk#u.w.Q.w.wau#N.Q.yavam#I#x.sawaY#I#IaCaoaoaO#vaz.Gaz.GazaS#uanaoaCa0.Wa0.CaC.CawaY#Da9a9#La9aja9a9.7aj#L#L#Lbpaja2bpa2bpa2#Laj#L#L#L#L#Laj#Laj#La9#L.7.7.E.7.E#D#D.N.s.N.s.N#x.7.7.n.7a9#sa9#D#s#D#D#D#D.7#D#D", +"#g#g.j#g#g#g.j#g#g.j#g.j#g#g#g.j#g#gas#gas#gas#g.jasasasas#gasasas#gas.jas#g.jas#g#g#ga2a9.C#SbhaFbgamam.8amaCa0aYaYaY#Da9.E#Laja9#Laj#Laj#L#L#L#L#Lajaf#L#Laf#Laja2ajaf#Lafa9a9.na9a9a9a9.7a9a9af.n#Lajaf.7#L.E#Lbpaj#g.n.7#s.N.s#DaY.saY.Naw#x.saYbo#x#x#I#x#I.8amaob##v#u.G.2bkaz#ubbaP.w.G.2.u.Oa#aoav#Ibfboawbo#xaoamaBan.Gba#a#ua#ao.5#Qaq.W#x#x#x#I#x#xaY#xawaYbl#D#M#Da9a9a9a9a9.7a9a9a9#L#Lajaf#Lajaf#La9.n#D#saY.NaYaY.N#sbl#D#MaY#M#D#D.n#Da9#D#D#D.n#Laj#L#L.E#Laj#L.7aj#Laj#Laj#Laj", +"#g.j#gas.j#gas.j#ga2a2#ga2.jas#gas.j#g.jas#g.jas#g#g.j#gas#gas#g.jas#gas#gasas#g#g#La2.j.7bnaF#ub#b#amb#ama0bn.CaY#M.N#sa9.na9#Lajaf#Laf#Lafajafaj#Laf#Laj#Laj#La2afafaj#L#La9.7a9.7a9.7a9a9a9.7afafafa9#L.n#L.7ajaja2.j.7.E#D.N#Daw.Naw.N#I#x#x#I#x#I#x#IaC.CaC.5bg.8aO.0.w#T.2.G#u.ybbbb#u.GaX.e#z#SaoaC.s.W.W#I#Iaoam#v#u.G#TarazbmaoamavaN.C#x#xawaY#x#IaY.saY#Daw#D#Da9a9a9#sa9.na9a9.na9.na9a9a9#sa9#Da9#sa9a9a9#D#Mbl.NawblblaY#MaYaYaYaw#D#D#s#D#D.n#D#D.n#La9ajaf#Laf#Laj#L#L#L#L#L#L#L", +"#g#g#g#gas#g#g#ga2.j#g.j#gas#g.j#g#gasas#g.jas#g.jas#gas.jas#gasas#gas#gas#g#gasa2aj#g#La9aYa0bmbgambgama0.C#x#xawaY.N#Da9.7#L#Laf#Laj#Laj#Laf#L#Lafaj#Laf#Laf#Laja2#Lafaf#L.na9.na9a9a9.Ea9a9.7ajafajaf#L.7#L.7bp.Ebp.Eaj.7#s.Naw.Naw.Naw#x#I.N#I#x#I.C.Wa0aoamao.5ao#vaBazal#3aB#vaF.y.yaB#u.wa6#z.w.8.C.Wam.CaoamaO#v#uaz.G.GaBaFama0#xawbfa1aY.NaY.NaYaY.NaY.N#D#D#D#Da9a9a9a9.7#D.n#D.7a9a9#D#s#D#D#D#s#D#Da9.na9a9#D#Daw.N#D#s#D#D#D#s#D#D.7.7.7.7.E.7.7.7#L#Laj#L#Laj#L#L#Laj#Lajbpaj#Lbp", +"as.jas.j#g.jas.ja2#ga2as#g.j#gas.j#g#g.jas#g#gas#g.j#g#gas#gas#gas.j#gas.jasas.j#ga2#gaj#LaY#Uamb#ama0a0aCbn#Ibn.Nblaw#Da9aja9aj#Laj#L#Laf#L#Lafaj#L#Laj#L#Laj#L.3aj.3#L#L#La9.7a9a9.7a9a9.7a9a9afa9#La9aj#L.n#L.E.7aj#L.E#D.sbfaw#M.NaY.s#x#IaY.C.W.C.W.Caqaqao.5aoaF#v#uaz#T.o#vaO.8.8bcbcaB#ualbaa5#vaoa0avaoaF#vbm#uaz#u#uaZa0am#x#M.N.N.N.N#D.Naw.N#s#D#D#D#D#sa9#Da9.n#L#L.na9a9.7a9a9.7#s#D#D#Da9#Da9#D#s#Laf.7a9.n#Da9a9#L.7#L.7aj.7#L#Laj#Laj#L#L#Laj#L.j#L#La2#La2#La2ajbp#Lbpa2#L#ga2", +"#g#g#g#gas#g#gas.j#g.j#g#gas#ga2#gas.j#g#g.jas.j#gas#g.jas#gas#gas#gas#gas#gas#gaa.j#g#L#LbjaY#Ua0aCa0a0#xbn#xawbl.N#D#Da9.7#L#Laf#Lafaj#Laj#L#Laf#Laf#Lafajaf#L#La2#Lajaf#La9a9.n.7a9a9a9a9a9#Lafafajafaf.7#L.7#L.7#Laja9#saY#IaY.saY.saY#I#x.s.C#xaC#x.Caoaqamao.8a##v#u.Ga5azaOaOaoao.8#v.ya5ba#z.w#vao.Wam#vaB#uaB#uaZa#aF.5#xawaYbla9.E#D#sa9#sa9#D.7.7a9#s.7a9.7.7#L#L#L#L#L#Lajaf#L#Lajafa9.7.na9a9.7a9a9.7aj#L.7#L.E#Lajafajaf#Laf#Lajaf#L#L#L#Laj#L#L#L#La2aj#gaj#gaj#g#La2.jbp.jbp.jbp", +"as.jas#g.jas.j#ga2as#gas.j#g.j#g.j#gas#ga2#g#gas#g.jas#gas#gas.j#gas#gas#gas#gas#g#ga2bp#L.na9bla0bnbn#UaYawaYaYaYbl#Da9.n.7afaj#Laj#L#L#L#Lafaj#Laj#Laj#L#L#L#L.ja2a2a2af#L.n.7a9a9a9a9.7.n.7a9afaf#Lafaj.7af.E#Laj#L.Ea9aw#x#IaY.saY.NawbfaY#x#I#x#I.C#I.C.Wa0.8am#v.0#u.G.w#uaO#v.8#Q.8bdbb.Q.K#z#u#vaFaoaBa7a7#u#SaFaoamaCbnaYaY#Da9aja9a9bj.7a9.7a9.Ea9.7.7af.7#L#Laj#L#La2ajafaf#L#Lafafafaj#Laf#Lajaf#L#La9#L#Laj#La2a2a2#ga2.j#g.ja2a2#gaj#gaj#g#La2bp.j#g.j#ga2#ga2#g#g#g.j#g#g#ga2a2#g", +"#g#g#g.jas#g#gas.j#g.jas#gas#ga2as.j#g.j#g.jas#ga2#g#g.jas#gasasas.jas#g.jas#g.jasaa#g#Lbp.7afajbn.RaYaYaYaYaYaYbl.N#D#D.7#L#L#Laf#Lafaj#L#L#L#Laf#Laf#L#La2#L.3#La2#L#L#Lafa9a9.n.7a9.7a9a9a9.7afaf#Laf#La9aj.7.7.7aja9#saw#x#I.N#saY#I.NaY.s#I#x#I#x#I#xaC.CaoamaO.yaB.waz#uaZ.8bc.8.8#Q.y.Q.w#4#4.wa##vaB.Qaz#vaFama0#x#x.N.s.N#D#sa9.7a9.E#D.E#L.7aj.7#Laja9aj.7#L#L#La2.ja2af#Lajafajafaj#Lafafajaf#Lafajaf#L#L#La2a2.j#ga2.jas#gas#g.jas#gasa2#g.j#g.j#g#g#g#g#g.j#g.jas.ja2#gas.ja2.j#g#g", +"as.jas#g#gas.j#ga2as#g#gas.j#g.j#g#g#ga2a2#g#g.j#g.jas#gas.jas#g#gas#gasas#gasasa2#g.jbp#LajafafaYbnaYaYblaYaY#MaY#D#sa9a9.7#L#L#Laj#L#La2afa2#L#L#Laja2#Laf#L#La2.j#L.3aj#La9.7a9a9a9a9.n.7a9a9afaj#La9aj#L.7#L#D.na9#s.naw#x#Ibl.Naw.Naw.NaY#xawaYaw#x#I#xaC#I.8aO.yan.w.G.w#vb#by.8.8bc.ybb.Qay.Y.G#u#1a5.GaBamamaobn.s#Da9.7aY#Da9.7a9.7.7#Da9aj.7af.7af.7#L.7afaj#La2a2a2.j#Laf#Laf#Laf#Laf#La2#La2#La2a2a2.7.j#La2#gaa.jasas#gas.jasasas.j#g.j#gas#gas#gas.jas.j#gas#g#gas#ga2.j#ga2#ga2a2", +"a2#ga2.jas#gasas#gas.j#g#g#gas#g.ja2a2a2.ja2a2#ga2#ga2.jas#gas#gas#gas.j#gas#gas#g.j#ga2bp#L#Laj#L.naY.R#xaYaY#D#Dbl#D.7#saf.7.n#L#L#L#L#Laj#L#Laja9#La9aj#L#L#La2a2a2.j#L#Lajafa9#sa9.7a9a9a9.E#Lafafajafa9.na9aj.na9#s#D.N#IaY#s.sbl.s#D#s#D#s.N#I#x.W.Cavam.5.8aF.0azal#T.w.0.8#v.8byaKbbaIaP#aba#N.O.GazaB.5#xaw.N.NaY#D#D#s.7.n.7#L#La9.7a9#L.7af.E#L.E#L#L#L#L#La2#La2bpa2#L#Laj#La2#L#Laja2aja2#ga2.jbpa2as#gas#gas#gas#g.j#g.j#g#g.j#gas#ga2.j#g.j#g.j#g#ga2#g#ga2.j#ga2a2#g#ga2#g.j#g#g", +"#g.j#g#g#g.j#gas.j#g#gas.j#g.j#ga2a2#ga2#g.ja2a2#g.jas#g#gas#gasas.j#gas#gas.j#gasasas#g.j#g#Lbp#La9#Dbl.RaYaY#D#D#Da9#D.7a9.7#L#L#Lbp#L#Lbp#L#L#L#L#L#g#La2a2#Las.ja2a2#Laf#L.7a9.7.na9a9.7a9a9af#L#La9#Lafaja9.na9.n#D.s.s#x#I.Nbl.s#D#M#DaY.saY#I#xaC.Caqao.5bgaO#uaz.G.G#u.y#x.W.8#v#v.y.0.ybabaay.f#uaB.8a0bfaYaY.N.N#D#D#Da9.7.7af.7.7af.E.7aj.7#La9#L.n#L#L.jaf#L#gaja2#L#La2#Lafaj#La2#L#g#g#L#g#L#ga2#g#gas#gas.jas#gasasas#gas#gas#g#g.j#g#gas#ga2as#g#ga2#g#L#gbpa2bp.j#L#gajbpa2bpa2", +"a2a2#g.jas#gas#g#gas.j#g#gas#g#g.ja2a2.ja2a2a2.jas#gas#gas#g.jas#gasas#gas#gasas#g#g#ga2#g#L#La2#La9a9#DaYbl#Dbl#Da9#Da9a9.7#L#La2#g.j#g#ga2#ga2.j#ga2.j#g#g#g#ga2a2#g#La2aj#L#L.n#Da9a9.na9a9.7#Lajafajaf.7a9.naf.na9aE.N#I#Ibn.saY.Naw.NaY.saY#x#I#x.Wa0ao.5.8aoaO#u.G.Gaz#ua##IaCaCaobg#va7azaH#zaz#uaFam#x#xaw.N.N#D#D.n#D.7.E#L#L#Laj#L#L#Laf.7#L#L.E#L#L#L#L#La2#La2#L#gaja2#L#La2#L#L#La2a2#g.j#ga2#g#L.jas#g.jas#gas#gas#g#g.j#gas.j#g.j#ga2.jas.j#g.j#g.j#ga2.j#ga2#g#L#g#gaja2bp.j#L#g", +"a2#g.jas#g#g.jas.j#gasa2#g.j#g.ja2a2#ga2#La2a2#g.jas#gas.jas#gas#gas#gas#gas#gasas.j#ga2#gaj#Lbp.j#La9a9#D#Dbl#Dbl#D.7a9.7.7af.7a2a2a2a2a2a2.ja2bpaj#Lbp#Lbpa2#L.j#g#La2#L.7#L.7a9a9a9.7a9.7a9.n#Lafaf.7afafaja9.na9.n#D#s#I#x#IaY.sawaY.saYaw.N#I#x#I.C.W.5av.5bgaOaB.G.O.G.y.5aO.8bgaFaB.Gau#N#zaz.0aFa0#x.NaY.N.N#D.n#D.7.7a9#L#La9#L.7#L.7#L.E#L#L#L#Laf.7#L#La2#L.jbpa2#La2#La2#Lajafa2#L.j#L#g#L#gaja2#g#g#gasasas#gasasas.jasasas#gas#gasa2.j#g#gas#gas#g#ga2bpa2bpaja2aj#ga2#L#g#La2bpa2", +"a2#ga2#g.jas#g#g#gas.j#ga2a2as#ga2aja2.j#g.j#La2#g#g.j#gas#g.j#g.jas#g.jas#g.jas#gas#ga2#g#La2#L#L#g#La2a9a9#D#D#Da9#Da9.7a9#L.7a2.j#g.ja2aja2#L#L#g#ga2.j#L.j#g#La2#Laj#L#La9.7.na9.na9a9a9a9a9#L#Lajafaja9a9.naf.n#s#s.N#I#x#U#I#x#x#I#x#I#x#I#x#I#x.Wamao.5.8ao#v#u.Garaz#ua#.y.0#u#u#aau#3alaza#b##I#xaw#D#sa9#s.7a9.7a9aj#L#La2aj#L#Laf#La2#L#La9aj.7#L#Laja2#L#g#La2#L#g#Laj#L#La2#L#La2#L#ga2#ga2#g#g#L#gas#g#gas#gasasasas#g#g.jasas.j#g#gas#g.j#g.j#ga2.jbpa2bpa2bpa2bp.jbp.jbp.jbp.jbp", +".j#g.ja2#g.j#ga2.j#ga2.j#g.j#g.ja2#ga2a2a2a2a2#g.j#gas#g.j#gas#gas#gasas#gas#gasa2.j#gaj#g#Lbp#La2#La2#L#La9#Dblbl#Da9bja9#L.7#L#L#Laf#L#L#Laf#Laj#L#L.7#L#L#L#L#L#L#L#L#La9#L.7a9#Da9a9.7a9.Ea9#Lafaf#Lafa9.na9.na9.E#D#s#x#I#I#I#I#x#I#x#I#x#I#x#I#x.WaC.5.8.8.5aBa5#a#TaPaPbk.U#3al#3#T.G.w.0aFaC#x#x.N#D#Dbj#Dbj.7.7aj#L#L#La2#L#La2#La2aj#L.7#L#L#L#L#Laf#Lbp.j#La2bpa2aja2#La2af#L#Laja2#L#g.jbpa2bpa2#g.j#gas.jasas.j#gas#gasasas#g#gas#ga2.jas#ga2#g.j#g#L#gaja2aj#gaja2bpa2#L#L#L#g#La2", +"a2#ga2#ga2a2#g.j#ga2#ga2a2#g#g#g.j#L.j#L.j#La2a2#gas.j#gas#g.jas#g.j#g.j#g.j#gas.j#ga2a2#gaj#L#L.ja2#g.j#g#L#Dbl#Da9a9a9.7a9.7a9a9a9a9a9a9#sa9#Da9a9.na9a9a9#Laf#Laj#L.7a9.E.7a9.n.7.n#Da9a9a9a9#Lajaf.Eaf.na9.naf#Ma9.s.s#I#x#I#x#I#x#I#x#I#x#I#x#I.CaCaq.8am#vaO#u.G.Uay#3#3bv.M#C.O#u.y.5am.C#UaYaYaw.N#D.7.7.7.7aj.7#L#Laj#ga2#ga2a2.ja2a2a2ajaf.7#L.7aj.7#La2a2bpa2aja2bpa2#L#Laja2#La2#L#ga2bpa2.j#g#ga2#gas#gas#gasasas.jas#g.j#gas.j#g.j#ga2a2.ja2a2#gas.j#L#g#L#g#L#gaj#Laj#L.j#La2aj#g", +"#g.j#g.j#g.ja2a2#ga2.j#g.j#g.j#ga2a2a2a2#g.ja2#g.j#gas.j#gas#gas#gas#gas#gas#g#ga2#g.j#L#g#La2bp#La2#gas#g#La9bl#D#Da9bja9.7.n.7a9b.#D#s#D#D#D#s#p.nbl#p.na9a9a9#L.7#L#L#La9.7.7a9#Da9.na9.n.7a9#Laf#Laf#Lafa9.na9.n.E#s.N.s#x#U#I#x#x#I#x#x#I#x#I#xaC.Wa0.8.8.8.yaB#T#4beaM.Y#T.fa7#uaOa0bf.s.N#Mbl#s#D#D.s#DaW.E#L#L#Laj#L#g#ga2a2.ja2a2a2aja2.7#Laj#Laf#L#L#L#L#ga2#L#g#La2#L#La2#L#L#L#La2aj#ga2#g#g#ga2#ga2as#gas#gas#g#gas#gasas.j#g#gas#g#g.ja2#g#g.ja2.j#L#g#L.jbp.j#La2aj#L#Lbpaj#g#L#g", +"a2a2a2#La2a2.j#ga2.ja2a2a2a2#ga2#ga2#ga2a2a2#ga2asaa#ga2#ga2#L.j#La2#L#Lajafa2#L.ja2#ga2#La2#L#L#L#Laf#Laj#L#L#La9bl#Da9blaYaYaYblbl#DaYaYawaYaYblblblblblblbla9#Da9#D#sa9#Da9#D.na9.7a9.7a9a9.n#Laf.Eaf.Eaf.naf.na9#M#D#saY.saw.N#s#s#D#s#s#D#s.C#I#I.C#Iao.5#v#u.OaVadbi#3#1aBbdaO.W.C#IaYbf.N#D#s.7#L#L#Laj#L#Lbp#Lbpbpa2bpa2.j#g#g#Lbp#Lbp#L#L#L.7.7.E#L.7#La2a2a2.ja2#ga2.ja2#L.3a2a2#g#g#g#L#ga2#ga2#g#ga2#ga2#ga2.j#ga2#g#gas#gas#g.jas.ja2#g#L.j#L#g#g#L.ja2a2#L#L#L.7#L#L#L#La2#L#Laj#L", +"a2a2.j#L.j#La2a2a2a2a2a2#ga2a2a2.ja2a2.ja2#ga2a2asa2asa2.j#L#g#La2#L.jaf.3#L#La2aa#ga2a2#L#Laj#Lafaj#L#L#Lbpaj#La9#D#p#Dbl#DaYaYbl#DblaYaw#xaYaYbl#Dbl#Dbl#Dbl#Da9#sa9#D.7#D.7#D.7a9a9a9a9a9.7a9.n#Laf#Laf#La9a9.n#s#D#M#DawaY#I#s#D#s#s#D#s#D#sbf#Ibf#I#Ia0bc.y.G#zad#4aXbk#v.8bgao.C#x.N#x.N.s.7bj#L.7aj#Lbp#Lajbp.j#L#gaj#g#L#gbpa2bp#L#La2#L#L#L#Laf#La9#L#L.j#ga2#ga2a2a2a2a2#La2aj#L#g#L#ga2#g#ga2#ga2#ga2#g#ga2#g#ga2bpa2as.j#g#g.j#ga2#g#L#Laj#Laj#Laj#L#gaja2ajafaj#L.Eafaj#L#Lajaf#L#L", +"a2#La2a2a2.j#ga2.j#L.j#ga2a2#ga2#ga2#ga2#ga2a2asa2.jasa2#ga2#La2#La2#L#L#Laf.j#L.j#L.jafaj#Laf#Lafafaf.7#L#L#Lbpa9#pa9#D#Dbl.sbl#D#MblaYaYaYaYawbl#D#M#Dbl#D#Mblbja9bja9#D.n#Da9.na9.7a9.7a9.na9#Laf.Eaf.Ea9.n.n#D#M#saYaw#IaY#IaY.s#D#s#D#s#D#s#I#x#I#I.Cao.y#1#T#rbq.G#u.yaOaCamaC#xawaY.s.N.N.7aj#Lbp#Lbpa2#ga2#Lbp#L#g#L#g#L#ga2#gaja2bp#Lbp#Laj.7aj.7aja9#L#L#L#L#L#Laj#L#L#L.j#La2#ga2#g#g#L#ga2#g#g#ga2#g#ga2#g#ga2#g.j#g#gas#g.jasa2.j#gaj#L#Laj#L#Laj#La2a2a2#L#L#La9#Lajaf#Lajaf#Laj#L", +"a2.ja2.ja2a2a2#ga2a2#ga2a2#g.ja2a2a2a2a2a2.ja2a2asas#ga2a2#L.j#La2aja2a2a2#Laf#Lafa2af#Laf#Lafajaf.E#Laj#L#Lbpa2a9.na9#Da9a9#D#Dblbl#DaYaYaYaYaY#Dbl#Dbla9#D#D#Da9#Da9#Da9bja9bja9.7a9a9.na9#Da9#D.na9a9a9a9#D#sbl#saYaw.s#x#I#I.saw.saY.s.Naw.N.s.s#IaCaoao#u.G#z.UaX#uaOaOao.W#x#IaY.N.N.N#D#D#L.7#Laj#La2#ga2#gbpa2bp.jbpa2bp.ja2#g#L#Laj#L#La9.7a9.7a9.7.7a9#L#L#Laj#L#L#La2af#La2#L#L#g#L#ga2#g#ga2#ga2#g#ga2#g#ga2bpa2bpa2#g.ja2#ga2#g.ja2#Laj#Laj#Laj#L#La2.j#Lajafaj#L.E#L#Laf#L#L#Laf#L", +"a2bpa2#La2.j#ga2aja2a2a2.ja2#ga2#g.j#ga2#ga2#ga2a2aa#ga2#ga2bpa2#La2afaja2afa2#Lajafajafajafa9a9af#Laf#L#L#L#Lbpafa9a9a9a9a9#D#D#Dbl#DblawaYaYaY#D#Dbl#D#Dbl#D#Da9b.a9.7a9#Da9#Da9.na9.7#D.na9.na9a9#D.n#D#s#D#M.NawaY#I#x#I#Ia0#IaY#Iaw.Nawbo#x.s#x#I.WaF.yaz#3.a#4a5#v#vaoaC#IaYaY.saYaw#D#sbj#Laj#Lbp#L.j#g.jbpa2aj#g#L#g#L#g#g#L#g#L#g#Lbp#L.na9a9.na9a9.na9#Lajaf#L#L#L#Laj#Lafa2#L#g#L#g#g#L#ga2#g#ga2#ga2#ga2#ga2.j#ga2#g.jas#g.j#g.j#ga2aj#L#Laj#L#Laj#Laj#La2#L#Laf.7af#Laj#Lajafaj#L#L", +"a2.ja2.j#L#ga2a2a2#ga2#ga2#ga2a2a2a2a2a2a2a2.ja2as.jasa2.j#La2#La2#La2a2#La2afajafafafafaf#pa9.n#Laf#L#L#L#L#g#Lafa9a9a9a9a9a9a9a9#DblaY#DaYawaY#D#M#D#D#M#Da9#Da9#Da9bja9.7#s.7a9.7a9.na9a9.7#D#s#D#s#D#Dbl#s.N#M.Naw#I#I#IaC.W#I#xbo#xbo.N#IaYbo.W.Wa0#vaz.Y#.aVapaOaO#O#I#I#xawbl.N#D#D.7a9.E#L#L#L#gaj#g#g#ga2bp#gbpa2bp.j#La2#g.j#L#La2#Lbpa9.7#D#D#s#Da9#D#L#L#L#L#L#L#L#L#L#La2#L.j#Lbpa2#ga2#g#g#L#ga2#g#g#ga2#gbp#g#L#g#g#g#ga2a2#g.ja2aj#Laj#L#Laj#Laja2#Lajafaj#Laj.7aj#Laf#L#L#Laf#L", +"a2#La2#ga2.ja2#ga2.ja2a2a2a2#g.j#ga2#g.j#ga2#ga2#gaa#ga2#ga2aja2#L.j#La2#L.jafaf.3ajaf.n#p.n#pa9afajaf#L.7#L#L#L#L#La9a9#D.7a9#Da9a9bl#DblaYaYaY#D#D#D#D#D#D#D#Da9bja9a9.7#Da9#Da9a9a9#Da9#sa9a9#D#D#D#D#s#D#saYaw#I#x#IaC#x.WaC#I#I#x#I#x#I#I#xa1ao#Q.8.w#4.P.4#u#Sao.WaCa0bobfbl#s#D.na9#L.7#L#Lajbpa2a2#g.jasbpa2#L#g#g#L#gbp#ga2#g#Lajbp#Laja9a9#M#Dbl#D.na9.7a9.7a9.Ea9a9.7af.jaf#La2#L#L#g.j#ga2#ga2#g#L#ga2#ga2bpa2a2.j#g.j#g.j#g.ja2#g.j#Laj#Laj#L#Laj#L#Lajaf#L#Laf.7af#Laj#Lajafaj#Laj", +"a2.j#L.j#La2#L.ja2a2#ga2#g.ja2a2a2a2a2a2a2a2a2a2asa2asa2a2a2bpa2af#La2afa2#L#Lajaf#pafafa9#p.n#p.7af#L#L#Laj#Lbpaf#La9.7a9a9bja9a9#D#Dbl#DaYaYaY#D#D#D#Da9#Da9#D#sa9a9bja9a9bja9.Ea9.7a9.Ea9a9a9#s#D#s#D#Dbl.s#Daw#x#IaC.WaCaCao.Wav#Ia1#I.Ca1#I.Cav.8aO.G#dbs#BaLaB.8aC#I.WaYbf#sbl#Da9a9.n#L.E#L#L.jbp.j#gasasa2bp.j#L#ga2bpa2#g#L#g#L#g#L#L#La9#Da9bl#s#p#Da9.7a9.E.7a9.7.7.n#Laf#L#L#gaj#L#g#ga2#g#gbp.j#ga2#g#ga2#g.jbp#gbpas#ga2#ga2#g.ja2.E#Laj#L#Laja2#Laja2aj#Laj#L.E#L.Eafajaf#L#Laf#L", +"#L#L#L#L#La2bpa2#Laj#L#La2bpa2bp.L.L.jasaa#ga2#gaja2a2a2a2#La2#La2a2#L.j#La2afa2.3aj#p#Mbl#D#D.7ajaf#Laj#L#Lbp#Laj#Laf.n.7a9a9.7#pa9#p.NaYaYbl#Dbl#D#Da9#Da9.7a9a9a9a9afa9.7a9.7#Dbl#Dbl#D#D#D#D#xaYaYawaYaYaY#Ubn#I#I#I.Wao#v#vaC#I#x.W#Ibo.C.WavaoaZ.o.Yab#3.QaOaoaC.W#I#x.s.Nbl#sa9a9aj#La9#L#L#g#L#ga2#g#L.j#g#g#g#ga2bp#ga2.ja2#L#Laf#La9.7bl#DblblaYaYaYaYaj#L#L#L#L#L#L#L#L#L#L#L#L#L#L#La2#ga2a2a2#g#La2#La2#g#La2a2#L#L.ja2.ja2.j#L#Laj#L#L#Laj#Laj#Laj.3#Lafajaf#Lajafa9.na9a9.na9.na9", +"#L#Laj#L#Laj#La2bp#L#gaj#L#L#Lajaa.jaaaaa2#ga2bp.3#L#L#La2#L.j#La2a2a2#La2#La2#L.3af#pblbl#Da9a9afaja2#La2#La2#L#Laf#L.7a9a9bja9a9#p#DblaYaw.Nbl#Dbl#Dbl#D#D.7a9a9afa9a9a9a9aj.7bl#D#D#sbl#Dbl#MaYawaY#xaY#xawaY#x#U#x#I.Cao.8aBaxav.W.C.Waoao.8aO#vaPay#daVbk.0#OaoaC.W#x#I.N.N#Dbl.na9a9#L.7aj#g.j#ga2bpa2#g#gasas#g.j#g#ga2#g#La2.ja2#Laja9a9a9a9bl#DaYawaYaY#La9.Eaf#L#Laj#L#L#Laj#L#L#L#L#Lbpa2#L#g#La2#g#L#gaja2#ga2#ga2#La2a2a2#La2a2.3#L.jaf.jaf.j#L.3#Laj.3aja2#Laj.3#Laja9af.n#L#Laf#L", +"a9ajafaf#L#L#L#L#L#L#L#L#L#L#L#Laa#ga2#g.j#gbp#La2#L.ja2#La2#La2a2#La2a2a2#L.j#L.jaf.n#pbl#sa9.Eaf#Lafaj#Laj#L#Lajaf#La9a9bja9a9#Ma9bl#DaYaYbl#DaYbl#Dbl#Da9a9a9a9#p.naf.7a9.7a9.n#Da9#D#D#s#D#DaYblaY#MaY#MaYaY#MaYaw#I#IaC.8aObgaoaoao.8ambc#v#uar.M#d#4.G.y.8bgaoaC#x#I.N.N#s#pa9a9.7ajaf#L#La2bpa2.j#g#gaj#g#g#gas#ga2#g#L#La2a2#Laf#Laf#La9a9a9a9#D#Dbl.Nbl.E#L.7#L.7af.7#La9#L.7#L#L#L#L#La2#ga2#ga2#g#La2#L#ga2#L#g#L#Laj#L#Laj#Laj#Laj#Laf#L#La2afaj#Lajaf#Lajaf#Laj#Laja9afajaf#Lajafaj", +"afaf#Lafajafajafajaf.Eaf#Laj#L#L#La2#L#L#gbpa2bp#La2#L.3#L.jafa2#La2a2#La2a2#L.3afaf#p#Mbla9a9.7afajaf#L#L#L#g#L#La9aja9a9#Da9.7#pbl#DaYaYaYbl#DaYblaY#Dbl#D#D#Dafa9afa9a9a9.7.7.7#Da9bja9#D#D#s#D#D#saYbl.NblaY#M#D.saw#I.WaOaB#vaO#v.8aOaO#v.y#3ad.Z#.#T#vav.haoaC#x#IaY.s#D#D.n#Dajaf.7#Laj#L#ga2#g#gbpa2#ga2a2as#ga2#ga2bp#La2a2a2a2a2#L#L#La9afa9#M#DblawaY#L.7af.E#Laj#L#L#Lajaf#L#L#L#L#Lbpa2#L#g#La2#gaja2#L#ga2#g#La2a2aj#L#L#L#L#Laf#L#Laj#Laj#L#Laf#Laj#L.7aj#L.Eaf.7.na9#D.n#Da9#Da9", +"a9.na9a9a9a9#pa9a9a9a9a9a9a9a9.nafaj#L#L#L#Lbp#La2aja2#La2#La2a2#La2a2a2a2a2#La2aj#p#pbla9a9#Lajaf#Lafajafaj#L#Lajaf#La9.7.nbj#Da9blaYaY#x.N#DblaYblaY#DaY#Dbl#Da9a9a9a9.7a9.7.7a9.7.E.7.7.7.7a9#D#D#D#D#s#D#s#D.sbl#s.s#xaoaO#S.yaBaB#u#u#ubk#E#.ab#4#3.G.y.8bo#U#I#x.s.N#D#s#Da9#L.7aj#L#La2bp.jbpa2#La2#g#L#g.jas#g#ga2#Laja2#L.j#La2af#L#L#La9.7a9bj#Daw.Nbl.E#L.7#La9#L.7#L.7#L.7#L#L#L#L#La2#ga2a2#ga2#L#g#La2bpa2#La2bp#L#Laf#L#Lafaj.7ajaf#Laf#L#Laj#Laja9.na9.7afa9.Ea9a9a9a9a9a9.na9a9", +"a9a9a9a9a9a9a9.n#paf#paf#p.n#p#pbl#D.na9a9#L#L#L#La2#La2#La2#La2a2a2a2#La2#La2afa9#p#M#pa9.nafa2afajaf#L#Lbp#L#L#Laf#La9a9#Da9a9#D#DaY#x#xaYaY#DblaYblaY#Dbl#Dblafa9afa9#Da9.7a9#L.7a9#Laf.7.n.7a9a9#s#D#D#D#D#D#s#D.s#x#I.8#Saz#u#u#uaZ.w.GbiaV#4.U#3ara5#vao.W#x#IaYaw#D#sa9a9#L.n#Laf#L#gaj#L#ga2#g.ja2#g.j#gas#gas#gaja2bp#La2a2a2a2#L#Laf#L#L#La9a9#Dbl.NaY.7#L.n#L.E#L#Lafaj#L#L#L#L#L#L#Lbpa2#L#g#L#ga2#ga2#ga2a2#gaja2#L#L#L#Laj.7#La9#L#L#Lajafaj#Laf#L.n.7a9.Ea9.Ea9.n#D#s#D#s#D#D#s#D", +"a9.n#pa9.n#pa9#pa9.n#p.n#p#p#p.nblblbla9.na9#Laf#Lafa2aj.3#L.j#La2#La2#La2aja2#La9.nblbl#pa9#L.j#Laf#Laja2#La2aj#L#Laja9a9.7#D#s#p#DaY#x#x#xaY#DblblaYaYbl.Nbl#D#Dbl#D#Da9#Dbj#D.7#L.7#L.7af.7#L.7.na9a9.na9a9.n.NaYbobfaoaFaBazaz.w#uaP#3#4ad#4ap.O.O.O.w#S.8.5#Uaw#x.saY#s#D.n.7#L#Laja2aj#gas#L#gbp#gbpa2bpa2#gas.j#g#g#L#La2#La2#La2#L#L#L#L.7#L.7.7.E#D#s#D.na9#L.7af#L.7#L.7#La9#L#L#L#L#La2#ga2a2#ga2#L#g#La2bpa2#ga2#ga2.7a9.7#La9.7.7a9ajaf#L#Laf.7.na9#D.Ea9.7a9.7a9b.#D#D#D#D#D#D#D#D", +".n#pa9#paf#p.n#p.n#p#p#p#p#p.n#p.b.R#Mbl#p.nafajafaja2#La2#L.3#La2a2aja2#L.3#L.ja9#pbl#Mbl.nafa2afajaf#La2#Lbp#L#Laf#La9.n#D#s#DblaYaY#xbn#xaY#DblaYblaYblaY#Dbla9bla9#D#D#D#Dbja9#La9#La9.7.7a9.7a9.7.7.7.E.7#D.N.sbf.Wam.y#uaz.Oar.Gal.Mbxadalbkbkbkbkbka7.yaF#I#IaY#s#Da9#s#Daj#Laj#L#g#L#g#g#gaja2a2a2#ga2#gas#gas#ga2#g#gaja2a2a2af#Laf#La9#Lajaf.7a9#D#s#Da9.Ea9.E#L.E#Laj#L#L#L#L#L#L#L#L#L#g#L#g#La2#ga2#ga2#ga2#L#g#La2#L#L#L.7#Laf#La9#L.E.7.7.Ea9.n.7.n.7a9.7.n.7.na9#D#D#s#D#s#D#s#D", +"#Lafaj#L.7#L#L#Lafafajafaja9#pa9aYawaYaYawblblblafafaf#Laf#L#L#L.jaaafa2#L#Lafaf.n#F#M#pa9afaj.7#Lbp#Lbpbpaj#L.Eaf#Laj#D#D.N#D.N.naYaYbna0a0bnaY#DblaY#x#xaYaYblbl#D#Da9a9.7#L#L.7.7.7.7.7.7.E.7#Dbj#D.s.N.N#DboaY#MaY.W.8aZal#P#PaT#P#.a.ad.ObkaX.G.O#Taz#SaoaC#x#x#I.N.s#D.E.7af.7#L.E#L.Eaf#Laj#g#gbp.jbpa2aj#ga2#g#L#ga2#ga2#L#L#L#L#L#L#L#L.7#L.7a9.E#Da9#D.Ea9.7a9.7a9#La9#L.7aj#L#L#L#L#L#L#L#L#L#Lbpa2#L#L#g#L#ga2a2#ga2bpa2#La2#L#Laj#L#Laf#Laj#L.7#L.7af.7.E#L.7#L.7#L#sa9.7a9.7#L.7#L", +".E.7.7#La9aj.7#Lafajafafafa9a9.nblbl#MaYblbl#Dblafajafaj#L.E#L#Laaa2a2aja2afajaf#p#p#pa9.naf.7#L#gaj#Lajbp.7#L.7ajafa9#D#D.NaY#xblaY#x#xama0a0aY#p#Dbl#xbnaYblaY#Dbl#Da9a9.7af.7.7.7.7.7.7.7.7.7#D#s#D.N.N.N.N.N#IaY.N#Iamanay.P.PaDaD#..M.O.G#u#u.w.GaP#u.ybgaCaC#x#IaY.N#s.7a9.7aja9#La9#L.E#L#L#ga2a2#ga2#ga2#g#L#ga2#ga2#g#g.7#L.7#L.7#L.7.7af#L#L#La9#Db.#Da9.7a9.Eaf.7a9.7#L#L#L#L#L#L#L#L#L#L#L#L#La2#L#L#ga2a2#g#L#g#La2#ga2#g#L#ga2#La2#L.7#L.7a9aja9#L.E#La9aja9#L.n#L.na9aj#Laja9aj.7", +"#L#Lafaj#L#Laf#Lajafaf.Eaf#sa9a9a9a9#pbl.nbl.n#p.nafa9#Laf.7#L#L#L.ja2#La2af#L.n#p#Mbla9a9aja9#Laj#Lbp#L#L#L.7.7#D#D#saYaw.N#xbf#MaYaw#xbna0a0aYblaYaY#xbn#xaYaYbl#D#D#Da9#D.7#L.7.7.7.7.7.7.7bj#s.7#D#s#D.N.sbfa0#UaoaO.yan.2.g#m.AbA#4ar#u.0#u#S#vaBaB#uaB#v.5aoamaC#x#IaY.N.na9.7.E#L.7af#L#La2#g#L#g#L#gbp#ga2#ga2#g#g#ga2#g#L#L#L#L#L#L#L#L#L.E#L.7.7a9#Da9.Ea9.7a9.7.7#L#L#L.7#L#L#L#L#L#L#L#L#L#L#Lbpa2#La2bpa2a2#ga2#ga2#L#ga2a2a2#g#La2#Laj#L#L#L#L#L#La9#L.7#L.7aj.7#La9.7#La9.7#La9#L", +"#L#L.7#L.7#L.7#Lafaf#Laf#La9a9.na9#Da9.n#Da9#D#Dafaf#Lafaja9aj#La2a2af#Laf#Laja9#p#D#p.na9.7aj#L#L#L#L#Laj.7.7b.#D#saY.NaYbf#x#x#DaYaYaY#xbna0#xaYaYaY#xaYaYaYaY#Dblbl#D#Da9.7.7a9.7.7.7.7.7a9.7af.7#D.N.s.N#x#IaF.8amaF.0#uaybe#.ba#aaz#ua##vaOaOaO#v#v.y#uaBa#b#bga0a0awaYbl#D.Ea9a9a9.E.7a9.7#Laj#L#gaja2a2a2#ga2#g#ga2#ga2#g#L#L#L#L#L#L#L#L#L#L#L#La9.Ea9.7.7.n.7.n#La9.n.7af#L#L#L#L#L#L#L#L#L#L#L#La2bp#La2#ga2#g#La2bpa2#ga2#L#g#L#ga2#g#L#L#Laf.7#L.7#L#L#Laj#L#L#Laf#L.7#L.E#L.n#L.E#L", +"#L#Laj#L#L#Laj#L#L#Laj#L.7.7a9.7a9a9a9#Da9a9.na9.naf.Eaf#L.7#La9ajaf#Lajaf#La9a9#M#pbla9a9#L#L.7aj#Laj#Lbjbj#sbjaY.N.Naw.N.Nawbf#DblaYaYaY#xbn.CbnaYaYaYaY#xaYa0bl#D#D#Da9#D.7#L.7#La9#La9#L.7.7a9#sblaYaYbnaCa0.5amaFaB#u#a#4abarazaBa#aO.5ao.5aoaoamaOaB#u#uaZaCa0bn#xaYaY#Dbla9a9.na9a9a9#La9#La2a2#L#g#g#L#g#g#ga2#ga2#g#ga2#ga2a2#ga2a2#La2#L#L#Laf.7.7.7a9a9.7a9.7.7.7#L.7#L#L#L#L#L#L#L#L#L#L#L#L#L#L#L#L#g#La2bpa2#ga2a2bpa2#ga2a2#g#La2#L#L.7#Laj#L#Laj.7af.7#La9#L.7ajaf.7#L#L#L.7af#L", +"#L.7af.7#La9#L.7a2#L#L.7#L.n.7.na9a9.na9a9a9a9a9afaf#Laf#Laf.E#Lafajafaf#La9.na9#D#p#sa9.n.7aj#L.7#L.7a9.Ea9#Da9.NawaY.N.NaY.N.N#D#D#D#MaY#x#xa0ama0#xbnaYaYbn.CaYaYaY#D#D#D#D#Da9a9a9a9.7#Da9#s#D.NaY#x.Ca0amamaFaB.f.Oau#aazan#v#vaFam.5aCav.CavaoaoamaOaB#uan.Ca0#xawaY.s#D#s#Dbja9bja9.7a9a9a2#La2#La2a2a2a2#ga2#ga2#g#ga2#ga2#ga2a2#ga2#ga2#L#L#L.7a9.7a9.7.Ea9.Ea9.7af.7af#L#L#L#L#L#L#L#L#L#L#L#L#L#L#L#La2a2#ga2#ga2#L#ga2#g#La2bpa2a2bp#L#L#L#L.7#L.7af#L#L#L#Laj#L#L#L#Laj#L#La9aj.7#L", +"#L#L#L#Laj#L#L#Lajaf#Laja9.7.7a9.7a9a9a9a9.na9a9aja9#Laja9#L.7#Laf#Lafaja9a9#D#D.nblbla9b.#L.7.E.7.n.7.n#D#D#s#D#D#D#D#s#D#D.n#D#D#D#s#Dblawa0.Cama0a0aYaY#xa0amblaY#D.N#D#Dbj#Dbj#D#D#D#D#D#D#D.N#x#x#xbg#vbmaBbk#a#Ea7a7aZ#va#amb#ao.C.W.Cbf#IaqaoaoaoaO#SaZ#ubn#I#xaY.Na9a9.7a9a9a9a9a9a9a9a9#Lajaf#L#L#L#La2a2#g#g#ga2#ga2#ga2a2#ga2a2#ga2a2#L#L#L#L.7.Ea9.7a9.7a9#La9#L.7#L#L#L#L#L#L#L#L#L#L#L#L#L#L#L#L#L#g#L#g#La2bpa2#g#La2#ga2#ga2#ga2#L#L#Lajaf#L#L#L.E#L.7#L.7#L.7#L.7af.7aj.7af.7#L", +".E.7.n#L.7#L.7af#L#L#L.7aj.7a9.Ea9a9a9.7a9a9.7a9afafafafaja9aj.7afaja9#La9a9#s#D#p#M#D#s#D.n.E.7a9.na9#D#sa9#D#D#D#s#D#D#Da9a9.n.N#D#D#Dbl#xa0ama0ambnaYaYbnama0aYaYaY.N#D#D#Dbj#D#D#D#D#s#D#Daw.C#I.Caobm.G#faG.yaBbh.l.taFb#.5a0a0aoa0#xbo#xboaqavaoamaC#Sa7an#I#x.N.s#Dbjaj#L.n#Da9#sa9a9a9a9#Laf#L#Laf#Laf#L#ga2#ga2#ga2#g#g#ga2#ga2#ga2a2#g#L#L#La9.7a9.7.7.7.n.7.7.7#L.7#L#L#L#L#L#L#L#L#L#L#L#L#L#L#L#L#La2#ga2a2#ga2#ga2a2#g#L#g#La2bpa2#L#L#L#L.7#L.7#L#Lafaj#L#Lafaj#L#L#L#La9#L.7aj#L", +"#L#L#L#Lajafaj#Laf#Lafaf#Lafajaf#L.jafajaf#Laja9aj#Laj#L#L#L#Laj.7.7.E#Laj#L.7.7bl.NawaY.NaY.N.s#s#D#sa9bj.Ea9.Ea9.na9.n#D#s#D#Da9.n#D#D.saY.s#x.R.Rbn#x#x#xaY.NbnaYblbl.na9.7.7#D.N.N.N.Nbfbfbfavama#aSaG#z.G.0aoa0aC#xaCbn.Wbn#I#xaY#I#x#x#I#x#Ia0avao#v.0aBa7#IaYa9.7.E.7#D#Da9a9a9a9.7a9.7afa2a2a2a2a2#g#ga2#ga2#g#ga2#g#ga2#ga2#g#ga2#g#ga2a2#g#L#L#L.7a9.7.na9a9afaj#La2a2#L#Laf#L#L#La2#L#L#La2#La2#La2#La2#L#L#L#L#L#L#La2a2a2a2#g#ga2#g#La2#La2#Lajafa2.7#L.7af.7#L.7afaj#L#Lajafafaf#L", +"#Lafajaf#L#Laf#Lajafaj#L#Laf#Laf#Laf#Lafajaf#Da9.7a9.7.7af.Eaf.7.na9a9a9.7.7.n.7awaYawaYaw.s.N#D#Da9#D.na9.7a9.7.n.7.7.7#D#D.7.7#Da9#s#D.N#x.N#x#Ua0a0bna0bn#IaYb#am#xaY.N.N.N.Nbj#D.N#I#xaqaoa0a0a#a7#fa6az.0.5bnaCbnbn#x#x#x#xaYboaYbfaw.NaY#I#x#Iao.8.5#v#u.T#I.N#sbja9bj.7bj#sa9.Ea9a9.7a9a9#L.ja2a2.j#ga2#g.j#ga2#g#ga2#ga2#g#ga2#g#ga2#g#g#ga2#L#L#La9aja9a9af.7af#L#L#L#gafa2#La2afa2#La2.3#La2#La2#La2#La2#La2a2a2a2a2#La2a2#L#g#La2bpa2bpa2#ga2#L#La2#L#L#L#L#Laj#L#L#La2a2afafaj#Lajaf", +"#L#L#L#L#L#Laj.7af#Laf#Lajaf.Eafajaf#Lafa9a9.n#D#D.n#Da9#s#D#D#D#D#s#D#s#D#D#D#sbl#s#D.s#D#s#D#s.7aj.7#L.7aj.7#L.7af.Ea9#L.7a9.7.na9#D#D#D.NaY#xa0.Vaoamama0ambna#b#amambn#x.C.Cawbf#xa0amamaF#v#vaBazaSa7a#aq.W#x#x.s#xaw#xaw#x.N.NaY#xaY#x#I.N#I#xavam.8.yana7#U#x#D.7b..7a9#Da9a9a9a9.7a9af.7a2#La2#L#ga2#g#g#ga2#ga2#g#ga2#ga2#g#ga2#g#ga2#ga2#L#L#L#L.7a9.7a9a9a9#La2#La2a2#L#Lafa2#La2#La2#L#L#La2#La2#La2#La2#L#L#L#La2#La2a2a2a2#g#ga2#g#La2bpa2a2#Laj#L#L#L#L.7#L.7#L.7af#L#Laf#Laf#L#L", +".7#L#Laj#L#La9#La9a9a9a9a9a9a9a9af#L#D.n#D.7#D.7#D#D.N.s.N.N.N.sbl.NblaYblaYawaY#M#D#Ma9#D.nbj.7#L#L#Laj#L#Laj#Laj#L#L#L.7a9.E.7a9a9a9#DaY.s.N#xaCb#a#aFa#amamam#vaFamam#xa0#xam.CaCamamaObma7aza7aZbm.tam.C.Cbfaw#xaYaY.NaY.NaY#DaY.s#xawbfaY#x#x#Iaqao.8aZ#ua7ao#xaw#Da9b..7#Da9#s.7a9af.7a9a9a2#La2#La2#ga2#ga2#g#g#ga2#g#ga2#g#ga2#ga2#ga2#ga2#g#L#L.E#L.7afa9afa9#Laf#L#ga2#La2#La2#La2#La2af#La2#La2#La2#La2#La2a2a2#La2#La2a2#La2#La2bp#g#L#ga2a2#g#La2#L#L#L#L#L#L#Lafaj#Lafaj#Laf#Laf#L", +"a9a9a9a9a9a9a9.n.7a9.n.7a9a9.n#D.na9#s#D#D#D#D#D#D#D.sblaY#saY#DaY#MaY#saYblaY#D#D#s#D.7.n.7bj.E#L#Laj#La2#La2#L#L#L#L#L.n.7a9.7a9.E#D#D.NaY.N#Iamam#v.0a#aFa#a#bmbgamaCbna0aoa0amaF#vaBa7a7.l.TaFb#b#amam#x.Nbj#x.N.s.NaY.NaY.N.N.NaY#x.N#IaY#I#x#Iaoaq.8.ybhazb#bn.N.N.7a9#D#s.7a9a9a9.7a9#La9#Lajaf#L#L#Lbp#L#ga2#ga2#ga2#g#ga2#g#ga2#g#ga2#ga2#L#L#L#L.7a9.Ea9a9a9a2#L#La2#g#La2#La2#La2#La2#La2#La2#La2#La2#La2#L#La2#La2#La2a2a2#ga2#g#ga2#ga2bpa2a2#L#L#L#L#L#L#L#L.E#L.7a9a9a9a9a9a9.7a9", +".7a9a9a9.n.7a9a9#s#Da9#Da9#D#D#D.7#D#D#DaY.Naw.Naw.NaY.NaY.NaY#s#D#D#D#D#s#D#s#D.na9a9.n.7.7.7#L#g.ja2#g.j#g.j#g.j.3aj#L.7aja9.Ea9a9a9#D.N.s#x#x.Cb#aF.yaZa#a##Sa##SaFamamaOa#aZazazaza7a7bmaFaFa0a0a0bn#IaYaY.Naw.NaYaY.N.N.Naw.NaY.Naw#x.N#x.N#x#I.Cao.5.ya7az.5aoaY.s#D.E#D#Da9.na9.7.na9a9a9#Laf#L#L#L#L#Lbpa2#g#ga2#g#ga2#ga2#ga2#g#ga2#g#ga2#g#L#L#Laf.7#La9afa9#L#L#La2a2#La2#La2#La2#La2#La2#L#L#L#La2#La2#La2#La2#La2#La2a2#L#g#L#g#L#g#La2a2bpa2#g.j#L#L#L#L.7af#L#L#La9.7a9a9.Ea9a9a9", +"a9a9a9a9a9a9.na9#D#D#s#D#s#D#s#D#D#D.saY.s#xaY#x#D#M#D.nbl.nbl#Da9.Ea9.7a9.7a9.7#Laj#Laj#Laj#Laj#gas#gas#g#gas#ga2#L#La2af.7#L.7a9#s#D#D.NaYaYboa0a0aOa#a#a#aBbh.GaPa7az#uaS#TalbaaGa7aZaFaoambnaCa0#x#I#D#DaYaw.N.N.s.N.N#D.N.N.N.N#I.NaY.saY#I.N#I.C.8.5.ya7azaOb##x.N#Da9a9#sa9a9#D.na9.7a9.7a9a9.7#L#L.7bp#L#ga2#g#ga2#g#ga2#g#ga2#ga2#ga2#ga2#L#L#L#L.7a9.7.na9.7a2af#L#ga2#La2#La2#La2#La2#La2#L.3#La2#La2a2#La2#La2#La2#La2a2a2a2a2#g#ga2#ga2bp.ja2bpa2#L#Laj#L#Laj.7#L.7.na9a9.7a9a9.7a9", +"afa9afa9.na9a9a9#s#D#D#D#D#D#D#D.saY.NaY.Naw.NaY.n#Da9a9a9a9a9#Daj.7#L#Laj#Laj#Laj#L#L#Laj.7bp.7as.jas.jas.jas.ja2.ja2#L#Laja9aja9a9#D#D.Naw.N#x#xa0am#va#a#bmaB#l#0.2.2.2#0ab.4arazaZa#aFa0.W.C#x#x.NaYaYaYblbl.N.N.N.Nbj#Dbj.NaY.NaY.N.NaY.NaY.NaY.Waqao.0#ua7aBaO.Waw#D.na9#Da9.na9a9a9a9a9af.7afa9.7#L.7.7bpa2#g#ga2#ga2#g#ga2#ga2#g#ga2#g#ga2#g#L#L#L.7.Eafa9afa9#L#L#La2#g#La2#La2#La2#La2#La2#L#L#L#La2#La2a2#La2#La2#La2a2#La2#L#g#L#g#L#g#La2#Lbpa2#La2#La9#L.7#Laf#L#La9.7.na9a9a9.na9", +"#D#Ma9#Da9bl#M#DaYaYawaYblawaYaYaYawaYaYbl#D#D#s.7af.E#L.7aj.7#L#Lajbp#Lbp#L#L#L#ga2.j#g#g.j#g.j#g#g#g#g#g#g#g#g#ga2a2aj.7a9.7.7a9.na9#M#DaY.Nawbn#UaoaF#v.8am#va6a6ba#V.Z#oab.I.TbmaFaoam.C.C#I#x.s.N.N#D#D#D#DaY#DaYbl.NaY.N.s#D#M#D#D#s#D#D#s#Daw#x.CaC.5bc.yaBaZ#vam.Nbj#Db.#D#D.7a9.7#D#D.Na9a9.7a9#L#L#L#La2a2a2#ga2#ga2a2#L#L#L#L#L#L#L#L#Laf#L.na9a9#D#Da9a9a9a9#L#L#L#La2#La2#L#L#L#L#La2#La2a2a2a2#L#La2#La2#La2#La2#La2a2a2a2a2a2a2a2#L#L#L#L#L#L#L#L#L#L#L#L#L.7a9.7af#La9.7a9bja9#D", +"bl#D#D#M#D#Dbl#D#MaYbl.saY.NblawaYaYaY#M#D#s#D#D.7#L.7#L#L#L#Laj#g#L#gaja2aj#gajas.jas#gas#g.j#gas.jas.jas.jas.ja2.j#L#Laf.E#D#Daja9a9#DaY.s#x#IaCamama##uazaz.G#.a..Z#Valarak#aaZ#Sa#ama0#U.C.CaYaY.NawaY#D#D#DaYaY.sbl.N.s.N.Na9a9a9a9#D#D#D#D#s.N.N#I.CaobybcbhaB#vaF.WaY.s.Nbl.s#D.na9#D#DaYafa9a9a9#L#L#L#L#ga2#ga2#gaaa2as#L#L#L#L#L#L#L#L#L#L#La9a9#D.7#D.na9#D#L#L#L#L#L#L#L#L#La2a2a2a2#L#La2#L#L#La2#La2#La2#La2#La2#La2a2#La2#La2#La2#L#L#L#L#L#L#L#L#Laj#L#Laja9.7.Eafaja9a9#sa9#D#D", +"#D#M#Dbl#D#M#DblaY.NaYbl.NawaYaYaY#M#D#D#D#D.7afaja9#Lajbp#Lbpbp#Lajbp#Lbpbpa2bp#g#g#g.j#g#gas#g.j#g#g#g#g#g#g#ga2a2aj.7a9#Da9#Da9a9#s#D.s#x#I.Ca0aO#uazal.Y.A.1a.aHaGaz.Ta#bma##SaFaFbgama0.C#x.s.NaY.N.N#s#D#Dblbl#Dbl#D#D#D#D#Da9#D#D.7.E.7a9#D.saY#x.Wa0.8.5#S#uaB#S.5.C#x#x.NaYbl#Da9#D#D.Na9a9.7a9#L#L#L#La2asa2aaa2#ga2a2#L#L#L#L#L#L#L#La2af#L#La9.7a9#Da9a9.7#La9#L#L#L#L.3#La2#L#L#La2#Lafa2#La2a2#La2#La2#La2#La2#La2a2a2a2a2a2a2a2a2#L#L#L#L#L#L#L#L#La2.7#L#L.7af.7a9a9a9bja9#D#D#D", +"aYaYaYawaYaYaY.saY#M.NawblaY#Daw#Dbl#D#s#D#La9.7#L#L#L#L#L#L#Lbpa2bpa2aj#ga2bpa2as.j#gas.j#g.j#g#gbp.j#L#gaja2bp.j#Laf#L.7#s.N#sbjb..N#Ibf.Waq.8#vaz#zaHbs.m.B.BauaSa#aFaFbgama0ambga#aFamam.W.CaYaY.NawaY#D#D#D#sbl#D#D#D#D.Nb.a9a9.n.7#La9.7b.#Da9.s.Nbo.C.Cava#aZaBaBaOaOb#ao#x#IaY#D.n#Da9#Da9a9a9#L#L#L#L#La2a2#ga2#ga2#ga2bpa2#ga2a2#ga2a2#La2af#L.7a9a9.7a9a9#D#L#L#L#L#Laf#L#L#La2a2a2#La2#La2#La2#La2#La2#La2#La2#La2#La2#La2#La2#La2#L#L#L#L#L#L#L#L#L#L#Laf#L#La9.7.7a9.7a9#D#D#s#D#D", +"aYboaY#x#x#I#x#x#I#xaYawaY.NaYaY#D#M#Da9.7.7aj#L#L.E#L#Lbp#L#L#Lajbp#Lbp#Lajbpaj#gas#g#gas#gas.j#L#Lbp#Laj#gbp#L#Laj.7a9.7#Dbj.N.N.sbo.Caq.8#v#u#3adbe.A#Y#9.PbranaBb#amamaYaYaYa0am#vbmaOb#.C#x.s.N.NaY.N#Da9#D#pa9.na9#Da9.7a9.7a9.7a9.7.7.7.7a9#D#D.N.N#xbo.Cb#aOaF#vbma##vbmamam#xbl#D#D#D#Da9a9.7#Laf#L#L#L#g#La2bpa2#L#ga2a2bp#Lbp#L#Lbpa2#L#L#La9a9.7a9.7a9af.7af.7#L#L#La2#La2a2#L#La2a2#La2#La2#La2#L#La2#La2#La2#La2#La2a2a2a2a2a2a2a2#L#L#L#L#L#L#Laj#Laj#L.7aja9#L.na9#D#s#D#D#D.N.N", +"#x#x#x#I#x#x#IbnaYaY#IaYaY#MaY#M#D#D#Da9.7#L#L#L#L#L#L#L#Lbp.E#Lbpa2bp.j#L#g#L#g.j#gas.j#g.j#g#g#Lbpajbp#Lbp#Laj#L#Laj.7.n.N.N.sbf.C.Caoa#.w.ObB.u#.#oa8aMabalanaBa#a#a0#xaYaYaY.Wamb##Sa#b#a0.C#xaY.NaY.s#D#D#D.nbla9a9#D.n.7a9#L#L#L#Laj#L#L.7.E.7b.a9.s.N.N.s.Camam.8aF#vaZ#uaFb##xaYaY#D#D#sa9a9a9.7#L#L#L#La2a2#ga2#ga2a2#g#L#L#L#L#L#L#L#L#La2af.7a9a9.7a9a9a9#D#L#L#L#L#La2#La2#La2#La2a2a2a2a2#La2#L.3#L#La2#La2#La2#La2a2#La2#La2#La2#L#L#L#L#L#L#L.7#L#Laf#L#L#L.7a9.7bja9#D#s#D.N.saY", +".CaC.Ca0.Ca0#x.CawaYaY.Nbl.N#D#D#Da9.E.7aj#Lbp#L#L.7#Laj#L#Lbp#Lajbpaj#Lbpaj#Lbp#gas.j#gas#gas.jbpaj.7#Lajbp#Lbp#La9a9#D.N.s.N#x.WaqaO#ubk#zaHbA#Pbsbeab#a#ua#ambm.Fa0bn#xaY.N.s.Nbnb#bmaBa#aC.Caw.NaY.NaY#D#D#D#pa9a9a9a9.7a9#Laj.7#L#L#L#L#L#Lbja9bjbj#D.7.N.Nbo.C.Ca0a##vana7an#Sa0aYawbl#D#Da9a9.7af#L#L#L#L#L#L#L#L#L#L#L#L#L#L#L#L#L#L#L#L#Laf#La9.n.7#Da9.7afa9#L.7a2#L#g#La2#La2#La2#L#L#La2a2#La2#La2#La2#La2#La2#La2#La2a2a2a2a2a2a2#L#L#L#L#L#Laj#Lafaj#L#L.Eaf.7#La9#s#D#DaY.NawaY#x", +".C#xa0#x.W#x#x#x#DaY#Dbl.sblaY.Na9#D#L.7#L#L#Laj#Laj#L#Lbp#L.7#Lbpa2#L#g#L#g#L#g.j#gas#g#g.j#g.jbp.7#La3#La3aj.7.7aj.7#s.N.N#Ibf.8aF.y#3ad.A.MaT.P#V#P#Tan.5.C#Ia0b#bga0#xbf#xbf.N#xa0bm.T#Sao#x#x.NaY#s.N#D#D#D#p.nafa9.na9#L.7#L#L#L#Lbpaja3#L.Ebj.E.7#sbj#sbjbf.s#xavama#aBana7aZbgbnaY#D#D.7.na9a9.7#L#L#L#L#L#L#L#Lbp#L#L#L#L#L#L#L#L#L#L#La2a2#L.7a9a9a9.7a9a9a9#L#L#L#g#La2#La2#La2#La2a2#La2#La2#La2#La2#La2#La2#La2#La2a2#La2#La2#La2a2#L#L#L#L#L.7#L.7afaj#L#L#L.7a9#LaY.Naw.Naw#x#x#I", +"aY.saY.NaY#DaY.N.na9.na9a9a9a9aja9a9a9a9.7a9.7a9#Laf#L#Laj#L#gaj#Lajbpaj#Lajbpaj#Lafaj#L#L.7.Ea3#L.Ebj#D.s.N#Db..7.7.N.N.WamamaOakaybs#Y.maDbaaHaga7#SamamaC.C.CaYamb#aFb##xaY#D.n.Nawa0#vaZaZa##xaw.N#Daf.na9#s#Da9a9a9.7af#Laf#La2#g#g#L#Lbp#L#L#L#L#L#L.7.7.7.7bj.N.Caoam#vaZaz.fanama0aY#Ma9aY#D#Da9a9.7.7#D#L#La2#La2#L#L#La2a2a2a2a2a2a2a2.7afa9a9#D.7#D.7af#L#L#L#La2#ga2a2a2a2a2#ga2#ga2a2a2a2a2a2a2a2a2#La2#La2#L#L#L#La2#La2#La2a2a2#La2#L#Lafa9a9a9bja9#D#D#DaY.s.N#x#Ibn#x#x#x#x#U#x", +"aY.Naw#D#D#s#D#Da9a9a9a9a9afa9a9a9a9.Ea9a9.na9a9afajaf#La2#L#L#Lbp.7bp.7bp.7bp.7a2a2#Laj.7.E.7.E#L.E#D.s.N.Nbjbj.N.s.N#xa0aO#u#E#V#2....#KaD.YaGa7bmaFaFaoama0.CbnaCb#aOama0.N#D#Dbl#xa0bmaB#ua##x#xaY#sa9.7a9.7#D#D.7a9a9aj#L#L.j#La2bpa2#Lbp.E#Laj#L.E#L.7b.#Db.#D.s#xa0.8a##v.6azbhaOam#xaYbl#Dbl#Da9#Da9.7.7#La2#La2a2a2a2#La2a2a2a2a2a2#La2#L#L#L#D.7a9#Da9#L.3afa2#La2bpa2bp#g#L#g#La2#L#g#La2#La2#La2#La2a2#La2#La2a2a2#La2a2a2aja2#L#La2#Lafaj#La9.E#Da9#s#D#Daw.NaY#IaYaYaYawaYawaYaYaY", +"a9a9a9a9.na9a9.na9.na9.na9.na9a9a9.7a9a9.7a9.7a9#L#L#L#L#Laj#L#Laj#Laj#Laj#Laj#L.jbp#L#L.E#L.Ea3.n#D.Nbf.Cbo.Caobf.CamaOaBaz#EaraQ#.#o.Abzay.Gana#aFaFaOamam.C.Wbna0a0b#ama0#I.N#D#M#x.CaoaZbhaBa0#IaY#Da9#s.7a9#sa9#Da9a9#Laf#L#L#ga2#g#L#Lbpbp#L#L#L#L#L.7.7.7.7#D.NaY.Cambga#a7.6#ua#b#aoa0#xbl#D#Da9.7a9#Laf#L#La2#La2a2a2a2#L#L#L#L#La2#La2.7afa9a9#D.7#D.7afaf#L#La2#L#L#ga2a2#ga2#ga2#ga2a2a2a2a2a2a2a2a2#La2#La2#L#La2#L#L#Laf#L#Lafajaf#L#Lafa9a9a9#Db.#D#DaY#DaY.N.N.N.s#D.N#D.N#D#s#D", +"aj.7aj.7.7.7.7.7#Da9#Da9a9a9a9.7a9#Da9#s#D#D.n#Da9a9.na9.7.7bj.7bp#L#L#L#L#L#L#Laj#Laj.E.Ebjb..N#MawaCaoaoama0.Cb##va7#a.Oaz#uaZaZanaz#e.6anaZaFaBaOaF.5amama0a0#xaCa0ama0a0#xaYbl.NaY#xa0#vaZ.lama0#x#Mbl#D.7#D#Dbja9.Ea9af#L#La2#L#La2bp.j#Lbp#Laj#Lbpaj.7bj.7#s#D.s#x.Wa0amamanaB.0a##va#bgamaYaY#Da9a9a9#L#L#L#Laf#L#L#L.7#La2a2#La2#L#La2#L#L#L.7a9.7a9#Da9#L.3#La2#L#L#La2bpa2#g#La2bpa2bpa2#La2#La2#La2#La2#La2#La2a2#La2.3#L#La2#Laf#L#Lafaja9a9.7#s#D#D#Da9.s.N.s.Naw#Dbj.7b..7b..7bjbj", +"#L#Laf#Lajafaj#Laf.7.7.7.7.7a9.Ea9bja9#D.7a9bja9a9.7a9.7a9.7.Ebjaj#Laj.7.E.E.7.E.7.E#D.s#xbo.C.WaCamb#a#.y.0.yaB.Gazazazbhbma#aFaFa#a#aZaBa#.5.5#SaFambgama0amam#x#xbna0a0aCa0#xaYawaY#Ia0aO.lbh#vb#bnaY#s#D#s#D#Da9#Da9.7ajaf#Laja2bp#g#L#Lbp#Lajbp#L#L#Lbj.7.7#Da9#DaY#x.CaCam.5a#aOa#a##va#a##xawaY#Da9.7#L#L.7af.7#La9#Laf#L.7af#Laf#L#Laf#Laf.7a9.7a9a9#D#Daf#L#La2#L#L#L#La2a2a2#ga2a2#ga2a2a2a2a2a2a2a2a2#La2#La2#L#L#L#L#Laf#Lafa9a9a9a9a9a9a9bj#D#D#D#D#D#D#Da9#Da9#D#s#L.7#L.7#L.E#L#L", +"#Laj#Laj#L#L#L#L.7.n#La9aja9#L.7a9#s.7#Da9#Da9bj.n#Da9.7.E#Dbj#D#D#D#Da9#Da9#Da9.N#I#x.Wam.8.5#va#aBaP.G#a.U#4.Uaza7aZa#aFaFbmb#a#b#aFa#.8ama0ama0a0a0a0a0aC.Ca0#I#x#xa0b#a0a0a0aYaY.N.N#Iambm.lbmaFaobnaYaY#Dbj#D#s.7a9a9af#L#L#La2aj#ga2bp#Lbp#L#L#Lbp#L.7.E.7#D#D#D.saY#x.C.CaC.5am#v.5a#.0#va0bn#x.N#D#D.7.7a9.7a9.7a9.7.7a9#L#L#L.7af.7#L.7#L#L.7a9a9bja9#Da2afa2#La2#L#L#L#L#g#L#g#L#g#La2#La2#La2#La2#La2a2#L#L#La2afa2af#L#L#L.7a9.Ea9.7.n.7#Da9#s#D#D.N.N.sbj#sbjb..7bj#Laj#Laj#L#L.7#L", +"bjbj.7bj.7.E.7.7.7.7a9.7a9.7a9.7#D#D#D#D#s#D#D#D#D#D#D#D#D.N.s.N.sbfbobf#Ibf#xboa0.8.5#v.yan.w.G#TabaMa8#cabalaZa#aFa#b#b#a0b#b#ama0aoa0a0#x#x.CawaYaY#Ubn#xaYaY#x#x#x.Rbna0a0amaYaY#D#DaY#UaF#GaZ#S.V#UaY.s#Dbj#s#Da9.n.7#La2af#L#La2#g#gajbp#L#Lbp#L#L#L.7bj.7a9#s#Dbl.N#x#x#x#x.C.Cam#va#a#.0aF.8a0#x#x#D#D#Da9#D.7#Da9a9.7.7#Laf#L#L#L#Laf#Laf.7a9a9.7a9#D#Daf#La2#La2#L#L#L#ga2#ga2a2#ga2bpa2a2a2a2a2a2a2a2#Lafa2#L#L#L#L#Laf#La9a9#La9a9a9a9#D.7#D#D#D#D#D.s.Nbja9.7.7a9.E#L.7.7.7.7aj.7aj", +".7a9b..7.7bjbj#D.Eaf.7#L.7af.E#L#D#D#D#D#D#D#s#D#D#s#Dbj#D.s.N.N.C#x.C.C.C.W.C.Wby#vaBaz#T#4aH#..ga8bsbr.2al#TaZaFaFb#b#ama0a0a0.Cama0#xaY#x#x#xaYbl.NaYaYaYblaYbf#x#x#xbna0a0aobn#xaw#D.sa0.t#SbmbmaOa0#U.N#D#D#D#D#Da9a9#Laf#L#L#La2#L#g#L#Lbpa2ajbp#Laj.7.7.7#Dbl#DaY.N.N#Ibf.Naw.Cao.5.5a#a##va#ama0bf#D.N.N.7#Da9#D.7a9.7a9#L.7#La9#La9#L.7#L#La9.7a9bja9#Da2af#La2#L#L#L#L#g#La2bpa2bpa2#La2a2#La2#La2#La2#L#L#Laf#L.3#Laf.7a9af.7a9a9.7a9.7#D.n#D#D#D#D#Dbjbj#Dbj#s.7.E#La9.n.7.na9.7a9.7", +"#Laj#Lafajafaj#La9#D#s#D#D#D#DaYaYaYawaYaY.NaY.N.C.C#x#IaYaY#M.namav.8.5#v.0.w.G#aau#4#4#z#3.Ga7#Z#0aM.gaTayaZa0a0a0a0#xbn#x#U#xawblawaY#D#M#D#D#D#Da9#D#sblaY#Mbl#Mblbl#DaYaYaYa0#IaY.N.NaY#Ua0.t.tbm.Fam#x.Nb.#Da9a9.7af#L#La2aj#L#L#L#L#Laj#L.7#L#L#L.7#L.7af.7.7a9.7.n#D#D.NawaYaY#x.CaCamao.0a#aB.0.taFb#.VaY#Da9a9af.7#D.N#Laf#L#L#L#L#Lafa9a9a9a9a9.7.7.7a2#La2a2a2a2a2a2a2a2a2a2a2a2a2a2#g#L#ga2a2#ga2a2a2a2a2a2#L#Laf.7#pa9a9a9#Dbj#D.N.na9a9a9b.#D#D#D#D#s#D#D#D#s#D#D.n.7#L#L#Laj#L.7", +"aja2afaj#L.7.7#L#sa9#D#D#s#D#D.N#D#D#D.N.N.N.N#DaY.N#x#xaCamb#aF#SaZanaz.Galba.4.O#aaz#uaB.0aBan#Tbz.mab.2az.5#xa0bnaYaYaYaYaYaY#DaY.NaYbl#D#D#D#D.n#D#Dbl#Dbl.Na9bl#Dbl#DawaYaYbnaYaY#D.s.N#xaCbm.Fbm.tb#aC.N.Nbl.na9a9aj#L#L#L.7#L.7#L.E#L.7#L#L#L#L#L#L#Laj#La9aj.7.7.7#D.N#D#Dbl.N#xbn.Ca0ama##va##v#vbm#vaF#x#x#Da9a9#D#D#D#L#La9#L.7af.7#L#pa9afa9.7#D#La9#La2a2#La2#La2#La2#La2#La2#La2#La2#ga2a2bpa2bpa2a2a2a2a2a2#La9afa9.na9a9#D#D#Dbja9.nbj#D#D.NaY.saY.Nbl.sblaYaY.Na9.7#Laj.7.7#L.7", +"#Laj#L#Laja9.E.7#La9.Ea9#D#D#s#Db.#D#D.Nbo.Caqaq.bbnbga#aZaS.G#q#t.HaQauaGar#a#a#vaOaF.5b#.8#vaB.2.A.1aDaka#amaYaYaYaYaYaYaY#D#D#D#D#s#D#D#D#D#D.7.7a9#D#D#D#Dbla9a9.n#D#D#D#Dblaw#xaw.N#DaYaYbnb#aF.taOb#.C#I.Na9a9.7a9a9#L.7#L#L#L#L#Laf#L#L#L.n#L#L#L#L#L#L#L#La9a9.7a9.Ebj#D#D#D.s.N#x#x.W.Ca0amamaFa##vbmaBb#bnaY#D#D#Da9bjaf#L#L#Laf#L#L#La9a9a9a9a9a9.7.7a2af#L#L#L#L#L#L#L#La2#La2#L#L#L#L#L#L#L#L#L#L#La2#L#Laf#La9.7a9a9afa9a9bj#s#D.Nbl.NblaY.NaY#xaYawaYawaYbl.sbl#M.7.E#L.7#L.Ea3.E", +".7.7.E.7.Ebj.7.7.n.7a9.7#s.N.N#DaY.N#x.Cam.5a#aZaF#SaZa7arala6ay#W#W#kbhbmaFa#.5#x#x.CaCaoamaOaB#P#obsba#uam.C.NaYaYaY#D#D#D#D#Da9#Da9#D.7#Da9a9#La9.7.7a9bl#s#Da9a9a9bla9bl#D#DaY.NaYawaYaY#IaYa0aCb#.Va0a0#U.N#D#Da9.7a9.7aj#L#L#L#Laj.7#L#L#L#L#L#L#L#L#L#L.7#L#L.E#La9.7.7.7#D#D#DaY.s#x.C.C#x#Ia0aCama#a#aZa#.8a0#xaY#Da9af.7#Da9#D.7#Da9#Dafa9afa9.7a9#La9#L#L.3#L.3#L.3#L.3#Laf#L#L#L.3#L#L#L#L#L#L#L#L#L#L#L#L#La9.7a9a9a9#D.na9bl#DaY#s#x#x#x#Ia0#I#x#xawaYblaw.NaYaYaY.7#D.7.Ebja3.7.7", +"#Db.#D#D#s.N.s.NaY.Naw.N.NaYbo#xa0b#a#bmaS#aa6.Kbaba#a.faZaFb#amb#b#ama0.C#xbf#xbobf.NaY#xao#v#u.q.qaGanamaYaY#DaY#sbl#Da9.7#L.7.7.E.7a9.E#L.7.E#L#L#La9.nbjbl#Da9a9.7a9.7#D#D#DblaY#xaYaY#IaYaY#xbna0bnbna0aCbn#sbl#Da9.7af.7a9#L#L.7#L#L#L#L#L#L#L#L#L#L#L#L#L#L#L#La9.7af.7a9aj.7#D#D.N.Nbo#x.Nbl#Ia0am.5aO.0aB.0b#.CaYbla9a9a9.7a9.7a9.7a9a9a9#pa9a9a9bj.7.7#L#L#L#L#L#L#L#L#L#L#Laf#L#L#L#L#L#L#L#L#L.7#La9#Lafa9bja9#D#D#D#Dbl#DaYaYaYaYaY.C#xama0.CaC.C.C#x#xboaYaY.NaY.N#s.N#D.N.s.NaEaW", +".N.N.s.N.Nbf#xbfaCa0a0a0a0amam.8aZbhazaGau#j.e.e.6ana#.5ambn#xaY#I#x#xbo.N.N#saW#x#Ibfaw#x.5aZ.G.q.KaBam#xaY.s#D.7#Da9.7.E#L#L#L#Laf#L#L#L#L#L#L#Laj#L#L.7#Da9#Da9.7a9#D#D#Da9#D#DawaY#IbnaYaY.Naw#xbnbnbna0bna0aY#D#D#Da9.7#L.7#L#L#L#La9#L#L#L#L#L#L#L#L#L#L#Laj#L#L#L.n.7.7.7#La9.E.7#D.N.N.N#saY.N#x.Wa0.5aF.0aZ#v.5a0aY#Da9.7#Da9bja9#D.7#Dafa9afa9.7a9#La9#La9#La9#La9#La9#La9#L.7a9af.7af.7#L.7.7#L.7af.7.7a9.7#D#D#D#D.N.saYaY#x#I#xbnbnaOaoaoamaCa0a0bn#Ibn#x#x#x#x#I#x#xaYboaY.N#xbf#x", +"#x#xa0.CaCa0aoa0aFa##v#vaZ#uaZaZarazazanbmaF.5a0.C#x#x.N#D#D#D#D#D#D.Nblbj#D.N.sbf#x#I.CbgaBaz.2baazaF#x.n.7#Dbla9.7.7#L#L#Lajbp#L#L.E#La9#L.7#L#Lbp#L#L.7#L#D.E#L#L.E.7.7.7.7#Dbj.N#xbna0#I.N#DaYawbna0bnbn.V#U#D#D#D#D#D.7a9.7#Laja9#Laj#L#L#L#L#L#L#L#L#L#L#L#La2#L#L#L#Laf.7#L#L#La9.7#s.N.N.7#D.N.N#x.CaCaq#vaZaBa#aF#xaYbl#D#D#D#D#D#D#D#Da9a9a9a9a9a9.7.7#L#La9.7a9a9#L#L#La9a9a9.7a9.7#L.7af.7af.7a9.7.7#D#D#D#D#D.N.NaY#x#x.Ca0b#ambgamaOb#aCa0.C#I#xaYa0a0#xbn#x#xbna0aCa0a0a0ao.CaCaq", +"aoa0aoaO.5.8aFaO#u#uaSazaG#3araza#a#amam.C#x.s.Nafaf#La9bjaWbfbf.N.NaY#xawaYaYaY#x.C#xaCamaB#aaT.GaF.C#D#La9#L#D.7#Laj#L#Lbpbp#Lajaf#L#La2#L.j#Lbp#L#Lbpa9.7#Da9.7#La9#La9.7a9.7#Dbl#xaCbn#xaY.s#D.N#Ubnbnbnbna0bl#D#D.7a9.7#L.7a9#L#L#L#L#L#L#L#L#L#L.7#L#L#L#L#L#Laj#L.7#L#L.7a2.7#L.7.7#D.N.Nbj#D.s.N.N#I.Ca0aFaZaBaZ#vam#xaY.7#Da9#D.7#Da9#Dafa9afa9.7a9.7a9#L#Lafa9#La9#L#La9af.7a9a9a9afa9a9#L.7.7a9#L.7af#D#D#D.N.N.NaY.s#xama0.8aF#Sa##va0a0a0#xbnaYaYawbn.WbnaCbnaCa0aCaFb#aO.5aOaF.8aF", +"aZ.ya#amaoaFaB.Taka6aGaraBaFa0#xbnaYaYaw#D#Da9#D#L.Eaf.7a9aj.7.7aja9.n.7#D#D.sbfaw.N.Wam#v.w.Ga7.C#IaY#D#s.7.n#Laja2#L#ga2#ga2#g#L#Lajafaj#L#L#Laj#L#L.na9a9.na9a9a9.na9a9#L.Ea9a9#saYaY#x.C#x#xaYbn#x#U#x#xa0aCbn#D.7#L.7a9a9#paj#L#L#L#L#L#L#L#L#L#L#L#g#L#L#L#L#L#L#L#L#L#L#Laj#Laf.Ea9.7.7a9#Da9#D#D#DaY.NawaY.pa#.0.0a#ambn.N.N#D#D#D#D#D.7a9af#L#L.7#L#L#L#L#L#La9a9.7a9#Da9a9#Da9bja9bj#D#D#D#D#D#D#D#D#D#s#D.saY#xbn.8aFaZaBaZa#aFama0aqaC#x.N#MaY#x.Ca0aFb#b#amamb#.5aFaoaOaFaOa#bmaZ.y", +"aZa#aOa##v#vaB.T#4#z#a#uaFa0aC#xaYawaYbl#Da9#Da9.7a9.7#L.7a9.7a9af.Ea9.7#s.N.N.N#D#Ia0.8a#bkaraZ#IaY.s#D#Da9.7#Lbpa2bpa2#g.j#ga2ajaf#L#L#Laja2#Laf.7#L.7a9.7#Da9afa9a9a9a9.7a9#La9#Dbl#x#x#I#x#xawaY#U#xbn#Ia0.CbgaYa9#L#L#Lafa9#Laj#Lbp#Lbp#Lbp#Lbp#L#ga2#g#La2#L#L#Laj#Lbpaj#L#L.7#La9.7.7a9.7.E#D#D#D#D.saY.N#Ua0#va##S.0aOamaY.N#D#D#Da9#D#Dafa9a9af#L#L#L.7af#Laf#La9#Da9.7a9a9.7#D#D#D#D#Da9bja9a9#D#D#s#D.N.N#x.Ca0aoaF#vaZbmbmaOa0.W.C#x.C#xbl.NawaY.CamaCamaCamamambgamb#.5aOa##Sa#.yaZ", +"#vaFaO#v.ybmaZazbaauazb#a0#x#xaYaYaY#D#sa9#D.E.7aj#L.7aja9aj#L.7aja9.n.7#D#D.sbfaY.WaCam#u#3a7aFaYaY#D#D.n.7ajafaj#gaj#g#L#g#Laj#L#Lajaf#Laf#Laj#L#L#La9a9#Da9a9.na9a9.7.n.7.7a9.na9aY#x#x#x#x#xaYaY#x.R#IbnbnaC.t.VaYa9.7aj#L#L#Lbp#L#Laj#La2#L.j#La2#g#g#g#gajbp#Lbp#L#L#L#Lbp#L#L#L.7a9.7.7.7a9#D#s#D#DaY.NaYaYa0ama#a#.yb#a0.N.N#D#Dbj#D#Da9a9a9.7a9bja9.7.7a9a9a9#D.7#D#D#D#D#Da9#Da9#D#D#Da9a9.n#D#DblaYaY.8b#.8aOaFaOaFaOb#bgama0#x#x#x.N#U#x#I#x#x#xaoama0bna0bnaoam.5amaOaFaFaF#va##vaZ", +"aOaOaF#va#a#az#faS#ubmb#a0#xaY#Dbl.n#Da9a9.7#L#L#L#L#L#L#L#Laj#L#L.Ea9a9#s.N.N.s#x.Wb##v#Ebk#va0aw#D#D#Da9#L#L#Lbpa2#L#ga2#ga2#g#Laf#L#L#Laj#Laf#L.7#L.n.7#D.na9a9a9a9a9a9.7a9#La9#sbl.NaY#xaYaYblaYaw#x#x#x.C.C.Fb#bnbl#Da9.E#L#Laj#L#Lbp#Lbp#Lbp#Lbp#L#g#L#g#L#Laj#Lbp#Lbp#L#L.7#L.n#L#L.7af.7#Da9#D#D#D.NaY.saY#Ibn.5a#a#aFambf#x.NaY#D#D#D#Da9a9a9.7a9.7.7#L#D.nbj#D#D#D#D.Na9b.bl#Daw#xaYaYaYaYaY#Ia0a0aoam#uanaBa##vb#bgb#bnbnaYaYaYaYblaw#x#x#x#Ua0.Wa0a0.W.C.Wama0ambg.5aFaFa##va#a##va#", +"b#ao#vbmaB#uaz.Gb#b#ama0#xaw.N#D#Da9a9a9.E#L#Laj#L#Laj#L#L#L#L#L.Ea9.n#D#D.N.N#x#Iao.5#u.Oazam.C#Dbl#sa9ajaf#La2.jbp.j#L#gajbpaj#Laj#Lajaf#L#Laj#L.n#La9a9a9a9#D.na9a9.Ea9.n.7a9a9#DaYaw#x.sbl#D#sblaYbl#I#x#Ua0b#bgb#bn#D#D.7#Lbj.7.7.7.7.E.7.7#L.j#La2#g#L#La2bp#L#Laj#L#Laj#L#L#L#L.7af.7.7.7a9.7#D#D#s.Nbl.NaYaY.CaCby#va#.8#xbfaY.N.s#D#Dbj#D#D#D#D#D#D#D#D#D#D#D#D.Naw.NaY#D.NaYaw#x#xa0aoamamaFaF#v.0bbanaBaZ#vaFb#am#x#xaYaYaYaY#IaY#D#D#x#x.Ca0avamama0.C#x.Ca0aoamaFa##uaZaBaZ.y#S.0.y", +".8aOa##Sazar#ua#a0am#x#x#x.N#D.7.na9#L#L#Laj#Lbp#L#Lbp#L#Laj#Laj#La9.7.n#D.sbo#x.Wao#v.f#f.ya0bf#M#D#Da9a9#L.ja2#La2bp.j#L#ga2a2#Laf#Laf#Laj#Laf#L.7aj#Da9b.bl#Da9.na9a9a9a9.7.n#D#MaYbfaYaY#Da9#D#D#Daw.NaY#x#Ib#b#bg.VaYbl#s#L.Ebj.7b..7.7.7.7#Lbp#Lbp#L.jbp#L#L#Lbp#Lbp#Lbp#L.7aj#La9.7a9#L.7a9#s#D#D#DaY.Naw.N.s.CamamaOa#a#.W#xbf#xaY#D#D#Da9#Da9#Da9bj#Dbj#D.N.Naw.N#x#xbfaYaw#x.Ca0a0aFbma#aBaZbbaZ#uaZ.0bgb#a0am#x#x#xaYblaY#MaYaY#Dbl#DaY#xaCamamaoaqaC.C.Wamao.5a#a#.yaSazaZ#uaZ.yaOaF", +".5aF#Sbhaza7aFa0a0bn#xaw.N#D.7.7af#L#L#L#La2#L.j#g#Lajbp#Lbp#Lbpaja9.n#D#s.N#I#I.WaF#uarazaF.W.Nbl#D.n#Laj#La2a2aj#g#L#g#L.jbpaj#Laj#L#Lajaf#Laj.7afa9.na9#D#D#Ma9#p#s#D#sa9.na9#DblawaYaw#Da9a9#D#D#saY.Naw#x#xaCb#.VaC.V#xaY#Dbj.nbja9bj#s.7.7aja2#L.j#Lbp#La2ajbp#L#L#L#L#L#L#L#L#L.Ea9.7.7a9#D.7#D#D#D#DaY.N.N.N#I.CaoaFa#aB.C#x#xbf#x.N.NaY#Dbl#D#D#D.N#D.NaY.saYaY.C.W.C.W.Caqa0.8a#aZaBan#u#uan#Sa#b#ama0bnaY#xaYaY.NaY.N#s#DaY#DblaY#Dbl#I#xam.8.5aOam.Cama0aoaFbmaBbha7#a#ea7an.y.yaF.8", +"bc.y.wara7b#a0aoaYaYaYbl#Da9.7.7#Laja2#L#g.j#g#ga2bpa2bp.jbpaj#Laf.Ea9#s#D#I#I.C.WaOaz#EaZb#.C.N#sbla9afafaj#L.j#L#g#L.jbpa2bpa2#Lafajaf#L#L#Laf.E.7.n#Da9#D#sbl.n#D#M#s#D#s#D#s#DawaY.NaY#Da9.n#D#D#D#DaY.NaY#I.CaCam.Vb##U#xawa9bj.7b..7bj.7bj#Laj#Lbp#La2#L#Lbp#L#Lbpaj#Lbpaj.7#L.7af.7a9.7.Ea9#D#D#s#D.N.saYb..Nbf.Wa0aF.0#ua0.W.C#Ibfaw.NaY#saY.N.N.N.N.N.N.N#xaY#I#x.W#x.C.Wam.8aZ.waz#ubha#aFaFb#ambn.bblawaY#MaY.N.s.N.N#D#D#D#DaY.saY#I#xaCam.8aFbyaoaCaoamama#a7azararaya6.G.Gaz#u#v.8", +".J.far.laobn#xaY#D#sa9#D.7a9aj#L#L#L#L#L#Lbp#Laj#g.j#ga2#L#L#Lbp.na9.7#s.N#I.Caobh#EaBaCbn.s#IaY#Ma9.n.7#L#L#L#Laj#Laj#L#Laj#L#L#L#L#L.7aja9.Ea9bl#M#D#M#DblaYblaYawaYaYawaY.NaYawaY#Mbl#D#D#D#Da9.n#D#s.Nbl.saY#x.RaY.N#xa0aFbm#IaYaY.N#s.7.E#L#L#La2#L#L#Lajbp#L#La2#L#L#L.7#La9a9a9.7#L.7.7.7#Da9#D#D#DaY.N.NaYaY#Ia0.5.8a#an.0.5bn#xbl.N#x.C#Dbl.sblaY#I#x.W.R#Ibna0aOa##vaZazararaz#ua#aFaO#x#I#x#Ibn#x#xaYaYaY#DblaY#Dbl#Dbl.NblaY.NaY#x#xaoaobnaY#xaCa#.0aOaOaOaFaFaFaFaF.l.Ta7bh.G.G#q#e", +"araza7aFam#xaYawa9#Da9a9a9#L#L#L#L#Lbp.j#L#La2#Las#ga2#gbp#Laj#L.7.7.n#D#M#xaCaFbk#iaOaC#xblaY.Na9a9a9afaja9aj#L#L#Laf#Laf#Laf#Lajafaja9#L.7a9.Ebl.n#D#M#DawaYawbn#Ubn#I#x#I#xawaYawaYaY#D#s#D#D#D.n#D#DaY.s#x.N#U#IawaY#xbna0aF#x.W#xaw.N#D.7b.afajaf#L#Lbp#L#La2#L#L.E#L.7a9.7a9a9.na9.7a9.7.7#D#s#D#D#D.Nbl.Naw.N#x.CamaF.0.y.yaF.CaYaw#x.Caq#Ibn#x#x#x#xbna0aoamaF#vana7.wazaZan#uaZaOamamamaY.RaYaYawaYaYaYaYblaY#D#Dbl#DaY#DblaY.N#xaY#I#xbnbnawaYbnam#va#ama0a0aoamamaoam.taFbmaZ.6ar.2#4", +".faBb#a0aY#xbl#Da9a9#D.E.7#L#L#L#g#ga2#g#g#g#g#g#g#g#ga2#L#L#L#L.n.7a9a9.N#Iam.8#f.Gb#bn#UaYaw.Na9.na9.7af#Laf#Lajafaj#Laj#Laj#Laf#Laf#L.na9a9#D#Mbl#M#DawaYaw#x#I#U#x#U#Ibn#I.NawblaY#s#D#D.N.sa9#s#D#M.NaY.s#xawaY#D.s#D.Nbnama0a0aC#x#xbl.NaY#La9#L.E#L#L#L#Laj#L#L#La9.7aja9a9a9a9#D.n.7a9.7#s#D#D.Naw.N.NaY#Dbl#I#xaC.5#va#aBaFa0aC.C.Caoa#ama0a0ambgaF#va##uan.w.wan.wanaZ#vaFb#ama0a0#x#xaYbfaY#xaY.Nbl.Nbl#D#D#Dbl#D#D#D#DaY#saY.N#x#x#xaYaYaYaY#Ia0bg.5bn#xbn#xbna0a0amaCb#ao.t#SaZar#a", +"aFama0aY#xaY#Da9#D#Da9a9#L#L#L#g#ga2#gbpa2bpa2bpa2#ga2#gbpajbp#L#Da9.7#saYaY.W.5#EaraFa0#U.NblaYa9a9a9ajaf.E#La2#L#L#L#Laf#Lafaj#Lafaja9#D.n#D#D#s#DblawaY#I#x#Ibnbn#I#U#x#IaY.N.Rawbl#D#D#D.s.N#D#D.saY.saY#I#x.N#s#s.7bj.N#xa0aob#amaoa0#I#xaY#D.na9.7a9bpaj#L#L#L#La9.Ea9#D#D#D#D#D#D#D#Dbj#DaY.Nbl.N.N#x#xbfaw.NaY#xama0aOa#aBa#bgama0.5a#.0aFaOaF#SaZan#ua7bhazaBbhaBa#aFb#b#aCbnbn#x#xaYaw.Nblaw#D#Dbl#D#D#s#D#p#Da9#D#D#Dbl#DaY#x#xaw#x#xaY.NaY#x#x.C.C.CawaYaw#xaw#x#Ibn#x#Ua0a0amaFbmbm", +"bn#xaYaYaY#Ma9af.7.n#L#L.7#L#ga2bp#ga2#g#ga2#ga2#ga2#L#L#L#L.7.7#s#D#s#D.N#xamaoaS.OaBam#xaYaw.N.na9a9#Laf#L#La2ajafaj#L#Laj#Lafaf.na9a9a9bl#D#Mbl#saYaw#x.b#x#x#U#Ibn#I#xawaY.saYaYbl#D#D#D.N#D#M#sblaw.N#I#x#I#D#sbj#Db..N.N.Camamb#am.pa0a0bn#D#Da9.7.7aj#Lbp#L#La9.7a9a9#s#D#MaY#D#Dbl.saY.N.N.N.s#x#xbf#I#x.NaY#I.CaCamam#vaBbm#SaF#va#a#aB#ubh#uanaBaBbmaZ.FaFb#b#a0aCbn#I#x.RaYawaYawaY.N#D#D#D#D#D#D#D#Da9#Da9#Da9#Da9a9.saYaw.Naw.N#xaY.N#x#xaY#xaC#xaYblaYaYaYaYaYaY#xaYblaY#Ua0a0.Vbn", +".NaY#D#Da9a9a9#La9.7.7#L#L#g#L#ga2bpa2bpa2bp#gbp#g#Lbpaj#L.7.Ebjbj#D#Dbl.s#xaoa##TalaBam#x.NaY#Da9a9a9af#L#L#L#L#L#Lafaj#Laf#Lajafa9a9#p.n#D#M.NblaYaYawaY#x#I#x#Ibn#U#Ibn#I.NaYawaY#sbl#saY.s.N#sbl#s.NawaY#I#x#I.N#D#s#D.N#Ibnaoa0#Ia0a0b#aoamaw.N#Da9.7#L#L#L.7.n#L.7#s#DaW#DaYaYaY#I.NaY.N.N#I#x#xbf#x.C.C.C#x#I.Ca0amama#a#a7azaza7aZaB#uan#uan.laZ#SbmaFaF.V#Ubn#UaYaYawaYaYawaY.NaY.N#D.N.n#Da9#D.n#D.7a9#Da9bj.nbja9#s#DblaY#D#x#xaYaY#x#M.N#x#I#x#x#xaY#Dbl#DaYaYaY#xaw#x#IaYaYaY.baYaY", +"#D#D#Da9a9#Lafaj#L#L#Laj#Lbp#ga2#g#ga2#g#ga2#ga2#g#L#Lbp.7.7.7#D#D#s#D.saY.C.8aB#4#zaZa0#xaYaw#Da9.na9#L#L#Laja2#Laj#L#Lafaj#L#L#p.n#pa9blblaYaYawawaYaY#I#x#x#Ibn#Ibn#I#x#U#x#IaYblaYaY.Nbl.saY#s#Daw#Dawbf#I#x#I#x.s.N.s#xa0aC.C.Ca0.CaCa0ambg#x.N.s#D.7aj.7aja9.7a9#sa9#D.s.NaYawaYaYaY.NaYaYbf#x.C#x.W.C.Caqavaqa0ao.5#va##vaS#W#aazazanbm#SaFaFa#aFaOaFbgb#aCbnbnaw#x#x.N.N#sbl#D#s.N.N.N.N.7.7.7.7.7.7a9.7.7.7a9.7a9.7.7.7aY#DawaY.NbfaY#x.NaY#x#x.C.WaY#D#M#DaY.NaY#x#x#x#x#x#xaYaY#Da9#D", +"a9.7.7.7afaj#Laf#L#L#L#La2#La2#gbpa2bp#g#L#g#L#g#Lbp#L#L.7.7.7bj.s#D.NaY.Nao#v.QaD#za#am#xaY.N#D#pa9a9ajaf#Laf#L#Lafa2#La2#Lafaja9#p.na9#MblawblawaYaY#I#x#I#x#x#Ubn#Ibnaw#x#IaYaYawaY#M.saY.N.s#D#M#D.s.Naw#x#I.W#x#I.s#x.W#Ua0.Cava0.W.Ca0a0a0#I#IaY#D.7#L#L#La9.E#D#D#D.N#D.sbnbn#x#x#x#x#I#x.C#x.W.Caqamavam.C.5.5aFbya#.y.0.Gakar#e.TaBaFaF.5aFaOamb#a0aoambn#Ua0.C.Ca1bfbf.Nbl.N#D.N.N.N.Na9aj.7af#Laf#L.Eaf#L#L#L.7.n.7.n#DaYblbfaYaY#x#x.s#xbo#x.C#x.Na9#D#DaY.N#x#IaY#xama0bn#x#D#D.7#L", +"#Laj#L#L.7#L#L#Laj#L#Lbp#g#g#g#La2a2a2a2#ga2#L#L#L#L#L#L.7a9.7a9#Da9.s#Iama##u#.bA.faFaYawaYaYbfa9a9afa9#L#L#Lajafajafafajaf#Lafafafa9a9bl#Dbl#s.RawaYaY.R#U.R#Ubn#Ubn#Ibn#U#x#x#M#D#D#Daw#D#s#DaYaw#s.n#D.s#I.Caoaoam.8.5aO##am#va#byaFbcaqav.CaFaOaFaC#x.N.saW.N#D.N.s.N#I#xbn#U#xaw.R#x#xbna0#U.Vamb#b#aFa#bmaBaZ#vaZ#v.0aB.yaFaO.5bgamamamaobn#U.C#Ua0aCbnbnawaY#MaYblaY.saY.7.n.7.na9.E.7.7#La9#Laj.7#L.7af#Lafaja9a9a9#Da9.Nbl.Naw#x.s#xaY#x#xbn#x.baYaY#Da9.na9#DaY#x#x#x#IaYaY#sbla9.na9", +".7af.7#Lajaf.7#L#Lbp.j#L#g#L#g#ga2#ga2#g#La2#L#Laj#L#L.7a9.7.n.7#sbl.NaYaoa#azbAa6a7am.RaYaYaY#xafa9a9af#Laf#L#L#Lafaj#Laf#Lafajafaja9.n#D#M#DaYaw.R.RaY.baY#UaY#Ubn#UaYbn#x#I#x#M#D#M#D.s#D#s#D.s#Dbl#s#s#MbfavaCbgaCaoaC.5ao.5#vaOaOam.8.8amavb#b#aoaC#xaw.N.N#s.s.NaYaw#xbnbnaCa0a0a0amamaoaFaFaFa#.yan#u.G.6aBaBbmaO.5b#.5b#amaoa0a0amaCa0a0aY#xbn#Ibn#Ibn#IblawaYaY#M.Nbl.N.n.7a9.7a9.7afa9.7aj.7#L#L#L#L.7#Laf#La9a9#D.7#D#s#DaYaY.NaY#x#xbn#x#x#U#xaYawaYa9a9a9bl.NaY#x#x#xaYaYbl#Da9.7a9", +"#L#L#L#L.7#L#L#L#La2#L#L#ga2#g#L#ga2a2a2#ga2#L#L#L.7#Laf.E.7.7#DawaY#I.CaoaBazbaaSa#.VbnawaYaY.N#pa9afa9a9#Laja9af#Lafafajaf#Lafa9#pa9blblbl#MaYaYaYaw.R#x#UaYbnaw#x.R#I.R#I#x#xaYaw.NaYaw.N.N.s#D.s.saw#I.CaoaoaO.F#vaOaO.8#vbc#va#aO#vaO.5.8aCaFaO#SaOaOao#I#x#MaYawbnbnaCa0b#a##va#a##vaZaZ#uazazbh.Galay.2alaFaOaFamaCa0aC.C#I#x#x#I#x#xaY#IaY#I#x#I#x#x#I#xbl#D#M#D#D#s#D#D.n.7.n.7.n.7.7.Eaf#L#L#L.7aj#L#Lajaf#La9.7a9a9.7bl#DaY.NaYaY#x#xaCa0#x#xbnawaY#D#Da9#D#DawaY#x#I#xaYaY#D#Da9a9a9", +".7#L.Eaf#L#Laj#L#L#L#g#L#g#L#g#g.ja2a2#ga2bp#L#L#Laf#L.7.7a9.7#Dblaw#x.W.5az#aalaZb#a0bnaYaY#DaY#p#Da9afa9a9#L#Laja9aja9#La9aja9.na9#sbl.n.NblaYaw.R#xawbnaY#U#U#x.R#Ibn#I#x#I#xawaYaY.saY.s.N.N.s.saw.W.Waobc.yaBaB#u#S.y.y#va#aB#u.Qaz.waBaZ.yaZaB.0aBaB#vaO.5bn.Vb#am#Sa#aB#u.wbhazazbh.waz.GarazaSaz#a#a#a#ea0a0#Ubn#x#I#x#xaY#MaYblblawbl.NblaYaYaY#U#IaYaY#D#M#D#s#D#D.n#D.7a9.7a9.7a9.7a9#L#L.7af#L.7af.7af#L#L.na9a9bja9#D#D#DawaYbfaw#xbna0#x#UaYaYaYbl.n#Dbl#DaY.N#xaY#xaYaY#D#Da9a9.7", +"#L#L#L#L.7#L#L#L#g#ga2#g#g#ga2bpa2#ga2a2#ga2#L#L.7#Laja9#La9#sa9.NaYaY.Wambk#zaraFamambnaYblaYbl#Dbla9a9.7a9.7a9a9.7a9a9.na9a9a9#Da9bl#DblawaY.N.RaYbnbnbn#Ubnbn#I#U#x#x#x#I#x#Ibl.Naw.NaYbf#I#x.s#x.WamaO.y#uazal.U#z.U#T.G.GaP#Tal#z.U#3al.Ualal#T.G#T.G#e.w.wa7#ua7a7aS.G#e#TaS.w.wanaz.wazaS#vaOa##va#aFaFam#UaY#xaYaY.NaY.s#D#D#D#s#D#D#D#s#D#saY.saY.NaY#sbl#D#M#D#D#Dbj#D.n#L.E#L.E#L#L#L.E#L#Laj#L#L#L#L#Laf#La9.7#Da9#D#D#DblbfaY.N#xaY.C#I#x#xaYaYaY#Dbl#D#D#Dblaw.NaYaYaYaY#D#pa9#La9", +"#L#L.7aj#L#L#L#L#g#L#gbpa2bpa2#ga2asa2#g#La2#L#L#L#L#La9.7.7#D#sbl.N#Ia0#vaz#z#eam.Va0bnaYaYaYaY#Dbl#D#Da9a9.7.7a9a9a9.7#Da9#sa9bl#sbl.sbl.NblawaYbn#Ubn#Ibn.C#Ubn#x#U#x#I#x#IbfaYaw.NaY.N.saYboaYaCam.y#u#aau#4aH.4#..4aHbrbw#0.2bw.2aT.2ay.YaH#4#zal.o#T#Tal.U#aar.G.Ga4aPa4a4.ya#aZ.ya#a#a#aOa0bnaCbnaCbn#I#xblaYaY.s#D#sa9#Da9.na9a9a9.na9a9#D#D#D#D#s#D#s#D#D#s#D#D.n.7.E.7.n.7#La9#La9.E#Laf#La9#L.7#L.7afaj#L#La9a9.n#D.7bl#D#DaY.NaY#x#xbn#x.R#xaYaYaY#DaY#Dbl#D#D#DaYaYaYaYaY#D#Da9a9a9", +"#L#Laf#L#L#L#L#La2#ga2#g#ga2#g#La2a2#ga2#ga2#L#L#L.E#L.7.n.7a9#D#D#I#xaoby.w#zaSa0aCa0bn#x.Rblblbl#D#D#D#D.7a9.Ea9.7a9a9.n.7a9a9#sbl#DblaYaw#x#x#xa0#xa0a0a0aCa0#I#U#x#I#x#I#xawaY#x#I.Nawbf#x#IaCbgaBaza6aT#P.uaybaay#3#aar.Gazaz.Gazaz.Gar#aa6.w#u#uaBaZaB#uazazazaS.0#S.0aFa#am.5aoa0am.Wam.C#I#x#x#I#x#I#xaw.N.N#s.N.N#Dbj#s#D#D.7.7.7#D#s.7a9.Ea9a9a9a9a9a9#s#p.na9bj#Dbjbj#Lajafaj#L#L#Laf.E#L#L#L#Laj#L#Laf#Laf.7a9bja9#D#D#DawaY#x.s#xaY#x#x#x#IaYaYawaYbl#D#D#DblaY#s#DaYaYaw#D#Daf.7af", +"#L.7#L#L#L#L#L#L#L#gbpa2bp#g#L#La2#ga2a2#g#L#L#L#L#L.7a9#L.7#D#saY#x.C.8#va7albh.Ca0a0bnaY.RblblaY#Dbla9#Da9.7.7a9a9a9a9a9#D.n#Dbl#Dblaw#DaY#x#IbnbnaCa0#Ua0aCa0.CaC#x#I#x#I#Ibf#x#I#x#I#x#Ibo.C.paOa7#aay.K.K.K#Ear.faZa7#uaBaB#vbmaBaZa7an.TaZaOaF.FaFaOb#b##SaZ#va#aOama0.W#xavam.C.W.C#xaw#x#x#Ibfbf#xbf.N.N.saYaY#D.N.E#D.7a9#D#s.7#s#D#D#sa9.7a9.7.E.7.Ea9#s#D#s#D#s#D.Ea9.Eaf.E#Lajafaj#L.7#L.n.7#La9#L.E#Laf#L.na9#D.7a9#Dbl.NaY.NaY#x#x#x#U#x.RaYaYaYaY.N#xbl#D#D#D#DblaYaYaYbl#Da9a9.7", +"#L.3a2a2a2a2asa2#ga2a2#ga2a2#ga2#ga2#ga2a2#ga2#L#L#Laj#L#L.7b..7#x#I#x#xaC#uar#e#Sa0.CaYaY#DaYaYa9#p#pa9a9a9a9a9#s#D#sbj#D#D#D#D#saYaY.Naw#x#x.Ca0aoa0a0aCbn#Ibnaw#U#U.CaCamaCaCaw#Mbn#UbnaCbgaoaZanaral.2alaPan.y.0.yaB.0a#a#a#.8aF#v.0#u.0#v.5aCam.8amaOamaoam.F.tbg#x.C.C#xaY.NaY.saY.Nawbf.N.N.N#D.s#D.N#D.Nbl#sbl#s#D#D#D.7.Ea9.7a9.7a9.7.7a9#s#D#D#Da9#D#D.na9.na9.na9a9.na9a9a9.naf#Lafaf.E#L.7#L#L#L#L#Lafaj#L#L#La9.na9bl#MblaYaY.baYaYbl#Dbl#DaYawaYaY#M#D#DaY#Dbl#D#DaYblbl#D#p#Dafa9", +"afa2#La2a2#gaa#ga2a2bpa2#L#g#L#ga2a2#g#L#g#La2#g#L#L#Lbpaj#D.7bjaY.N.N#Iao#u#aayaFa0bnaYaYblaYaY#pa9a9blbl#D#M#D#Da9#Da9#Da9#s#Dbl#D#MaY#x#x#x.Wama0a0aCa0a0amao#Uaobg.8am.8amama0bgb#.8aFa#.0aZ#ua7#uaS#uanaBa#.8aFaOamaOamaCamb#ao.5a#.0#vaF.5a0a0aC.Ca0.Wa0am#ybgaC#xbf#I.NawaY.NaY.saY.NaYaw#D.s.N.N.N.s.N.sbl#sbl#D#D#D.n#D.7a9.7.n.7.n.7.n#D#D#s#D#s#Da9#Daja9a9.nafa9aja9aja9aja9af#L.n#L.7af.Eaf.E#L.7#Laf#Lafaf#La9.7a9blblblawaYaY.baY#Mbl#DaYaYaYaYaY.NaY#Dbl#s#Dbl#D#MaYa9bl#D#Da9a9", +"afaf#La2a2a2#ga2#ga2a2#ga2a2#ga2bpa2a2#ga2#ga2#g#L#g#L#L#Lbj.Ebjaw#D.s#xaoana6abaOam#xaYaY#DaY.N#pa9#p#sbl#Dbl#D.n#D.na9.na9a9a9#sbl#DaY#I#x.Wbnb#bgb#amamao.8aFamaO.yaZ#u#u#S#vaZan.yaZaZ.6aSa4aBaZbma#aF.5ama0aCa0.CaCa0a0a0.Wbna0a0aoam.5aoa0#I#x#xbn#I#x#x#x.p.Vbn#x#I.NaYbl.N.NaY.N.NaY.N.NaYaY#DawblaY#DaYblaYblawaY.s#D#D.na9a9a9a9a9a9a9a9#D#D#Da9a9bja9a9.nafa9.Ea9a9.na9.na9.n#Lajaf#L.n#L.7#L#L#Laj#Lajaf#L#Laja9a9a9blblblaYaYaYaYaYbl#D#MblaYaYaYaYbl#saY#D#D#D.NaYblaYbl#D#p#Dafa9", +"afajaf#La2a2a2a2a2#g#L#g#L#g#La2#ga2bpa2#La2bpa2aj#Lbp#Lajbj.7#s#D#Daw.C#v.GaTaD#vb#a0bnawaYaYaYaYblaYaYaYawaYaw#D#D#D#D#D#D#s#Dbl#saYaw#xa0a0a0bgamaOamaOa#a#a#.yan#u.G.Gaz.w.w#u#uan#uan.w.6.GaFaOaFaoaobn#I#x#I#x#I#x#x#I#xaY#x#I#xbn.CaC.Ca0#x#x#IaY#xawaYaw.R.bbnawblaYaw#DaY.saY.Naw.N#M.N#D#s#DaY.N.saY.NawaYaw#Dbl#DaYaY#D#s#D#s#D#s#Db.a9#D#s#D#s#D.n#Daf#L.na9aja9aja9afa9aja9afaf.7af.7#La9aj.7a9#L.7afaj#Laf#La9a9a9.na9blblaYawaYaYblbl#Dbl.saYaYawblaY#D#Dbl#DblblaYblbl#Dbl#Da9a9", +"a9a9#L#L#L#L.jbpa2a2aja2#ga2#ga2#L#ga2#ga2#ga2#L#g#L#L#L#Lbj#s#D#saw#Iaq.y#3aH#Pa#bga0#UaYaY#xaYaYawaYaYaY#x.N#x.Naw.Naw.N.NaY.s#DblawbnaCamb#bgaFbma##S.0aB#u.yaz.w.waz.w#u.0a##SaFbma##Sa##Sa#amamaoa0#x#IaYawaYblawaYawaY#M.NaYaYawaY#I#x#x#U#x#x#xawaYaY#D#MaY#x.b#x#UaYaY#Daw#DaY#D#D#D#D#Dbl#Dbl#sblblbl#MaY.RaYaYawaY.s.Nbl#Dbl#D#Dbl#Dbl#D#s#D#D#D.7#D#Dajaf#La9.na9a9.na9.na9a9.n#Lajaf.E#L.7#La9aj.7#Lafaf#Laf#La9.Ea9a9#p.nblblaYaYaY#Dblbl.NblaYaYaY.Nbl#D#D#D#DaY#DaYblblbla9#Dafa9", +"a9afa9ajafbpa2#L#ga2bpa2#L#g#La2bpa2a2bpa2#L#ga2#L#Lbp.7aj.7#Db.bl#x.Waobb.2a6ak#vb#a0#x.RaY#xaYaYaY.R#x#x#x#I#xawaYaYaYaY#xaw#xaYaw.Ca0b#aF#vaZaZana7.waz.G.Ga7#uaBaB.0a#aFamambnbnaCa0a0aCa0a0aoa0#IaYaw.Nbl.NaY#MaYbl#DblaY#DawaY.Nblbl#xbn.Ca0#I#xaY.N#Mbl#DawaY#Ibn#Ubn#I#x#D#D#D#D#D#D#s#D#D#saY#Dbl.s#DaYblaYaYawaYaYaYblbl.nbl.nbl.nbl.n#D#D#D#s#D#D#s#D#Lafaja9#paja9aja9af.naf.naf#Laf.7aja9aj.7#Laf.7afajaf#Laja9a9a9afa9#Dbl#sbl.Nblbl#sblaYaYaYaYaY#DaYaY#Dbl#DaYblaY#MaY#Dbl#Da9a9", +"a9a9afa9#L#L#La2#ga2#La2#ga2a2#ga2#ga2a2#ga2a2bp#L.j#L#L.7#sbj#saY#Iaq.y.waXaraS#vb#a0#UaYaYawaYaYaYbn#x#U.Cbn.Caqaqavaqavaqaqaq#Ia0ao.5#vana7bh.Ga6al#aarbkaz#uaOamam.Cao#x#IaY#I#x#I#x#I#x#xawbn#xaw#D#D#D.sbfaY.N.saY.saY#D#D.Naw.N#saY.s.Cava0am.C#IaYaY#D#M.N#x.bbnaCa0a0#x#s#D#s#D#Da9#Da9blblbl#Mblblbl#MaYawblaYaYawaY.saYaYaYaYblblblbl#s#D#D#D#D#s#D#Daja9af.nafa9.na9.na9a9.na9#Lajaf.7af.7#L.n#L.E#Laf#L#Laf#La9a9.7a9a9a9a9#D#D#M#Dbl#Dblaw#DaYawaYaY#saYbl.Naw#DaYawblaYblbla9a9af", +"afa9.7a9#L#L#L#L#La2#g#La2bpa2bpa2#L#g#L#g#L#ga2#Lbp#Laj.7bj.s#D.Waoao.waX#aazaSaFa0#xaYaYaYaYaYaYaY#xa0a0.Caoa0.8.8.5ao.5amaoamaCaoam#v#ubh.G#eayaTay.Gaza7aBa#aoaC.CaC.CaYaY#Mbf#x#xaY#xawaYaY.NaYaw#D#s.N#xaNaw.Nbl.Nbl.N.N#s#x.NaY#D.NaY#xaqa0aoa0#x.NaY#MaY#x#xbnbn.Vamaoam#D#D#D#s#D#sbja9.N#M.Nbl.N#M.NblblaY.RawaYaYaYaYblawblaYawaYawaY#D#s#D#M#D#D#D#Daf#L#La9a9.naf#La9af.n#L.nafafa9aj.7aj.7#L.7#L.Eafaj#Laf#La9a9a9aja9a9.na9bl#D#D#DblblaYaYaYaYaYaY#DaY#DaYblbl#DaYaYbl#sbl#Da9a9", +".7a9a9.7a9a9.7a9#L#L#L#L#L#L#L#L#L#L#L#L#L#L#L#L#Lafa9a9#D#sbl.s.Waoan.G#Ea7aBaZ#vaFama0aCamamamb#.Va0aC.VaO.0#uaSaSazazan.Gak#a.Iay.Iar.Xar.Gazaz#uaB.yaO.5aoa0#Iaw.NaY.saY.N.N#D#s#D.N.N.N.N.s.NaY.NaY.NaY.saYa9bl#sbl#sbl.nbl#D#s#DawaY.saYawaY#x#U.CaC#xbf.N.s#I#x#Ia0aoamambf#I.N#D#DaYaY#Dbl#D#Dbl#D#Dbl#D#M#Dbl#Daw#D#M#DaYaYawaYblblaY#D.na9a9.na9.najaf.nafajaj#L#L#Laj#L.E#L.n#L.E#Lajaf#Laja9aja9.7a9#Lafafaj#L#Lajafa9a9a9bja9#D#D#sblaY#MaYaYaYaYaYaYaYawaYaYaY#xaY#UaYaYbl#Dafa9#L", +"a9bja9a9.7a9a9.7#L#L#L#L#L#L#L#L.E#L#L#L#L#L#L.7aj#L#sa9#saY.saYbo.5.w.GazaB#San.l#vbgama0#xama0ama0a0bgaFbmanazak#aar#eazaz#aa6.e.e.XaraSazbhan#S#v#vaFaoa0aC.Cawaw.Naw.Naw.Naw#Da9#s#D.s.N.s.N.NaY.s.Naw.NaY.Nbl#saYblbl#Dbl#D#D#DaY#D.NaY.N#x#Ibna0a0a0.C#I#x#x#I#xaCamaFaOamaYaYaYaY.N.Nawbl#s#Dbl#D#sbl#D#Dbl#Daw#Dbl#Dbl#D#Mblblblaw#Dawbl.na9.na9.na9a9.naf.n#L.7aj#Laj#Laja9aj.7aja9aj.7#L.Eaf.7#L.7af.7afaj#L#Laf#Laf#La9.7a9a9b.a9#D#DaYblaYaYblaYaYaw.RaYbnaY#U#xbnbna0aYaYaYbl#Da9a9", +"a9a9a9a9a9a9a9a9#L#L#L#L#L#Laf#Laf#Laf#L#Laf#Lafa9a9a9#D#D.Naw.N#x.8.w#e.lbma#az#uaZaFa0aC#x#x#x#x.WamamaF.y#ealayaG.G#eanaS#e#a.I#a.X.JanaZ#Sa#aOambga0.W#x#x.saY#saY.NaY.NaY.N#D#D#DaY.NaYaY#xawaYaYaYaYaY.saY#Dbl.N#M.Nawbl#D#M#D#MaYawaY#x#xbnaCam.8.5amamaCa0a0aob#aOaObm#v#x#I#x#xaY.N.NaY#Dbl#Dbl#D#Dbl#D#Dbl#Dbl#Dbl.sbl.N#Daw.NblaYblaYa9.n#p#sbl#Ma9bl.na9.na9.7.E.7.7.na9.na9a9.Ea9.n.7aja9.na9.Ea9.7af.7af#Laf#L#Lafa9a9a9#Da9#D#D#DblaYblaYawaYaY.R#xawaYaYaYbn.Cbn#xaYaYaY#D#D#D#D", +"a9a9a9a9a9.7a9a9a9a9a9#Laf#L#L#La9.7.na9a9a9a9a9a9a9#s#D#s#D.Nbl#I#v.G.G#uaF#van#uaZ.8a0bnbnawbnavam.5#van#ealbra6#a#e.wana7#e#e.fakaz.TaBa#a#aFa0aoa0.Wbn.s#M.N#saY.sbl.saY.saY#s.Naw.Naw.N#I.N#x#I#x#x#IaYaY#IaYawaYawaYaY#xawaYaYaY.NaY#x#x#Iamb#aFa#a#aOamamamaob#b#aF#Sbmbmaoa0#x#xawbl#D#D#Dbl#D#sbl#Dbl#sbl#D#D#sbl#D#D#D#Mbl#DawblaY#saY#Mbl#Dbl#M#D#M#M#Da9#sa9.n#D#D#sa9.Ea9b..na9.7a9.na9.n.7.7a9.7a9aj#Lafaj#Lafaj#La9.Ea9.7#D.E#D#DblaY#MaYaYaYaYaYaY.R#x.R#xbn#U#xbnbnaYaYbl#Dbl#D", +"a9a9a9a9afa9afa9af.nafaf#Lafa9a9afa9a9a9a9.na9.n#D#D#D#D#D#Daw.N#I.y.GazaZb#aOa#anaBa#aoa0aCbna0a0.5.8an.G.2.K#P#q#e.6anan.wazakazbha7aZaFam.8am#xaC.C#I#IaY#D#saY#saY.NaY.NaY.NblaYblaYaY#I#x#x#x#x#I#x#x#x#xaYaYbn#xbn#U#x.baY#x.s#x#x#I.Ca0.CbgaF#vbma#a#aOambgamb#aoaFaFaOaF#va0#x#I#x.Na9#D#s#Dbl#D#Dbl#D#Dbl#Dbl#D#Dbl#Dbl#DaYblaY#Dawbl#DaYaY#MaYawaYawaY.nbl#p#sa9#sa9#D#s#D#Da9#D.n#D.na9.na9a9.n#Da9#D#Lajaf#Laf#Laf#La9a9a9#Da9#Da9#DaYblaYaYblaYawbnawaYaYaYaYbn.Cbna0.Cbn#xaYaY#Da9", +"#pa9a9a9a9a9a9a9a9a9a9a9a9a9a9.na9a9a9a9a9a9#Da9#D#s#D#s#DaY.NaYaCaZ.6az.0aOaF#van#uan#vamamamamaOa#analba.g#P#P#a#Tan.y#uaZaza7an.laZa#bgama0.C#U.C#U#I.N#s#s#D#s.Naw.N#M.NaY.saYaw.Naw#x#x#x#U#x.baYbnaw#xawaY#Ubn#U#x#Ubn#xbn#xbn#Ia0a0a0aCa0b#.t.tbma#aFaFb#amamamam.Vb#b#.V#Sbga0#x#xbl#D#Dbl#Dbl#Dbl#s#Dbl#D#M#D#Dbl#sbl#Dblaw#DawblaY#DaYawaYaYaY#Ibn#Ibn#Mbl#s#D#D#Db.#D#sa9#s#s#s#D#s#D.n#D.na9#D#D#s#Dafafaf#L#Laf#L#La9a9.7.nbja9bj#DblawblaYaYaYaYaYaYaY#x.R#x#xbnbnbnawaYaYbl#Da9a9", +"a9a9#pa9#pa9#pa9a9a9a9a9a9a9#pa9a9.n#p.nbl.n#pa9#D#D#D#D#D.Nawbfbn#vazaS#SaF.8#vaZ.6aBa##va##v.0a7.faG#PaD#V.Kay.XazanaB.0#vbm#SbmaZ#vamama0aC#xa0.W#x#x#I.N#D#s.N#M.NaY.NaY.saYaYaYaYaYawbn#x#x#x#xbn#Ibn#x#x#xbn#xa0bna0bnaCbn#xa0#x#xbn.Ca0am.V.Vb#aOaFb#bgamaC.C.CaCa0a0aCa0a#aFbgbnaY.N#D.7#D#M#D#Dbl#Dbl#D#D#Dbl#D#Dbl#D#D#M.NblaY#DawblaYaY#Ibn#Ibn#Ubn#IaYawaYawaYawaY.s#D#s#Da9#sa9#s#D#sa9#Dbl#s#D#D#Daj#L#Lafaj#Lafaja9a9a9#Da9#D#Da9blaYblaYawaY.R#xaY#M.RaYawbna0#IaYbl#Da9a9afafa2", +"#pafa9afa9a9a9a9#pa9#pa9afa9a9a9#p#p#D#pbl#p.na9#D#D#D#DaY.NaY#Ia0#v.Gaz.0#vaF#vanaz.w#u.0#u.waP#A.f.Xa6.Ia6akaSanaZa#aFaoaFaOaF#SaFaFama0aC#x#x.Wa0.W#Ibf.N#sbj#M.N.saY#s.NaY.NaYaYaw#xaY#x#I#x.R#x#x#x#xaYbnaY.Cbnbn#xbn#x#xbn#x#I#xbn#xa0.Ca0.pb#b#aFb#aFb#.V.C.C#x.CaCa0#xa0.FaFaOa0aYbl#D#sbl#D#Dbl#Dbl#s#Dbl#D#M#Dbl#D#M.Nbl#DaYblawaY.saY#UaYbn#x#U#x#Ubnaw.Rawblaw.NawaY#s#s#s#s#D#s#D#sbl#Mbl.n#Dblbl#Dafaj#Laf#Laf#L#La9.7a9.7#s.7#DbjblaYblaYaYaYaYaYblaY#xaY#x#xbnaYbla9#p#p.naf#La2", +"#L#La9a9a9afa9af.j#L#La2af#La9a9#sa9#s#D#DaYaYblawaYaY#I#xbn.Ca0#Ubg.laz#uaBanaBa6#a.Xa6#aak#ebh#Sbm.Fa#aFb#amaoa0aCa0aoa0amb#.8b#aoa0aCa0#xaC#x#I#xaY.N#M#D#D#s#D#sa9.7a9.7.n.7#D#D#D#s#DaYaYaY#sbl#Mbl#Dbl#D#Dawbl.Naw.NaYaYawaYaYaYaw#DaYbl#DaY.RaYaYbnbna0a0#Ubnbn#x#x#x#I#xa0bgaBb#a0.s.s#L.NaY.N.saY.N.NaYbl.NblaY#I#x#x#x#Mbl#MaYaY#x.b#x#xbn.Wambgamamam#Ua0bnaCa0a0amaoaw#x#x#x#I#Iaw#Mblbl#sblbl#D#D#Da9#pa9a9a9a9#Laf.na9a9a9a9#paf#pa9a9#MaYaY#x#xbnaw.RaYbna0a0a0aY#D#pa9a9#La9#L#L", +"#L.7#Laf.7a9.7a9#Laf#Laf#La9.7#Da9a9blbl.Nbl#DaY#xaYaY#xaCa0amam.t#uazar#e#T#a#zacbaayaraS#uaZa#aFaFaFb#amaoama0a0a0aCa0a0ama0amaoa0a0a0aC#xaC#xbn#I.saY.s#D#sa9a9#sa9a9.Ea9.7a9#D#s#DaY#D#D#s.Nbl#D#D#D#D#Dbl#DaY#DaY#Dblbl#DaY#D#Dbl#DaYbl.NaY.baYaYaYa0#Ia0a0#x#UaY#x#U#x#xaYbnam.FaOa0#x.s.7aY.saY.NaY.NaY.sblawaY.N#x#Ibn#xaYawaY#xawbnaY#U#x#IaCa0aCbg.paobn#U#Ua0aCaCaCb#aCaC.C.Wa0.C.baYawawaYblaw#D.s.Nbla9#p.nafa9ajafa9#pa9#pafa9a9a9#pa9blaYaY.b#xaYaYawa0#xa0a0#UaYbla9a9a9a9#L.7#L", +"#Laf#La9.7af.7af#L#Laja9.7a9a9bj#D#D#D#MaY.NaYaY#MaY#Ua0amam.5.5aSal#PabbrayaTaTaGara7aZaZaZbm#vb#amamaCa0#x.C#x#I#x#x.CaC.CaC.5b#aob#aCamaC#xbn#I#xaY.s#D#sa9#s#Da9.Ea9.7a9.Ea9#D#D#D#D#s#D#D#D#Dbl#D#M#Dbl#sbl#DaYblaY.saY#DaY#MaY.Nbl.sbl#D#DaYaY.baYaYbn.CbnbnaYaYbn#x#x#x#xaYbnam#Sama0.N#s.NaY.Naw.Naw.NaY.NblaYaw#x#x#x#IaYaYawbl#x#I#xa0#Ia0aC.pbgb#bgb#.pa0.V.pb#.Vb#bgbm.taOaFaFao#U#x.bbn#IaYaYaY.NaYbl#Dbl#Da9a9a9a9a9a9a9a9a9a9.na9a9a9bl#DblaY#x#xaY.R#xaCama0#x#xbl#s#Daf.7af.7#L", +"#L#L.7a9.7a9a9.7af#La9a9a9#D#D#D#D#MaYaY.N#x#I#x#xaY#x#xamaO.0bbaT#PaD#VaTaRar#eaBaZbmaFaFamb#ama0aCama0.C.C#x#I#xaY#I#x#x.W.CaCaOaFaob#aoamaC.C#I.b.NaY#s#Da9.7.n.7a9.7.n.7a9.7#D#D#D#D#D#D#D#D#D#M#D#Dbl#D#Dbl#D#D#sbl#Dbl#D#D#D#D#Dbl#D#Dbl#DaYaYaYbn#x#x#x#IaYbnaY#IaY#xaY#IaYbna0aBbmao#x.NaY.saY.NaY.NaY.saYaw.NaY#x#I#x#xaw#x.N#I.C.CavaCaFaOa#aBa##vbm#Sbm.taFbmbmaZaBbh#kbhbhaZ#Sa#b#a0aCa0a0#U#xaYaw.Nbl#Mbl.n#D.n.7a9a9.na9a9#sa9#Da9a9a9.n#D#D#xaY#xawaYbnama0ambnaYblbl#Da9#Da9#L.7", +"a9a9a9afa9#La9a9.na9a9bj.n#D#D#saY.NaY#x#x#x#x#x#Ubnambga#.0#u#uaH#4#aazanaBaZbm#SaFaOb#bgamamama0.C.C.W.C#Ibf#xbf#I#x#x.C.Cao.8a#aOaOamaoa0.Wa0aY#xaw.N#D#s.7a9.7.n.7a9.7#L.7aj#D#D#s#D#D#D#s#D#D#Dbl#D#Dbl#D#Dbl#D#D#Dbl#D#Dbl#D#Dbl#D#D#D#DblaY.NaYawaY#xbn#xaYaYaYbn#x#x#x#x#U#xamaBaBaBa0.Caw#xaY#IaY#xaY#x#x#x#Ibn#xa0.Wa0.CaoamamaCamao.5azaz.G.Gar#e.G#a#eaz#ear#e#a.X#a#jaGak.faSaZ#vb#ambga0a0a0#I#x#xaw#xblaY#Da9#Da9#D#D#Da9#Da9#Da9.na9a9#D#DblaY#x.Rbna0.Cama0#x#xbl#Dbla9#D.7.7a9", +"a9.7a9.7a9.na9.7a9.7#s#D#D#D#D.N#x#x#x#I#x#x.Ca0amaOa#.yanaBan#u.6aBa#amb#a0b#amamb#amamamaoa0aoa0aCambn.C.C#x#Ia0.C.CaCamao.5aO#vaFaOb#aoa0a0.WaYaw.NaY#s#D.7.n.7a9.7.n.7a9.7a9#D#D#D#D#D#D#D#Dbl#D#Dbl#D#Dbl#D#D#Dbl#D#D#D#D#Dbl#D#D#D#Dbl#D#D#sbl#D.NaYaYaY#xaYaYaY#xaYaYaY#xaYa0a0bmaz#uaOam.C.W.C.C.C.C.W#x.W#xamamamaoam.5aoaF#v.y.0#uaB.wal.2ayal.2aya6aTa6alaR.2ayayaT#P#t.K.e.X.GaSaZaBaFb#amaoa0a0bna0aYaYawblbl#sa9bj.n.7#D.7a9bja9#Dafa9afa9bl.Naw.N#U.CaCaFaoamama0aYaY#D#D#Da9#L.7", +"a9a9.na9.7a9a9a9a9#D#D.N#s#DaY.saY#x.C.Ca0aoamao.0aZaBaZaB.0aBa#amb#a0aCaC.pa0a0aob#ama0am.C.Ca0.5b#amaCam.W.C.CaCa0ao.5amaOaF#vaF.8amamama0aqa0aYaw.Naw#D#Da9.7.n.7a9.7.7af.E#L#Da9#Da9#Da9#Da9#Da9#Da9#Da9#Da9a9a9afa9afa9afa9a9a9a9a9a9a9a9a9bl#D#Dbl.N.NaYaYaY.RawbnaY#x#I#xawa0b##Sazbha##vamaqao.Cavamao.5ao.5.8.8aF#v.0.yaZaB.waza7az.G.G#aararar.X#a.Xar#eazazaralalalayayaya6.Ial.XaSaS#va#aFaO.5aC.CaC#xbnaY.N#M#D#D#D.7a9.7.Ea9.7.7.Eaf#La9#D#D.N.NaYbnbnamamb#aoama0aYawblaY#D#D#D.7", +".7a9.7a9a9a9.Ea9bja9#s.NaYaw.NaYa0.Wa0aCamamao.5a7az.waZa#aFaFaFamamaC#xbn#xam.5amamamaoama0aoa0aOaFaoambgamaCam.8aFaOaFaOaFaF#vaFaFaOb#aoamaCamawaY.Naw#D#D.Ea9.7a9.7.n.7.7a9.7#D#D#D#D#D#D#D#D#D#Dbl#D#Mbl#D#Ma9a9a9a9a9a9a9a9.na9a9.na9a9.na9#D#D#D#DblaY.saYaYaYaY#xaY#xaY#xaYbnaObmazaZ#Sa#.8.8.8.5am.8.5.8a##va#.ybbbb.w#uazarar#a#eazaSaz#ua7aZaZaZaZ.Tbm#SbmbmaZan#uaSaz#aalaR.2.IaGaraSaZaBa#aFaoama0aC.R#IawaYbl#D#D#Da9.7.7a9.7.7a9.7af#L.na9#D#s.N.NaYaCamaoaFamama0aYaYaY#D#D#Dbj#D", +".N.N.N.N#D#D#D#DawaY.Nbf#xaqaqavamamaF#v.0#u.w#e#va#b#.5amamamaF#I#x#x#x#Ia0#x#x#x#I#x#xa0ao.5amamaoaFa#a#aBaZaZ.TaBaZ#SaFaFaF.5ao.5aoam.C.W#x#xaYaY.saY.N#s#D#Dajafaja9a9a9.7a9#Da9bja9#D.7#Da9#Dbl#Dbl#D#Dbl#D#Da9.7a9.7a9a9bja9#Da9#D#D#Dbl.Nbl#Dbl#D#D#Dbl.NaYaYaYaYaYawaYaY.Nbfa0b#bmaBana#bma#bm#u.6#T.oaR.Gararal#aalalal#Taraz.6#uan.0.0b#.8b#aob#aoambgamam.8aoamaO.8aFaBbhaz.Gar.X.X#abhazan.TaZbmbma#aCa0#xaYbfaY#s#D.s.N#D#D#sa9.7.7#s.7.7.7a9a9#D.7#DaYam.5aOa#amambf.N.N#s#D.NaYbf", +"aYaYaY.saY#s#D#D#D.s#x.Wao.8aq.5.yaB#uanaBan#uanaFaOamaob#aoamaobn#x#U.Ca0.C.C.Wbna0a0aoaF.5#va#.ya#.yaBaZaBbh#u#SaBaZaOa#.8aFbg.5aoamaobn.Cbn#x.sbl.NaY#D#Da9#Daf#L#La9.7a9a9.7#D#D#D#D#D#D#D#Dbl#Dbl#DaY#DaY#D#Da9a9.7a9#D.7a9a9a9a9#Dbl#D#D#D#D#D#D#D#D#D#D#DaYaYaYaYaYaYaYaY.N#x#xbgaFaZ#ua#bgaF#vanaz#ealalazazaz.Garaz#q#ebhananaZaZa#a#a#aCama0a0aoa0ama0aqaoamamaFaoam.8a##SaZ#uana7aSbhaBaZaZbmaOaFaOaFb#ambnbn#IaY.NaY#D#D#D#D.7.7b..7#D#Da9.7#s#D.n#D#MaY#Iama#aFaoa0#x.saY#D#Dbl.N#x", +".Nbo.N.N#xbf#xbf#x#Ia0a0aOa#aBaz.GaP.wan.ya#a#a#aCamambgama0a0a0.Wa0.C#xa0a0a0amamaoaFama#a#.0#vaSazbh#uanaBanaZa#aOaFaO.5aOaqamaoama0.C.C#Ibn#IaYaYaw#D#s#D.E.7#Laf#La9a9.7a9a9.7a9.7a9.7a9.7a9#D#D#D#D#Dbl#D#Da9.7#Da9.7a9.7#Da9.na9a9#D#Dbl#Dbl#Dbl#Dbl#D#D#p#D#D#D#D#D#D#D#D.N#DaYa0b##SaBaZamamaF#v.0#u.6.wan#u#uaSananaZaBa##vaFaFaoamamama0a0aCa0bna0#xaCa0a0.Cao.CaoamaoaF.5aOaFaFa#aFaFaF.5aoamaFamaFaob#bga0aobnbn#x#x#M#Dbl#s#Da9.7a9.s#D#D#D.N#DaY.N#Daw#xa0aoaF.5b##IaYaY#DawaYaw#x", +".N.N#Ibf#x.W.C.W.5#v.yaZ.G#z.Kba.o#e.w.0a#a##va#amamaOaFaOaFbgamama0amaoam.8.5.5a#aFaFa#aBan#ubh#a.Xar.Gbh#uaZaBaO.5aoamamaC.C.Wa0a0.W.C#I#x#x#xaY#saY#D#D.7af.7af#L#La9a9.7#D.7#Da9.7a9.7a9bja9a9a9a9a9a9a9a9afa9.7a9.7#L.7a9afa9a9a9a9a9#Da9#D#Dbl#D#D#D#p#D#D#D#D#Dbl#Dbl#Dbl.s.NaY#xa0a#aB.0amamamaFa#a#a#a#aBaZaZaZ#va#.0a#b#b#bgamambn.Cbn.Wa0.C.C.C.Wa0.C.C.C.Wa0.Ca0.Ca0aoamama0a0bn#Ubn.Wa0.Ca0.W.C#U#xb#.Vb#b#a0ama0a0aYaY#D#D#D#s#D#saYaY.s.NaYaw.NawaYaY#Ia0amamaOam.C#x#xaYaw#x#x.C", +".C.W.Caqaq.5.5.5anaP.o.Ya8#obs.g#TaS.wan.0#va##v.0bm.0a#.0a#a#.yamaoaFamaOa#aOa##va##S.0aZ#uaSaz#aaG#a.Gaz#uan#u#vaOam.8aCaq.W.C.C.Wa0#x#x#x#IaYawbl#D#sa9a9#L#Lajaf#L.na9a9.7a9.7a9#D.7#Da9.7a9a9a9af.7afa9.7a9.7af#L#Laf#La9.7afafa9.na9a9bl#Da9.na9a9a9a9a9afa9.na9a9.7a9a9a9.N#D.N#M#xaOaZaBamaOam.8am.8a#.5a##va#aoaFaFamamaoa0a0bnaC#x#x#x#x#I#xaY#xaY#xaY#I#x#x#x#I#x#I#xa0bn#I#xawbl.Nbl.Naw.NaY.NaY#xaYaCa0ao.Vbgb#b#b#awbnaYaYblblaYbl.NawblaY.NaYaYaYawaY#x#Ia0bga#aOamaC.C#xa0.Wa0am", +"aoaFa#aOa##v.y.ya4.2#4.4a8aDaTaRanananaZaBaFaFaF#v.0#v.0#v.0#v.0amb#aob#amam.5aFamaOaFa##v.0.yaZaz.wanazaz.w.w.waO#vao.5aoamaCam.Wa0#x#xaw#xaYaY#D#M#Da9a9.E#L#L#L#Laf.7a9.7#Da9.7a9#L#L#L#L.7#L#L#L#L#L#L#L#La2#La2#L#L#L#L#L#Lafajafafa9a9a9afa9a9a9a9a9afa9a9a9.7a9.7a9a9.7a9.N#D#D#DaYam#SaZaF.5aFamamamamaoaFamamb#amamaoa0a0bnaC#x#x#xaY#IaYaYaYaYaYaYaYaY#xaY#IaYaYaYaYaY.s#xaY#D#D#D.7.n#D#D#D#M#D.N.saY#xa0a0amamambgambnbn#UaY#x#xaY.saY#x.NaYaw#x#I#x#x#I#xa0a0aF#vaZ.5a#amaCa0am#v.5", +"an#uan#uan#ua7#uaz#a.Gaz.GaSaZaZ#vbybca#.5aoamb#.5b#amb#amb#amb#aCama0amamaob#amaCa0a0aoaFaFa#byaOby#v.yaZaB#u#ua##v#S#v.5ao.5aoa0#I#xaY#x#IaYaw#Dbla9#s#L#L#La9#Laf#La9#La9.7a9#L#L.7af.7af#Laf#L#L#L#L#L#L#L#Laf#Lafa2af#L.3#Lafafafafa9afa9a9#Laf#Laf#L#Laf#L#L#L#L#L#L#L#L#L.s#D#s.7#DaCa##ua#.0.5.5amama0a0amaoamaCamaCa0#xbn#x#x#x#xawbfaY.N.N.N.s.N.N.s.Nbl.Nbl.NaY.NaY.Nbl#D#D#s.7.7#D.7a9.n#p#Dbl#DblaY#x#x#xbnbnama0am.Vama0b#aCa0#x#xbn#I#x#x#xbnbn#x.Ca0a0aCam#van.wan#vbyaF#va#.yan", +"alal.Ga7bhaZaZaZa##Sa#aFb#ao.5.8aFaFamama0amamaobn#Ubn#Ua0#Ibn#Ua0a0a0aCa0amamao#x#xaCa0aoamao.5avam.8.8#v.yaB#u#SaBaB#u#S#vaO.8amaCbn#x#I#xawaYbl#sa9a9#La9.7ajafaj#La9#L.7#Da9.7#Laf#L#L#L#L.7a2#ga2a2a2a2a2a2#La2#L#La2#L#L#La2af#Laf.na9a9a9af#Laf#La9af.7af#L#L#L#L#Laj#L#L#D#D.7#s#D.CaBbhbb.y.0aOama0aoa0ama0ama0bnbn#xaYaCbnbn#x#xaYaY.Naw.NaY.NaY.NaY.NaY#DaY#M#Dbl#M#D#Da9.7a9#Dbjb..7afa9.na9bl#DaY.N#Ibf.W#xaC.Ca0amamb#b#a0ama0ama0#xbn#x#U#x#U.C#UamaCama0ao.0.w.6.wan.yan.yan.waP", +"#q.6a#aF.5aCa0a0bnbna0aCa0amb#am#U.Vbnbn#xa0.C#x#x.NaY.NaY.N.N.N#D#s.NaY.NawaY.N#M.s.N#x.C.Wamaq#UaCaCb#bgaOa##vbg#v#v#u.w#uaZ.yaO.5aoama0.RaYaw#D#D.7.n#Laj#L#L#L#La2#La2#La2#g#Laf#L#L#L#La2#La2#L#La2#La2#L#La2af#L.3#Laf#Lafajaf#La2#La2#La2#L#L#Laf#La2#L#L#L#La2#L#Laf#L#La2#La9#D#x#xaoaO.Xbha#ama0#x#x.CaC.Ca0aC.C#x#IbnaYaYawaYaYaYaYaY.N#D#D#D#D#D#D#D#D#D#D#D#D#D#D#D.7.E.7.7.7af.7.7aj#L#L.7.E.N.N.NaY.N.N.N.NaY.NaYbl#IaYbna0aoaFaOamaoamamamaFaF.5b#aOa#a#aZ#u#a.2.waP.w.w.waZan#u", +".GanaB.5a0a0#xaCbn#Ibna0a0a0amam.Va0bnbn#x#x#I.C.NaY.Naw.N#s#D#D#D#D#s#D#D#D#saY#D#DaY.saY#x.W.Cbn#Ua0aCaoamaOaFaob##v#uaB.y#vaOa#aO.5bga0#U#x.R#D#D.n.7.7#Lbp#L#La2#L#g#L#g#La2#L#L#Lafa2a2#La2#L#La2#La2#La2#Lafa2#L#La2#La2#Laf#L#Laf#Laf#L#L#Laf#L#La2#La2#La2af#Lafa2#L.3#L.j#La9#DaY#xa0#v#aa7a#b#a0bn#x.C#x#x#x#x#xbn#x#x#IaYaYaYaYaYawaY#D#D#D#D#D#D#D#D#Da9#D#D#Dbj#Da9a9#La9af.E.7a9#Laf#Laf.7a9#D.N.N.saY.Nbl#DaY#D.NaYaYaY#xa0b#.5aFbga#aFaFbma#.ybm#vaZ#SaBan.G#q.2.w#u.6#uan.y.0.0", +".6#u.0b#a0#x#xa0bnbn#x#xbn#Ibn#x.RawaY#x#I#x#xbfaYaw.N#D#D.7.7.7a9#D#Da9#Da9#D#Da9a9#D#D.N.N#x#x#I#x#Ia0ao.8am.8aCa0bg#v#vaOb#aoaFaOaFama0a0#Ubn#s#D#Da9.E#L#Lajbpa2#ga2a2aja2#gafa2#La2#La2#La2#Laf#La2#L#Laf#La2#Laf#Laf#Laf#L#Laf#L#Laf#La2afa2#La2af#La2#L.3#La2a2#L#L#L#L#La2#La9#s.N#xa0bg.Xana#aFamam.C#xbn#xbn#x#x#x#xbnaYaYaYawaYaYaYaY#Da9#Da9#Da9#Da9.7#D.7a9.7a9a9.7.7.7.7.7a9#L.7.n#L#Laja9a9#D.saY#D.N#D#D#D#D.saY#DaYaYa0a0amb#aFbm#SbmaBaB#ubha7aB#u#uazaz#Tal#q#uanaB.0a#.0a##u", +"azaBa#aobn#x#x#x#x#x#Ibn#xaY#xaYaYaYaYaY.NaY.NaY#D#D#D#D#D.7a9.7#sa9a9bja9.7#D.Ea9bj.n#D#D.NaY.N#MaYaY#Ia0aoaoam#IaCa0ao.5ao.CaCbg.5b#aoa0aC#xa0aYaY#s.7a9#Lbp#La2bpa2#L#g#L#ga2#Laf#L#La2#La2#La2#La2#La2#La2#Lafa2#Laf#L#L#L.3aj#L#La2ajaf#L#La2#L#La2#La2#La2#La2#La2a2a2afa2#La2#L#DblaY#IamazaSaBaFama0#x.C#xaY#xaY#x#U#x#xaYaYaYaYaYaYaY#D#D#D#Dbj#D#Dbj#Da9a9a9.7a9a9bja9.7afa9aja9.7af.7#Lafa9a9#D#D#D#D#D#D#D#D#D#D#D.NaY#I#xbnaoamam.5a#bma#aZaZaZaZ#uaZanaz#q#TaR.o#q#uaB.0a#.0#uaZ#u", +"an#vb#a0#x#x#xaYaYblaYaYaYaYaYaYaYaYaYblaY.N.N.sbl#D#Da9#D.7a9#L#D.7#sa9.7a9.7#Da9a9#Da9a9#s#D.Naw#Daw#xaCa0.C#x#U#xaCaoaCa0#Ibna0a0aoa0aCa0a0#UaY#M#D#Da9.7#L.7a2a2#ga2a2#ga2#g#La2#La2#La2#La2#La2#La2#Laf#L#Laf#Lafaj#Laf#L#Lafa2af#L#La2#Lafa2#Laf#La2#La2#La2#La2#L#La2#L#La2#Laj#Dbl.NaY#UaZ.TaBaFam.C.C#xaYaYaYaYaYaY#x#xawaYaYaYaYaY#Dbl#D.Ea9a9.7a9a9.7#D.7#Da9bja9.7a9a9.n.7a9a9a9.na9a9a9a9.na9a9a9#D#D#D#D#D.7#D#D#DaY#x#x#xbna0aCamaFaOa#bma#bmaBaZaZaB.6.Gal.o#e.GazanaBaZ#u#u#uan", +"#vaFama0awbnaYaYaY.NaY#D#DaY#D#M#Dbl#s#D#D#s#D#D#Dbl#D.n#Daf.E.7a9a9.7a9a9a9a9a9.7a9.7a9.7a9a9a9#D.n#D.N#x#I#I.W.C#I.Caoam#U#xaw#Ia0#I#x#x#I#x#IaYaY#Dblbja9a9#L#La2bpa2bpa2#La2#Laf#Laf#La2#La2af#L#La2#La2afa2#Laf#L#Lafaj#Laf#L#L#La2#Laf#La2#L#La2#La2#La2#L#La2#La2#L#La2#L#L#Lafa9#sblaY#xb#bm#SaFambn#xaYaYaYaYaYaYaYaYaYaYaYaYawaYaY#Dbl.7a9bja9.7a9bja9#L#L#La9.7a9a9.7a9.7a9a9.7a9.7a9a9a9a9a9a9a9a9a9#D#Da9#D#Da9#Da9.N.NaYaY#x#x#xaYa0ama0am.5aF.5a##vaZan#TaR.Gazana7.wan#uaZan#uaZ", +"b#a0#xaYaYaYaY#x#DaY#D#D#M#Da9a9#D#D#D#D#Da9#D#p#Da9#D.7a9.7#L#La9a9a9.7#L#L.7a9.na9a9.7af#L#L#L#La9.7#s.N#I#x#x.C.CaCa0.W.W#xawaYawaYawaY.NaYaYaYawaY#sbl.7#D.7#L.ja2#ga2#ga2#g#La2#La2#Laf#L#L#La2af#L#L#L#Laf#Lajaf#Laf#Laf#Lajafaf#Laf#L#La2#Laf#Lafa2#La2#La2#L#L#L.3#Laf#La2#L#La9a9#D#MaY.b#yaFbgam#x.N#saYaYaYaYaYaYaYaYaYaYaYaYaYaY#Dbla9.7#L#L.7#L#L#L.7af#La9#La9#La9afafafafa9a9a9a9a9.na9a9a9.n#pa9.n.7a9.7a9.7a9.7#D#D#D#s#DblaYblaY#x#xaCa0aCa0amaOaZ#u#q.G.6#uaBana7azaZaZaZaZa#", +"a0a0a0aYblaYaY#xaYaY#Dbl#Da9a9af.7.7#Da9a9a9a9a9a9a9.n#Da9.7#L#L#La9.7af#L#Lafa9.7a9#L#Lajafa2aj#L.7.n#D.N#xbo#I#x.Waq.8aoa0#I.Nawbl#sbl#DaY#saYawaYaYbl#D#Da9a9#L#Lbpa2#L#g#La2#Laf#Laf#La2#L.3#Laf#L#Lafaf#Laf#Laf#L#Laf#L#Lafaf#L#Laf#Laf#Lafa2#La2#L#La2#Laf#L#L.3#L#L#L#L#L#L#L#L.na9a9blblbn#Hbga0#xaYaYa9blaYblaYblaYblaYaYawaYaYaYaYbl#Da9a9a9a9a9a9a9a9#L#L#L.7a9.7a9a9#La9a9a9a9af.nafa9#pa9#pa9#pa9a9#Da9#D.7#Da9bja9a9.7a9a9a9#D#Dbl#D#saYaY#x.Cbn.WaF#San.Ga4aZa#a#aZ#uanaZaBa#bma#", +"bnaYaYawaYaY#M.N#D#D#D#D#D#D#Da9a9#D.nbja9.7a9.7a9.7.7a9#La9a9a9.7a9#L#L.7af.7a9#Laf#Lafa9.7a9a9#L.7#La9a9#DaY#Ua0#UaCa0#I#x#I#I.N#s#D#D#sa9#D#Da9#D#s#D#Daw#DaYajaf#L#L#Laf#L#La2a2a2#La2#La2#L#La2a2a2a2bpaj#Lajaf#Lajaf#Lajafaja9ajafajaf#L#Lafafafafa2#L#L#La2#L#L#L.3#L.3#L#La2#L#Lafa9.na9aYbnb#b#am.C.NaWa9bj#D#Dbj#D.N.NaYaY#DawaY#DaY#D#D.7a9.7a9.7a9a9#Laf#Laf#Laf#L#Lafafaf#La9#D#D#D#L#Lafajaf#Laf#L#L#L#L#L#L.7.7.7a9a9.7a9#D#D#D#DaYaY.N#x#Ia0.Ca0aF#vaF#vaOb#aob#aoaFaBaZ.0a#.5am", +"#U#x.RaYaYaYbl#D#D#D#D#s#D#Da9#D#D.7#Da9.7a9bja9.7a9af.7a9a9.7a9af.7a9af#L#L#La9a2afaj#L#La9.7a9aj#L#La9.nblaYaY#Ia0aC.W#x#I.N.s#D#s#D.n#D#D#D#sa9a9a9#Dbl#D#D.Na9a9a9a9a9#La9#L#Laf#Laf#Laf#Laf#Laj#L.7aj#L#L.7afajafaf#Laf#Laf#Laf#L#Laf#L#Lafafafaf#Lafa2#L#L#L#La2af#L#L#L#La2a2af#L#La9bja9.Rawa0.8a0.C.Nbj#Da9a9#Da9#D#DaY#DaYbl.Nblaw#Dbl#D.7a9a9.7a9a9bjaf#Lajaf#L#Laf#Lafafafa9a9#Da9#D#Laf#Laf#L#L#Lafaj#L#L.7#L.7af.7#La9a9.7#D#D#D#D#D.NaY#x#x.C.CaoaFaFaOaOamamamamaCaF#v#v.0#vb#am", +"bnbnawaYaYaY#Dbl.n#D#D#Da9bja9bj.n#D.7a9#D.7a9a9a9.7a9a9#La9a9a9#L#L#L#L#Laf#L#La2a2a2af#La9a9a9#L#Laf.7a9#D#IaY#UbnaC#xaY.N.saY.s#D#Db.#D.n#D.7a9a9#Da9#D#D#D#Da9bja9#Da9#Da9#Da9a9a9a9a9a9a9a9#Laf#L#Lafafajaf#La9#Lajaf#Lajaf.7#Laf#L#Lajaf#Lajafaf.3#L#L#L#Laf#Laf#La2a2#La2#La2#La2af.Ea9.naY#xaCamam#x.Nbj#s.7#D#D#D#Dbj#D#Dbl#Dbl.Nbl#Dbla9a9a9a9a9a9a9a9afafafafajafafajafaf.na9a9a9#D#D#Lajaf#L#Lafa2#L#Laf#L#L#La9.7a9a9.7a9a9#Da9#D#D#D#MaY#x#x.CaCa0aFaOaFamaFaCa0a0bnaCb#aOaFaOama0", +"#IaYaYaYawaYaw#D#D#D#s#D#sa9#sa9.7a9a9a9.7a9#L.7#La9af.7a9a9.Ea9afaj#Laf#L#La2#La2a2a2#La2#La9#L#L#Laja9a9blaYaY#I#U#xaw.Naw#D#Da9#sa9#sa9.7a9.7ajaf.Ea9a9.7a9#D#D#D#D#Dbj#D#D#Da9#D#D#D#sbl#D#sa9a9a9a9a9#Da9#Dafajafaf.Eaf.7afajaf#Lajafaf#Lafafafajaf#Laf#L#L#Laf#L#L#Lafa2#La2a2af#L#La9a9a9aw#x.Vaoa0#x.Nbja9#D#D.7#D#D#D#Dbl#DaY#DblaYaY.Na9a9a9a9a9.7a9a9#La9afa9afa9af#pafa9#pa9a9a9.7a9#Laf#Laf#L#L#L#Laf#L#Laf.7a9#D.7a9.7a9.7#D#Dbj#Dbl.NaY#x#I.Ca0aqbgaFamaoambn.Cbn#U#xbna0aCama0a0", +"aYaY#IaYbl.N.N#D#s#D#D#D#D#D#Da9a9a9.7a9a9a9a9#Laf#L#Laf#L#Laf#L#Lafa2a2a2a2a2a2a2a2a2a2a2#L#Lafa2#L#La9a9#DaY#Ubn#I#xaYaw#D#s.sa9bj.n#Da9.Ea9.7#L.7#L#L.7a9.7#L#Da9#Da9#Da9#Da9#Dbl#Dbl#D#Dbl#Dbl#s#D.na9#s#D#Ma9a9.n#Laf#Lajaf#Laf#Laf#L#Lafajafafafaf#Laf#L#L#La2#L.3#L#L#Lafa2a2#L#Lafa9.na9#Dawa0bga0#x.N#s#Da9#D#D#D#D#D#D.Nbl#DaYaYaYawaYa9.na9#La9afa9afa9a9a9a9a9a9a9a9a9#pa9a9a9a9a9a9#L#Lafaj#L.3#La2afafa2af#La9a9a9afa9.7a9#D#D#D#D#DaY.N#x#xa0a0aoaFbgama0a0a0aCa0aYaY.baYbnbnaC#x", +"aYaYblbl#D#Da9.7a9a9a9a9.na9a9.7ajafaj#L#L#La2#L#L#L#L#Lafaj#Lafa2a2#L.j#La2#La2a2a2a2#La2af#L#L#L#L#L#La9#MaYaY#Ibn#MaY#D.s#D#s.7.na9.Ea9.7aj#La2aj#L#Laj#L#L.7.7a9.7.7a9.7a9.7#M#Dbl#MblblaYbl.sbl#Dbl#D#Dbl#Daf.Ea9af.Eafa9af#Lafaj#L#Laf#Lafafafafafaf#Laj#L#Laf#L#La2afa2#La2#L.3#L#L.7#Da9#DaYaCama0#Ibla9#Dbj#D#Da9#D#D.N#MaY#DblawaYaYaY#pa9a9a9#pa9a9a9afa9afa9#p.na9a9#Mbla9a9a9#La9.7afaj#Laf#L#Laf#Laf#Laf.7afa9afa9a9.7a9#D.7#D#D#D#Dblaw#x#x.WamamaOb#aOa0aC.Cbn.C#U.RaYaY.b#xbna0", +"aYaY#D#D#D#s.7.7a9.7a9.7a9a9.7a9#Laf#Laf#Laf#Lafa2a2a2a2#La2a2aja2a2.3a2a2a2a2a2aaaaa2a2a2a2a2#La2#L#La9a9#DaY#I.RaYaw#D#M#D#s#D.n.7a9.n#L.7af#La2a2a2#La2#L#L#La9a9.7a9a9.7a9a9a9#pa9a9a9.n#pblaYaY#IaY#IaYaw#x.na9af#Laf#Laj#Laf#La9afajaf#L#Lafafafaj#Laf#L#Lafa2#L.3#L#L#L#La2a2#L#Laf.na9.n#D.NbnaCaobn#D#s#D.n#D#D#D.N.NaY#DaY#Dbl.NaYaYaw#D#pa9#p.n#pa9#pa9a9.n#pa9#pa9#pa9#D#pa9afafajaf#Laf#L#Laf#L#Laj.3af.3afafa9a9a9.7a9.7a9#D#D#D#D.NaY.N#xa0ama0aob#ama0a0a0bn#Ibna0#x.bbnaY#Uamam", +"#MaY#s#D#D.7#La9#L.7.na9a9.7a9a9#L#L#L#La2#La2#La2a2a2aja2#La2afa2aja2#La2a2a2a2#gaaa2a2a2a2a2a2a2#L#La9a9blaYaYaY#MaY#M.N#D.n#D.na9.n.7#L.E#L#L.ja2a2a2#g#L#L#L#Lajaf#Lajaf#L#La9a9#pa9#pbla9.naYawaYaYaY.RaYaY.na9.na9aj.7af.n#Lafaj#Laf#Lajafafajafafaf#L#L#L#Laf#L#La2afa2af#L#La2af#L.7a9a9.7aw#xaCa0#IaYa9#D#D#D#D#D.NaY.saY#Dbl#DaYaYaYaY.na9#pa9a9#p.na9af#p#pa9a9a9#pa9#Dbl#Da9.na9#L#Laf#L#Lafajaf#Lafafafafafafafa9a9afa9a9bja9bj#D#D#D#DaY#x.Wa0av.5.pamaCa0#Ua0#x#xa0bnaYaw.R.Cb#am", +"amam#xbla9a9a9a9a9a9.7a9.7afa2#Laf#Laf#La2#La2#La2a2a2a2a2a2a2a2#Laf#Laf#La2#L.3a2a2a2a2asa2#La2#gafa9blaYawaYaYawbn#IaYawaw#D#Da9.Ea9#Lafaf#L#L#L#La2a2a2a2a2a2a2a2#La2af#L#Lafajaf#L.na9bja9#D#p#pbl#M#x#Ia0bn#I.NaY#D#Da9a9.7af.Eafa9aja9#Lafa9a9a9a9#Lafa9afajafafafaf#Lafafa2.ja2afajaf#L.na2a9aY.Cbgam#x#Ma9.n#Lajafa9.N.N#pa9bl.N#MaYaYaY#p#pa9#pa9#pa9#p#pa9#p.n#p#p.n#pa9#pa9a9#paf#pa9a9.n#pafafafafafafafa9afa9afa9a9.na9a9a9a9a9#D#D.n#paYaYa0amb#amb#a0a0a0.Ca0#I#xaw#xaY#x#xaCa0aC", +"ama0#xbla9.na9a9bja9#Da9a9ajaf#La2aj#Lafa2#La2#La2a2#La2#La2#La2af#Lafa2#Laf#L#La2a2a2asa2a2a2a2a2#La9blaYaYaYawaYaY#xawaY.N#s#Daja9#Lafajaf#Laf#L.j#La2#La2#La2#La2#La2#L#L#L#L#L#Laf.7a9#D.n#Da9.nblblaYaY#xaC#x#IaY.s#D#sa9.na9a9a9a9a9a9a9a9a9afa9afa9a9#La9afafaj#Lafaf#Lafa2#La2#Lafafaj#La2.naw.CamaC#xaY#D#D#La9a9#sbl.Na9#M#DblaYaYaY#xbla9#p#pa9#pa9#pa9#pa9#p#pa9#p#p#pa9.n#pa9a9a9af#pafa9afa9a9afa9#La9af.7afa9afafa9afa9a9.na9#Dbl#p#pblbn#U.5bg.5a0aoa0a0#Ua0#xbnaYaYaY#U#xbn#xa0", +"amaCaYaYaw#Dbl#sa9#D.7a9.7af#L#Lafaf#L#La2#La2#La2a2a2a2a2a2a2a2#L#L#Lafaja2#L.3a2a2a2#La2a2a2a2#ga9#D#MaYaY#UaY#xaw#Ibl.Naw#D#Dafafaja9#L#Laf#La2#La2a2a2a2a2a2a2.jafa2#Laf#Laf#Laf#La9a9.7#Da9a9a9#sblawaY#x#x#IaY.NaY#D#D#D#D#sbl#s#D#sa9a9.na9.na9a9.nafa9afafafafafafafajafa2#L.3#L#Laja9#Daj#DaY.Ca0aoa0aY#D#Ma9.na9#D#DaYblblblaYaYaYaYaYbl#pa9#pa9#pa9#pa9#p#Ma9bl#p#D#pa9a9#pa9#pa9#pa9#pa9#pa9#paf#pa9afa9afa9afa9afa9a9a9a9a9a9a9#Da9bla9awaYa0a0ama0b#a0a0a0#x#U#x#xaw#xaw#xbn#I#xa0", +"b#b#aCaYaYbl#Dblbja9#D.na9#Lajaf#L#L#Lafa2#La2#La2a2#La2#La2#La2afafaj#L#Laf#L#La2#La2a2a2a2#La2#La9blaYbnbn.R#IaY#U#xaYaw.N#D#s#L.Eaf#Lafaj#L#L#La2#La2#La2#La2afa2a2a2#L#L#L#Lafajaf.7.n#Da9b.afa9a9a9#DaY#I#x.NaY#saY#s#D#s#DaYaYaYblaY#DaY#Dbla9a9a9a9a9a9a9.na9a9.na9a9a9a9#La2aj#Lafa9a9a9af#Mawa0aCa0a0bn.NaYbl#D#M#DaY.NaYaYaYawaYaYawaYbl.na9#pa9#pa9#pblbla9#p#pa9#p.na9#pa9.n#pafa9af.naf#pajafafafafa9a9a9afa9af.7afaf.nafa9a9af#D#DblblaYaY#xaCa0.Ca0aobnaCbn#xawaYaY.RaYaYaY#xbn#x", +"a0bnbnbnaYaYbl#D.n#D#sa9a9#Laf#L#L.3#L#L#La2#Lafa2a2a2a2a2a2a2a2#L#Lafaf#L#La2#L#La2#L#L#La2#L#Laf.nblaY.bbn#U#x#Ubn#Ibl.NaYa9.7a9afaja9#Lafaf#La2a2aja2a2a2a2a2a2a2a2a2af#Laf#L#L#L#La9a9.7#Da9#Laja9#D#D.NaYaY#s#D#D#DaY.NaY.saY.saY.NblaY#DaY#sbl#sbla9#Da9#Da9a9.na9a9afa9ajafaf#Lafa9a9#D#sa9blaY#Ua0aob#aC#xaYaw#D#DblaY#IaYawaYaYaYaYaYaYbl#pbla9#pa9#pa9bl#M#p#D#p#M#p#pa9#pa9#pa9a9#pa9#p#pa9#p#pafafaf.nafa9a9#La9afafa9afa9a9afa9#Da9bl.NaYawbn#x#x#x#Ubna0#xbnaY#xaYawaYaw#xawaY#x#U", +"#Ubn#Uam#UaYaYbl#Da9bja9a9#L#Laf#L#Laf#Laf#La2#La2a2#La2#La2#La2af#L#L#L#Laf#La2af#L#La2#L#La2#Lafa9bl.Ra0.pa0bn#U#xawaY#M.N#s.7.na9#Lafaj#L#Lafa2a2a2a2#La2#La2a2a2a2a2#L#L#L#Laf#Laf.7a9#D.7#Dafaf#L.na9#Daw.N.n#D#D#s#Daw#DaYaYaYaYawaYaYawbla9bla9bla9.n#D#Ma9a9a9#Da9#sa9#p#Laf#La9.7.n#D#D#DaYawa0a0aob#amaCa0aYaYaY#DaY#xaYaYaYaYaYbl#Dbl#p#pa9#pa9#pa9#p#pbl#p#pa9#pa9bl#p.na9a9#pa9#pa9af#pafa9af.na9afa9a9aja9a9afa9#Laf.7afa9.7afbl#D#D#DaYaYaY#xaY#xa0bnbn#U.RawaY.baYaYblaY.R#IaYaY", +".Rbnb#a0a0#xaYbl#s#D#sa9.Eaf#L#La2#Laj#La2a2#L#La2a2a2a2a2a2a2a2#La2afa2afa2#Laf.7af#La9a9#Lafa9a9a9.R.Ra0.V#UbnaYaYaY#D#D#D#D.7afajaf.Eafaf#L#La2#La2#La2a2a2a2a2a2#La2#L.3.7#Lafaj#La9a9.n#Da9#Laj.7a9.7#D.N.Na9.n#D#DaY.NaY.sbl#Mblbl#Dbl#Dbl#D#Dbl#s#Dbl#Dbla9#Da9.nbla9a9#Dajaf.na9#D#D#D#sblawaY#x#Ub#b#aO.5a0aCaYaYawaY#x#xaYaYaY.sblbl.na9#pa9#pa9#pa9#pblbla9#M#p#Dblbl.n#p#p.na9#p.n#p.na9#pa9#pa9af#pa9afa9a9af#Laf#Lafafa9afa9a9#Da9bl#D#M.NaY.Naw#x#UbnbnaYaYaY#xaYbl#MblaYaYaYaY#I", +"#Fbn.Vaoa0bnaYblbja9#Da9a9#Lajaf#Laf#Laf#L#L.3#La2a2#La2#La2#La2af#L#L#L#Lafaj#La9#L#La9a9#L#Lafa9blaw.R#Ua0bnbn#IaYaw#D#s#Da9#s#La9#Laf#L#L#L#La2a2a2.j#L#La2#La2a2a2a2#L#Laf#L#Laf#Laf.7#D.7#s#L#L#La9.7#D.sbf.n#Da9#Daw#DaY.N#pbl#M#D#p.n#pa9#sbl#D#D#Dbl#D#D.na9#Dbl.n#Da9a9af#La9.7a9#s#DaYaY#x.baYbnaoamaFaFaoa0#IbnaYaY.R#x#xaYaYbl#Da9#pa9#pa9#pa9#pbla9#M#pa9#pa9#p#Mbl#pa9a9a9#pa9a9#pa9#paf.naf#pafafa9a9a9afa9af.7afa9#L#La9a9af#D#D#D#DaY#D#DaY.NaYbnbn#U#x.baYaYaw#paY#D#MaY#IaYaY", +"blaw#xa0ambn#xaYawblbl#D#pa9afafa2a2a2a2a2a2#La2#L#La2#La2#La2#La2a2a2afa2#La9a9a9a9a9#D#D#D#D#D#pbl#paY.Rbn#I#x#pa9a9a9a9.7.7a9afajaf.n#Laf#L#L#L#L#La2a2a2#ga2a2bpa2#L#L#L#L.7af#Laf.7a9a9a9#Da9a9#sa9#D#D#D.Na9a9a9#sbl#D#Ma9bl#Dblbl#Dblblbla9a9a9afa9a9a9a9a9a9afa9a9a9a9.nafa9a9.na9a9#D.naY.RaYbna0a0b#aobgb#bg.Va0aCaY#D#Mbl#Mbl#Dblbl#Dbl#Dbl#Dbl#Dblbla9#pbla9#p#pa9#p#p#p#p#p#pa9#pa9#p#p#p#pa9a9afa9aja9afaf#Lafaf#La9afa9#Lafa9a9af#sa9#Dbl#DaYbl.N#UbnbnbnaYaY#IaYaY#MaY#xaYaYaYaY", +"aYaYbn.Ca0a0#I#xaYaYblbl.naf#Lafaja2#La2#La2a2a2#La2#La2#La2#La2a2a2#L#L#L#L#L#Lafa9af#D#p#Dbl#D#F.nblblaYaYaYaYa9.n.7a9a9.7a9.7afafaf#L#L#L#L#La2#ga2#ga2bpa2#L#ga2a2#L#L#L#L#L#Laj#Laf.7a9bja9.7#D.7#D#D#D.Naw#D#M#D#p#D#p#D#Dbl#sbl#Dblbl#Dbla9.na9.naf#paja9afa9.na9a9afa9a9afajafa9a9a9blblaYawaY#Ua0aC.5am.V.Vb#ama0aYaY#xblaY#DaYbl#M#Dbl#Dbla9bla9bla9bl#D#p.n#pbla9bl#p#p.na9#p.na9#p.na9bl.na9afa9a9a9a9afa9#La9af.7afa9a9#Laf#Lafa9a9a9a9a9#D#DaY#saYbnbn#U#x#UaYaYaYaYaYaYawaYaYaY#x", +"aY#xbna0a0a0a0bnaYaY#Mbla9a9a9af#L#Laf#L#L#L#Lafa2#La2#La2#La2a2#La2afa2af#L.7#La9a9#D#D#D#D#DaY#pblbl#MaYaYbl.Na9a9a9.7a9#L.Eaf.naf#Laf#L#L#L#La2a2bpa2#ga2#ga2a2#L#L#L#L.7a9a9a9a9afa9a9#D#D#sa9.nbl#DaYblaYaYbl#D#D#D#M#Dbl#sblbl#Dbl#sbl#D#Ma9a9a9a9a9a9a9a9a9a9a9a9.na9a9a9.n#pa9a9#D#sbl#saYaY.RaY#xa0a0aCa0#Ua0aCbnaYaYawbl#sbl#M#Dblbl#D#pa9a9a9a9a9a9a9#p#p#D#p.n#pa9.n#p#p#pbl#pa9a9#p#pa9#p#pa9a9afa9af#Lafaf#Lafaf#La9a9afa9af#La9afa9a9bl#D#p#DaY#DbnaCbnbnaYaY#IaYaYaw#xaYaYbn#I.R", +".Raw#xa0aC.Ca0a0.baYaYblbla9a9af#Laf#L#La2afa2#L#La2#Lafa2#La2a2a2a2a2#L#L#Laf#L#D#p#Dbl#DblaYaY#pblblbl#Dbl#D#Dafa9af#L#La9#L.7afaf#Lajaf#L#L#L#L#ga2a2#La2bpa2#L#L#Laf#La9.7#Da9a9a9#D#Dbl#DaYblblaYaYaYawaYaY#xawaYaYaYaYaYaYaYaYaYaYaY.NblaYa9a9#pa9a9#pa9#p.n#Da9a9a9#Da9#D#pa9bl.na9blaYblblaYaY#IaYbnbna0#Ua0b#b#a0aYaYblblbl.Nblbl#Dbl#Da9a9afa9afa9afa9#Ma9#pa9#pbl#pbl#p#p#pa9#pa9#pa9a9bl#p.na9a9a9a9#La9af.7afa9#La9afa9a9af.7afafafa9a9a9#D#D#DblaYbnbn#Ibn#IaY.RawaYaYaYaYaYaY#x#x", +"bnbnbnbna0a0a0amaYaYaYaY#D.na9a9afa9afa9#L#L#Laf#L#L#La2#La2#L#La2#L#Laf#L#L#Laf#D#Dbl#DblaYaYaYa9.nblbl#D#D#Dblafaf#L#L#L#L#L#L.naf#Laf#L#L#L#L#ga2bpa2#ga2a2#gaf.3af.7afa9a9.n#D#Dbl#sblbl.NaYaYaYaYawaY#x#xaYaYaYaYaYawaYawaYaYawaYawaYblaYblblbl#Dbl#M#Dblbl#Dbl#D#Dbl#s#Dbl.n#pa9blawblawaYaw.RaY.RaY#U#xbn#UbnaCaOama0aYbl#Dbl#Mbl.Nblbl#Da9.na9a9a9a9a9a9a9#pbl#pa9#pa9#p#p#p#M#p#p.n#pa9.n#pa9#pa9a9afa9#Lafa9afa9#Lafafa9afafa9af#La9#La9af#Dbl#Daw.NawbnbnbnbnaYaY#xaYbn.baY.RaY#xbnbn", +"ama0bna0#Uambgb#aY.RawaYbl#Da9a9a9.7a9.7a9af.7#L#La2af#Laf#L#L#La2a2#La2#Laf#L.7#pblblaYaYblaYaYblblbl#Da9a9a9.7afajaf#L.3#L#L#L#Lafaf#L#L#L#L#L#L#ga2a2bpa2bpa2#La9#Lafa9af#D#D#Dbl#DaYaYaw#xaYaYawaYaY#xbnbnaYawaYaYaYaYbnaYaYaY.RaY.RaY.baYawbl#Mblblblbl#Mblbl#D#D#M#Dbl#D#D#pbl#MblblaYaYaY.RaYaYawbnaYbnawaYaYa0aO.Fa0#x.R#Dbl.Nbl#Mbl#sbla9a9a9a9afafafaf#p#p.na9bl.nbl#p.n#p#pa9#pa9a9#p#pbl#pa9a9a9a9a9#La9afa9a9afa9#Laf#La9afa9af#Lafa9a9#D#Dbl#DblaYbna0#Ubn#I.RawaYawaYaYaY#UbnaCbn", +".Va0bna0.V.Vb#.5bn#xaYaYaY#Da9a9a9#La9#La9#L#Laf#L#L#La2#La2afa2#La2#Laf#La9a9a9blaY#MaYaYaYaYaYbl#Dbl#Dafa9#L#Lafa2a2a2a2a2#L#Lafaj#Laf#L#L#L#La2a2bpa2#ga2a2#gafafafa9a9a9bl#pbl#DblaYaYaYaY#xaY.Rbnbn#Ua0a0a0aYaYaYaYaYaYaY#U.R.b.R.R#U.Rbn.RaYaYawblaYblaYbl.N#MaY#DaYblaYbl#sblblblawblaYaYawbnaY.RaYaw.RaY#IbnaCb#aOb#.Vbn#DblblawaYblbl#Da9a9a9a9.7a9.7a9#D#pbl#p#p#pa9#p#p#p#pbla9#pa9a9#pa9.n#pa9.na9a9afafa9a9afa9#Laf.7af#La9afa9#Lafa9a9a9bl#s#DaY#sbnbnbnbnaYaY#x.Rbnbnbnbnbn#xa0a0", +"a0.Vbn.bbna0b#b##UbnaYaY#D#Ma9a9.Ea9a9a9.7a9.7#Lafa2a2#La2af#L#La2a2#L#L#Laf.7.7blblaYblaYaYaYaY#DaYa9a9a9#La2#La2a2#La2#L#ga2#Lafafafa2#L#L#L#L#L#ga2#g#La2bpa2afafa9af#p#Da9#D#DaY#D#DaYaYaY#x.RaYaYbnbna0a0a0aYaYaY.RaY#UaYaYaYaYaYaYaYaYaYaYawblaYaYaYblaYblaYbl.NblaY#s.Nblblbl#MblaYawaYaY.Raw.RawaY.b#x.baY#xa0aob#bga0bnbl#sblaYaYbl#sbla9.n.7a9.n.7a9a9#pa9#pa9#p#D#pbl#p#p.na9#p.na9#p.n#pbl#pa9a9a9af.7a9afa9.na9a9afaf#Lafa9afa9af#La9.nbl#D#D#DblaYbnbn#UaYaYaYawaY.RaY.Rawbnbna0a0", +"aYaYaYaYaYaY.N#xaYaYawbnaYaYaYaYbl#Dafa9afa9.7#L#L#L#L#L#L#L#L#L.3a2afafa9#D#DaY.R.R#x.RaYawaYaYa9.7a9#L#L#Lafa2a2a2a2a2#g#L#L#Lafafajafafa2#L#L#L#L.7#L#L#L#L#L#L#L#Laf.7#La9a9a9.7a9#D#D#D#D#Dblbl#IaY#xaY#xaYaYaYaYawaYaYaYaYaYawaYaYawaYaYaw#Fbl#M#FblaYaYaY.R.R.R.R.R.R.R.RawaYaYaYaYaYaYawaYbl.NaYaYaYbn#Ibn.baY#Ua0aOb#.Vbg#HaY.bbla9a9.na9a9a9a9.7a9a9.Ea9#p.na9a9.n#pa9#pbl#p#pa9#p#pa9#p#pa9#pa9#pa9a9#pa9.na9afafaf#L#Laf#L#L#L#L#Lafa9a9a9#pblbl.Nbl#x.R#xaY.R#x#xaYaw.RaYaYaYaYaY#D", +"aYblaYaYaY#IaY.NblawaYaYaYaYaYaY#Dbla9a9a9a9a9#L#L#L#L#L#L#L#L#L#Laf#Lafa9#Dbl.N.R.Raw.RaYaYaYaY.7#Da9.7af#La2#La2#ga2#ga2#L#L#Lafafafaf#L#L#L#L.7#L#L#L#L.7#L.7a2a2#L#Laf#La9bja9#D.7#D#D#D#D#D#D#DaYaYaYaYaY#xaYaYaYaYaYaYaYaw#xaY#xaYaYawaYaYbl#FblaY#MaYblaw.R.b.R#MaY#FaY#FaYaYaYblaY#MaYaYblawaY.RawaYawaYbnaY#Ibnao#SaBaF.p#H#U.RaY#Ma9#Da9a9.7a9a9a9a9a9a9a9a9#pa9#pa9.na9#pa9a9#pa9#pa9#p#D#p#s#pa9a9afa9af#pafafafafaf#L#L#Lafaj#Lafaja9#pa9a9#Dbl#DblaY#UaYaYaw#x#xbnaYblaw.RaYaY#Dbl", +"blaYblaYaY#D.NaY#pblblaY.RaYaYaYbl#Dbl#Da9a9.7a9#L#L#L#L#L#Laf#Laf.nafa9#D#DaYaYbn.RbnaYaY.R#xaYa9.7a9#L#L#La2#La2a2#g#L#L#L#L.7afajafaf#Laf#L#L#L#L#L#L#L#L#L#La2#La2a2#L#L#L#L#L#La9.7#Da9bj#DblblaYaYaYaYaYaYbl#Dbl#D#Dbl#Dblbl#Mbl#MaYblaY#Mbl.nbl#pa9aYblaYblaYaYaY.RawaYaY#M#F#M#Fbl#F#F#M#p#p#p#MblaYaYaY#UbnbnaCam#SaBbm#H.p.p.RaYaYbla9.na9a9.na9a9a9a9a9#pa9a9#pa9#pa9#pbla9#pa9#pa9#pa9#p#p#pa9#pa9#pa9#pa9a9afafafaf.3afajafafafafafa9.n#pa9#p#Dbl.N.RbnaY.RaYbnaY#x.b.RaYaYblbl#Dbl", +"#DblblaY#Dbl#D#Dbl#DawaYaYawaYaYaYaYbl#Dbl#D#Da9#Da9#Da9#Da9.7a9a9#p#Dbl#DaYaYaw.R.RaYbnaYaY#xaY#D#Da9.7#L#L#L#La2#ga2#L#L#L.7afafafafafaj#L#L#L#L#L#L#La2#L#L#La2a2a2#La2#L.7#La9#L.7a9.7#D#D#D.N#Dbl.sbl#D#Dbl#D#D#D#Dbl#D#D#Da9#D#D#Da9#D.n#D#pa9#pa9a9blblblblaYblblblblblbl#p#Fbl#p#pbl#pbl#p#M#pblbl#Faw#FbnbnaCamaCaF#SaZ#Hb#bgbnaw.Raw#Da9a9a9a9a9a9.na9afa9a9#p.na9a9#p.na9#pa9#pa9#pa9#M#p#D#p.na9a9a9af#pajafafafafaf#Lafa9afa9a9afaf#paf#p.n#Dbl#DblbnaYbn#Ubn#x#U#xbn.baYblaY#DaY#D", +"blblaY#DaY#D#D#Dbl#Dbl#DblaYaYaYaYaYaYaY#M#Dbla9#D#D#D#D#D#D#D#Dbl#Dbl#DaYaYaYaYbn.R#U.RaY.R#xaY.7a9.7#Laf#La2#La2a2#L#L#L#La9.7afafafaf#Laf#L#La2#g#L#g#L#ga2a2a2a2#La2a2#La2#L#L#Laf.7a9a9#Da9#DblaYaYbl.Nbl#Da9a9a9a9a9a9a9a9.na9.na9a9.na9a9ajafa9.na9a9.na9blblbl#Dblblblbl#M#p#p#p#p#p.n#p#p#p#p#M#pblbl#MbnbnbnaCa0aF#SaZ.V.V.VbgbnaYaYaYbl#D#D#D#D#D#Dbla9#p.na9#pa9#pa9#pbla9#pa9#pa9#pa9#pa9#pa9#pa9af#pa9#pafafaf#Lafa9a9a9a9a9afa9a9afafa9#p#Dbl#saY#x.bbn#xbn#I#xbnbnbnbnawbl#Dblbl", +"a9#pa9bl#M#Dbl#Da9a9#D#D#D#D#D.Nbn#U.RaYaYaY#D#Dbl#D#Dbl#D#Dbl#DaYblaYaYaYawaYaYaY.RaYbn#xaw#xaY.7a9#D#L.7a2#Laf#L#Laf#La9a9#Da9afafajaf#L#L#L#Lbpa2a2a2#ga2a2bpa2a2a2a2a2a2#La2.3#L#L#La9.7a9.7bl.NaYaY#D#pa9#pa9a9a9afafa9a9a9afafafajafafafafafajaf#La9a9a9bj.na9#D.n#Da9#s#D#p#p#p#p.n#pbl#p#p.n#pa9bl#Mblbl#UaY#U#x#Ub#aB.l.V.V.V.VaCbnaY.R#D#Mblbl#Mblblbla9#pa9#pafa9a9#pa9#p#pa9#pa9#pa9#pbl.n#D#pa9#pa9afafafafafafafafafa9#p.na9a9a9a9afafafa9#p#DaYaY.Rbn#x#Ubnbn#xaCa0aCbnaYaYblbla9", +"#pa9#p#Dbl#Da9#Da9afa9bla9bl#DblaYaYbnaYaYaYaYaYblaYblaYblaYaYblaYaYaYaYaYaYaYaY.Rbn.R#xaY.RaYaYa9.7a9#Laf#L#L#Lafaf#Lafa9a9a9.nafafafaf#Laf#L#Laa#ga2#ga2a2#ga2aaasa2a2#La2a2#L#L#L.3#La9.7a9#DaYblaYblbla9a9ajaf#Laf#L#Lafajaf#Lafafaf#Laf#L#La2#L#L#L#L#L.7.7a9a9a9a9a9.na9a9.na9a9a9a9a9a9.na9a9.n#D#D#D#D#D#MblawawbnaC.F.t.Fb#.Vb#.Vbnaw#xaYaYaYaY.NaY#D#Da9#pa9a9#p.n#pa9.nbla9#pa9#pa9#pa9#p#p#pa9.na9afafafafafafafafafa9a9afa9af#pafafafafa9#p#Dblblaw#xbn#Ubn#x#IbnaCb#aCbnawaY#D.na9", +"#pa9#pa9a9#Dbla9a9a9af#D#Da9#D#D#xbn#xbnaYaYblaYaYaYaYaYaYaYaYaYbnaYaYaYaYaYaYaY.R.R.RbnaYaYaYaY#D.7#Da9#La2#Lafajafafa9a9a9a9#Dafafafaf#La2#L#La2a2#ga2a2#gaaa2asaaa2a2a2a2a2a2a2#L#L#La9a9.7a9#D.saY#D.n#pafaf#Lafaj#L#Laf#L#Laf#L#L#L#L#Lafaja2a2a2a2#L.E#L#La9a9a9.7a9a9a9a9a9.7a9.na9a9a9a9.E#L.7.7#D#s#D#s#Fblbl#M#xbnbg.t.F.t.V.V.VaCa0aY#DaYaYaYaY.Nblbl.na9#p.na9a9#pa9#p#pa9#pa9#pa9#pa9#p#D#pa9#p#pa9afafafaf#Lafafa9af#pa9#pa9afa9afafaf#pa9a9#D#DaYbnbn#xbn#Ua0bna0bg.Va0aYblbl#pa9" +}; diff --git a/plugins/styles/metal/metal.cpp b/plugins/styles/metal/metal.cpp new file mode 100644 index 0000000..84de265 --- /dev/null +++ b/plugins/styles/metal/metal.cpp @@ -0,0 +1,523 @@ +/**************************************************************************** +** $Id: metal.cpp,v 1.1.1.8 2006/05/07 17:31:30 chehrlic Exp $ +** +** Copyright (C) 1992-2005 Trolltech AS. All rights reserved. +** +** This file is part of an example program for Qt. This example +** program may be used, distributed and modified without limitation. +** +*****************************************************************************/ + +#include "metal.h" + +#ifndef QT_NO_STYLE_WINDOWS + +#include +#include +#include +#include // for now +#include // for now +#include // for now +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +///////////////////////////////////////////////////////// +//#include "stonedark.xpm" +#include "stone1.xpm" +#include "marble.xpm" +/////////////////////////////////////////////////////// + + + +MetalStyle::MetalStyle() : QWindowsStyle() { } + +/*! + Reimplementation from QStyle + */ +void MetalStyle::polish( QApplication *app) +{ + oldPalette = app->palette(); + + // we simply create a nice QColorGroup with a couple of fancy + // pixmaps here and apply to it all widgets + + QFont f("times", app->font().pointSize() ); + f.setBold( TRUE ); + f.setItalic( TRUE ); + app->setFont( f, TRUE, "QMenuBar"); + app->setFont( f, TRUE, "QPopupMenu"); + + + + // QPixmap button( stonedark_xpm ); + + QColor gold("#B9B9A5A54040"); //same as topgrad below + QPixmap button( 1, 1 ); button.fill( gold ); + + QPixmap background(marble_xpm); + QPixmap dark( 1, 1 ); dark.fill( red.dark() ); + QPixmap mid( stone1_xpm ); + QPixmap light( stone1_xpm );//1, 1 ); light.fill( green ); + + QPalette op = app->palette(); + + QColor backCol( 227,227,227 ); + + // QPalette op(white); + QColorGroup active (op.active().foreground(), + QBrush(op.active().button(),button), + QBrush(op.active().light(), light), + QBrush(op.active().dark(), dark), + QBrush(op.active().mid(), mid), + op.active().text(), + Qt::white, + op.active().base(),// QColor(236,182,120), + QBrush(backCol, background) + ); + active.setColor( QColorGroup::ButtonText, Qt::white ); + active.setColor( QColorGroup::Shadow, Qt::black ); + QColorGroup disabled (op.disabled().foreground(), + QBrush(op.disabled().button(),button), + QBrush(op.disabled().light(), light), + op.disabled().dark(), + QBrush(op.disabled().mid(), mid), + op.disabled().text(), + Qt::white, + op.disabled().base(),// QColor(236,182,120), + QBrush(backCol, background) + ); + + QPalette newPalette( active, disabled, active ); + app->setPalette( newPalette, TRUE ); +} + +/*! + Reimplementation from QStyle + */ +void MetalStyle::unPolish( QApplication *app) +{ + app->setPalette(oldPalette, TRUE); + app->setFont( app->font(), TRUE ); +} + +/*! + Reimplementation from QStyle + */ +void MetalStyle::polish( QWidget* w) +{ + + // the polish function sets some widgets to transparent mode and + // some to translate background mode in order to get the full + // benefit from the nice pixmaps in the color group. + + if (w->inherits("QPushButton")){ + w->setBackgroundMode( QWidget::NoBackground ); + return; + } + + if ( !w->isTopLevel() ) { + if ( w->backgroundPixmap() ) + w->setBackgroundOrigin( QWidget::WindowOrigin ); + } +} + +void MetalStyle::unPolish( QWidget* w) +{ + + // the polish function sets some widgets to transparent mode and + // some to translate background mode in order to get the full + // benefit from the nice pixmaps in the color group. + + if (w->inherits("QPushButton")){ + w->setBackgroundMode( QWidget::PaletteButton ); + return; + } + if ( !w->isTopLevel() ) { + if ( w->backgroundPixmap() ) + w->setBackgroundOrigin( QWidget::WidgetOrigin ); + } + +} + +void MetalStyle::drawPrimitive( PrimitiveElement pe, + QPainter *p, + const QRect &r, + const QColorGroup &cg, + SFlags flags, const QStyleOption& opt ) const +{ + switch( pe ) { + case PE_HeaderSection: + if ( flags & Style_Sunken ) + flags ^= Style_Sunken | Style_Raised; + // fall through + case PE_ButtonBevel: + case PE_ButtonCommand: + drawMetalButton( p, r.x(), r.y(), r.width(), r.height(), + (flags & (Style_Sunken|Style_On|Style_Down)), + TRUE, !(flags & Style_Raised) ); + break; + case PE_PanelMenuBar: + drawMetalFrame( p, r.x(), r.y(), r.width(), r.height() ); + break; + case PE_ScrollBarAddLine: + drawMetalButton( p, r.x(), r.y(), r.width(), r.height(), + flags & Style_Down, !( flags & Style_Horizontal ) ); + drawPrimitive( (flags & Style_Horizontal) ? PE_ArrowRight :PE_ArrowDown, + p, r, cg, flags, opt ); + break; + case PE_ScrollBarSubLine: + drawMetalButton( p, r.x(), r.y(), r.width(), r.height(), + flags & Style_Down, !( flags & Style_Horizontal ) ); + drawPrimitive( (flags & Style_Horizontal) ? PE_ArrowLeft : PE_ArrowUp, + p, r, cg, flags, opt ); + break; + + + case PE_ScrollBarSlider: + drawMetalButton( p, r.x(), r.y(), r.width(), r.height(), FALSE, + flags & Style_Horizontal ); + break; + default: + QWindowsStyle::drawPrimitive( pe, p, r, cg, flags, opt ); + break; + } +} + +void MetalStyle::drawControl( ControlElement element, + QPainter *p, + const QWidget *widget, + const QRect &r, + const QColorGroup &cg, + SFlags how, + const QStyleOption& opt ) const +{ + switch( element ) { + case CE_PushButton: + { + const QPushButton *btn; + btn = (const QPushButton*)widget; + int x1, y1, x2, y2; + + r.coords( &x1, &y1, &x2, &y2 ); + + p->setPen( cg.foreground() ); + p->setBrush( QBrush(cg.button(), NoBrush) ); + + + QBrush fill; + if ( btn->isDown() ) + fill = cg.brush( QColorGroup::Mid ); + else if ( btn->isOn() ) + fill = QBrush( cg.mid(), Dense4Pattern ); + else + fill = cg.brush( QColorGroup::Button ); + + if ( btn->isDefault() ) { + QPointArray a; + a.setPoints( 9, + x1, y1, x2, y1, x2, y2, x1, y2, x1, y1+1, + x2-1, y1+1, x2-1, y2-1, x1+1, y2-1, x1+1, y1+1 ); + p->setPen( Qt::black ); + p->drawPolyline( a ); + x1 += 2; + y1 += 2; + x2 -= 2; + y2 -= 2; + } + SFlags flags = Style_Default; + if ( btn->isOn() ) + flags |= Style_On; + if ( btn->isDown() ) + flags |= Style_Down; + if ( !btn->isFlat() && !btn->isDown() ) + flags |= Style_Raised; + drawPrimitive( PE_ButtonCommand, p, + QRect( x1, y1, x2 - x1 + 1, y2 - y1 + 1), + cg, flags, opt ); + + if ( btn->isMenuButton() ) { + flags = Style_Default; + if ( btn->isEnabled() ) + flags |= Style_Enabled; + + int dx = ( y1 - y2 - 4 ) / 3; + drawPrimitive( PE_ArrowDown, p, + QRect(x2 - dx, dx, y1, y2 - y1), + cg, flags, opt ); + } + if ( p->brush().style() != NoBrush ) + p->setBrush( NoBrush ); + break; + } + case CE_PushButtonLabel: + { + const QPushButton *btn; + btn = (const QPushButton*)widget; + int x, y, w, h; + r.rect( &x, &y, &w, &h ); + + int x1, y1, x2, y2; + r.coords( &x1, &y1, &x2, &y2 ); + int dx = 0; + int dy = 0; + if ( btn->isMenuButton() ) + dx = ( y2 - y1 ) / 3; + if ( btn->isOn() || btn->isDown() ) { + dx--; + dy--; + } + if ( dx || dy ) + p->translate( dx, dy ); + x += 2; + y += 2; + w -= 4; + h -= 4; + drawItem( p, QRect( x, y, w, h ), + AlignCenter|ShowPrefix, + cg, btn->isEnabled(), + btn->pixmap(), btn->text(), -1, + (btn->isDown() || btn->isOn())? &cg.brightText() : &cg.buttonText() ); + if ( dx || dy ) + p->translate( -dx, -dy ); + break; + } + default: + QWindowsStyle::drawControl( element, p, widget, r, cg, how, opt ); + break; + } +} +void MetalStyle::drawComplexControl( ComplexControl cc, + QPainter *p, + const QWidget *widget, + const QRect &r, + const QColorGroup &cg, + SFlags how, + SCFlags sub, + SCFlags subActive, + const QStyleOption& opt ) const +{ + switch ( cc ) { + case CC_Slider: + { + const QSlider *slider = ( const QSlider* ) widget; + QRect handle = querySubControlMetrics( CC_Slider, widget, + SC_SliderHandle, opt); + if ( sub & SC_SliderGroove ) + QWindowsStyle::drawComplexControl( cc, p, widget, r, cg, how, + SC_SliderGroove, subActive, opt ); + if ( (sub & SC_SliderHandle) && handle.isValid() ) + drawMetalButton( p, handle.x(), handle.y(), handle.width(), + handle.height(), FALSE, + slider->orientation() == QSlider::Horizontal); + break; + } + case CC_ComboBox: + { + // not exactly correct... + const QComboBox *cmb = ( const QComboBox* ) widget; + + qDrawWinPanel( p, r.x(), r.y(), r.width(), r.height(), cg, TRUE, + cmb->isEnabled() ? &cg.brush( QColorGroup::Base ) : + &cg.brush( QColorGroup::Background ) ); + drawMetalButton( p, r.x() + r.width() - 2 - 16, r.y() + 2, 16, r.height() - 4, + how & Style_Sunken, TRUE ); + drawPrimitive( PE_ArrowDown, p, + QRect( r.x() + r.width() - 2 - 16 + 2, + r.y() + 2 + 2, 16 - 4, r.height() - 4 -4 ), + cg, + cmb->isEnabled() ? Style_Enabled : Style_Default, + opt ); + break; + } + default: + QWindowsStyle::drawComplexControl( cc, p, widget, r, cg, how, sub, subActive, + opt ); + break; + } +} + + +/*! + Draw a metallic button, sunken if \a sunken is TRUE, horizontal if + /a horz is TRUE. +*/ + +void MetalStyle::drawMetalButton( QPainter *p, int x, int y, int w, int h, + bool sunken, bool horz, bool flat ) const +{ + + drawMetalFrame( p, x, y, w, h ); + drawMetalGradient( p, x, y, w, h, sunken, horz, flat ); +} + + + + +void MetalStyle::drawMetalFrame( QPainter *p, int x, int y, int w, int h ) const +{ + QColor top1("#878769691515"); + QColor top2("#C6C6B4B44949"); + + QColor bot2("#70705B5B1414"); + QColor bot1("#56564A4A0E0E"); //first from the bottom + + + int x2 = x + w - 1; + int y2 = y + h - 1; + + //frame: + + p->setPen( top1 ); + p->drawLine( x, y2, x, y ); + p->drawLine( x, y, x2-1, y ); + p->setPen( top2 ); + p->drawLine( x+1, y2 -1, x+1, y+1 ); + p->drawLine( x+1, y+1 , x2-2, y+1 ); + + p->setPen( bot1 ); + p->drawLine( x+1, y2, x2, y2 ); + p->drawLine( x2, y2, x2, y ); + p->setPen( bot2 ); + p->drawLine( x+1, y2-1, x2-1, y2-1 ); + p->drawLine( x2-1, y2-1, x2-1, y+1 ); + + +} + + +void MetalStyle::drawMetalGradient( QPainter *p, int x, int y, int w, int h, + bool sunken, bool horz, bool flat ) const + +{ + QColor highlight("#E8E8DDDD6565"); + QColor subh1("#CECEBDBD5151"); + QColor subh2("#BFBFACAC4545"); + + QColor topgrad("#B9B9A5A54040"); + QColor botgrad("#89896C6C1A1A"); + + + + if ( flat && !sunken ) { + p->fillRect( x + 2, y + 2, w - 4,h -4, topgrad ); + } else { + // highlight: + int i = 0; + int x1 = x + 2; + int y1 = y + 2; + int x2 = x + w - 1; + int y2 = y + h - 1; + if ( horz ) + x2 = x2 - 2; + else + y2 = y2 - 2; + +#define DRAWLINE if (horz) \ + p->drawLine( x1, y1+i, x2, y1+i ); \ + else \ + p->drawLine( x1+i, y1, x1+i, y2 ); \ + i++; + + if ( !sunken ) { + p->setPen( highlight ); + DRAWLINE; + DRAWLINE; + p->setPen( subh1 ); + DRAWLINE; + p->setPen( subh2 ); + DRAWLINE; + } + // gradient: + int ng = (horz ? h : w) - 8; // how many lines for the gradient? + + int h1, h2, s1, s2, v1, v2; + if ( !sunken ) { + topgrad.hsv( &h1, &s1, &v1 ); + botgrad.hsv( &h2, &s2, &v2 ); + } else { + botgrad.hsv( &h1, &s1, &v1 ); + topgrad.hsv( &h2, &s2, &v2 ); + } + + if ( ng > 1 ) { + for ( int j =0; j < ng; j++ ) { + p->setPen( QColor( h1 + ((h2-h1)*j)/(ng-1), + s1 + ((s2-s1)*j)/(ng-1), + v1 + ((v2-v1)*j)/(ng-1), QColor::Hsv ) ); + DRAWLINE; + } + } else if ( ng == 1 ) { + p->setPen( QColor((h1+h2)/2, (s1+s2)/2, (v1+v2)/2, QColor::Hsv) ); + DRAWLINE; + } + if ( sunken ) { + p->setPen( subh2 ); + DRAWLINE; + + p->setPen( subh1 ); + DRAWLINE; + + p->setPen( highlight ); + DRAWLINE; + DRAWLINE; + } + } +} + + + +int MetalStyle::pixelMetric( PixelMetric metric, const QWidget *w ) const +{ + switch ( metric ) { + case PM_MenuBarFrameWidth: + return 2; + default: + return QWindowsStyle::pixelMetric( metric, w ); + } +} + +// ************************** +// --- Plugin - interface --- +// ************************** + +class MetalStylePlugin : public QStylePlugin +{ +public: + MetalStylePlugin(); + + QStringList keys() const; + QStyle *create( const QString& ); +}; + +MetalStylePlugin::MetalStylePlugin() +: QStylePlugin() +{ +} + +QStringList MetalStylePlugin::keys() const +{ + QStringList list; + list << "Metal"; + return list; +} + +QStyle* MetalStylePlugin::create( const QString& s ) +{ + if ( s.lower() == "metal" ) + return new MetalStyle(); + + return 0; +} + +Q_EXPORT_PLUGIN( MetalStylePlugin ) + +#endif diff --git a/plugins/styles/metal/metal.h b/plugins/styles/metal/metal.h new file mode 100644 index 0000000..ae11a61 --- /dev/null +++ b/plugins/styles/metal/metal.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** $Id: metal.h,v 1.1.1.9 2006/05/07 17:31:30 chehrlic Exp $ +** +** Definition of the Metal Style for the themes example +** +** Created : 979899 +** +** Copyright (C) 1997 by Trolltech AS. All rights reserved. +** +** This file is part of an example program for Qt. This example +** program may be used, distributed and modified without limitation. +** +*****************************************************************************/ + +#ifndef METAL_H +#define METAL_H + + +#include + +#ifndef QT_NO_STYLE_WINDOWS + +#include + + +class MetalStyle : public QWindowsStyle +{ +public: + MetalStyle(); + void polish( QApplication*); + void unPolish( QApplication*); + void polish( QWidget* ); + void unPolish( QWidget* ); + + void drawPrimitive( PrimitiveElement pe, + QPainter *p, + const QRect &r, + const QColorGroup &cg, + SFlags flags = Style_Default, + const QStyleOption& = QStyleOption::Default) const; + + void drawControl( ControlElement element, + QPainter *p, + const QWidget *widget, + const QRect &r, + const QColorGroup &cg, + SFlags how = Style_Default, + const QStyleOption& = QStyleOption::Default ) const; + + void drawComplexControl( ComplexControl cc, + QPainter *p, + const QWidget *widget, + const QRect &r, + const QColorGroup &cg, + SFlags how = Style_Default, + SCFlags sub = SC_All, + SCFlags subActive = SC_None, + const QStyleOption& = QStyleOption::Default ) const; + int pixelMetric( PixelMetric, const QWidget * ) const; + + +private: + void drawMetalFrame( QPainter *p, int x, int y, int w, int h ) const; + void drawMetalGradient( QPainter *p, int x, int y, int w, int h, + bool sunken, bool horz, bool flat=FALSE ) const; + void drawMetalButton( QPainter *p, int x, int y, int w, int h, + bool sunken, bool horz, bool flat=FALSE ) const; + QPalette oldPalette; +}; + +#endif + +#endif diff --git a/plugins/styles/metal/metal.rc b/plugins/styles/metal/metal.rc new file mode 100644 index 0000000..20ead13 --- /dev/null +++ b/plugins/styles/metal/metal.rc @@ -0,0 +1,97 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,0,0,0 + PRODUCTVERSION 0,0,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Vladimir Shutoff\0" + VALUE "FileDescription", "metal\0" + VALUE "FileVersion", "0, 9, 5, 0\0" + VALUE "InternalName", "metal\0" + VALUE "LegalCopyright", "Copyright © 2002-2003\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "metal.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "SIM\0" + VALUE "ProductVersion", "0, 9, 5, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/styles/metal/metal.vcproj b/plugins/styles/metal/metal.vcproj new file mode 100644 index 0000000..aa76570 --- /dev/null +++ b/plugins/styles/metal/metal.vcproj @@ -0,0 +1,264 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/styles/metal/metal.xpm b/plugins/styles/metal/metal.xpm new file mode 100644 index 0000000..0d72650 --- /dev/null +++ b/plugins/styles/metal/metal.xpm @@ -0,0 +1,130 @@ +/* XPM */ +static const char *metal_xpm[] = { +/* width height num_colors chars_per_pixel */ +" 154 77 46 1", +/* colors */ +". c #040204", +"# c #4c4e4c", +"a c #6c767c", +"b c #5c6264", +"c c #848a8c", +"d c #545a5c", +"e c #7c8284", +"f c #646e74", +"g c #3c3e3c", +"h c #444644", +"i c #8c9294", +"j c #4c565c", +"k c #7c7e84", +"l c #646a6c", +"m c #747e84", +"n c #4c525c", +"o c #74767c", +"p c #64666c", +"q c #8c8e94", +"r c #5c5e64", +"s c #84868c", +"t c #6c6e74", +"u c #444244", +"v c #4c4a4c", +"w c #4c5254", +"x c #5c666c", +"y c #848e94", +"z c #545e64", +"A c #7c868c", +"B c #3c4244", +"C c #444a4c", +"D c #8c969c", +"E c #747a7c", +"F c #6c7274", +"G c #4c4e54", +"H c #5c626c", +"I c #848a94", +"J c #545a64", +"K c #7c828c", +"L c #3c3e44", +"M c #44464c", +"N c #8c929c", +"O c #54565c", +"P c #646a74", +"Q c #747a84", +"R c #6c727c", +/* pixels */ +"DNDDDDDDDDDDNDNDNDNNiNNiNiNyiyiyqyyyyIyIcIcIcAsAsAAKAKeKememkmmmQEQEEaoaoaaFRFFFftftlfPllllpxpxpxHbbbrbrzrzrJddddOdOOjOjOnwwwwwGwGG#GCGC#CCCCCCCMCMMMhMBhB", +"DDDNDNDNDNDNDDNDiDNDNDiyNNiNNyNyiyqyqyIyIIcIcIAcAsAseAKeKekemkmkEmEQEEoaoaoRFRFFtFtftltlPllplpxpbpbHbbrbrrzrdrdJdddOOOOjOwOwOGwwwGwGGGCGCG#CvCCMCMCCMMMMMM", +"NNDNDNDNDNDNDiDNDNiNiNNDNNyNyqNqyqyqycyIcIcIAIAsAsAKAKKeKkKmkmkEmQQoQoEaoFoaFRtRFftftfPlPpllpxpbpbHbbbbrzrrdrdrdddOddOOwOOwOwwwwGwGwCGwCGGCvCCvCCChCMCBhMB", +"DDiDNDNDNDiDNNNiNNDiNyNiyNiyNyyNyyyIqIIcIcIAIcAsAAseKeKemKmkmkQmEEQEoaEaoaFRoFFtttftltlPlPppxppxbpbHbrrrrzrzrdddJdOdjOOOjwOwwOGwGwGGw#CGGCvCvCCCMMCMhCMCBM", +"iNNNiNiNiNNiDNDNNiNyNiNiNyNyiyqyqIqyIIyIcIcIcAsAsKAKAKeKeekmkmEkQQEEQaooaRoFFtRFFftltflPllllppxpHbpbHbbzrrdrdrOrOddOOjOwOOGOwGwwGwGwCGGCGCCGCCMvCCMCMMhMMB", +"NiNNNNNNNNiNiNiNiNNNiyNyiqyNyqyyyyIyIcIcIAcAsAsAAAseKeKmkmkmkQmEEQEoaEaoRoFRRFtfttftlPtllppxpxpbpbbrbrrbrzrdddddOdOOdOOwOwwOGOGwGGGGwCGGCGCCvCvCMMCMhMBChM", +"iNNiiNiiNiNNiNiNyiyNyNyNyyqyqyyqIqycIcIcIsIsAsAAseKeKeeeKmkmmkQQQoEQooaoFaFRFFRFtftPtlllPplpxpbpbbHbbbrrzrrdrdrdddOdwOOjOwOwwwwGwGwCGGGCGCGCGCCCMCMCMCMMMB", +"NyNiNiNiNiNiyNiyNNyiNyqyNyyqyyqIIIIIcIcAIAcAsAsKAKKeKkmkmkmkQEQEEQaoaoaaoFRFFtftftflPlPllpxppxpbbpbbrbrzrrdrdOJOdOOOOOwOwOwwOGwGwGGw#CGCGCvCCCvMCMMMhMhBMh", +"yNiyNyNyiyNyiNyNiyqyyiyqyqyyyIIIycIcIAsIcAsAsAKAeKeKeeKmkmkmEmQEQoEEaoRoRFRFRtFttltftlPlplppxpbpbHrbbrrrrdrddrOrdOdOdwOwOwOGwGwwGGwCGwCGCGCCvMCCMCMCCBMMMB", +"qyNyiqyNyNyNyyqyyNyqyyqyyyqIIyIycIcIcIAcAsAAAKsKKeKemkmkmkmQkEEQEoaoaoaFFRFFtRftftlPllllpxpxpbbHpbbrrrzrzrdJrOdOOdOjOOOwOwwwOGGwGG#GGCGCGCvCCvCMCCMhMCMBMh", +"NyqyqyNyqyqyqyNyqyqyqyyIqIIyIcIcIIcIAsIAsAsAsAeAKeKkKkKmkmEQEQEQaoEaoaRFoRFRfttftPflPlPplpxppHpbbrHbbzrrzrdrdddddOOdwOwOwwOwGwGwGwCwCGGCGCCGCCCCMMCMMMMhMB", +"yqyqyyqyqyqyqyqyyqyyIyqIyIyIcIIcIsAIcAsAAsAKKKKeeKmemmmkmQkQEQEoEaoaoFoFRFFtFtftftltlllpplpxbpbHbbbrrrzrdrdddJdOdOOOOjOwOwwwwwGwGGGGGCGCGCvCCGMMCMMhMBCBMB", +"yyyyyqyyqyyqyyyqyyyIyIyIIcIcIIcIAIcAsAsAsKAeAKeKekKmkkmQkmQEQEoQaooaoaFRFRtFttftPlPllPplpxpxpbpbbHrbzrrrrdrdrOddOdjOwOwOwwOGOGwGw#GGCGCGCCGCCMCCMChCMMMhMB", +"IqyqyyqyyyqyyqIIIIqIIIIcIIcIccIscAsAsAAAKAsKeeKekmekmmkmEEEQEEoaoaoaRFoFFFtftftltlPlPplpxpxpbbbHbrbrrzrdzddddddOOOOOOwOwO#wGGwGGGCw#GCGCvCCvMCMCMMMMBCBMBM", +"IyIIIIIIIIIIIIyIyIIIyIcIccIcIcAIAsAsAAsKsKKeKeKmeKmkmkEmQQQEQaoEaoaRoFRFRtRFtftfltlPlplxpppbbpHbbbrbrrzrdrdrJOdOdOdwOwOwwwOwwGwwGwCGCGCGCCGCCCvMCMCMMhMhMB", +"IIIyIyIyIyIyIyIcIcIccIcIcAIAcAsAsAsAsKKAeKeKekKkkmkmkmQkEEEQoEoaoaoFRFRtFftftftlPlllplppxxpbpbbbrHrzrzrdrddOddOOOjOOwOwOwwGwGwG#GGGCwCGCvCCMvMCMMMhMBMBMBh", +"cIcIcIcIcIcIcIcIcIcIcIcIAscsAIAsAAsAKAKeKeKkeKmemkmkQmQEQEQoEoaoaoFRRFFRtFttltPltPpPlppxppbpbHbHrbrrrrdrdrOrdOddOdwOjOwOGOwwGwGGwCGGvGCGCCvCCCMCMCMhCMMhMB", +"IcIcIcIcIcIcIcIcIcIAIAcAIAAsAsAsAsKAKseKeKeKmkkmkmmQmkEQEEoaEaoaaRaoFFtFftftfPtllllppxppxbpbbbbbrrzrzrdrdddOdOdOOOOwOwwO#wGwGwG#CwCGCCvCvCCCMCMCMMMBMBhBMh", +"IAccIcIcIcIcIccIAIAscsAsAIsAsAsAAKAeKeKeKemkemkmmkQkEQEEQoQoaoaoFoFFFRtRttftltllPlPllppxppbHbpHrbbrrrdrddrddOdOOOjOOwwOwwwwGwGGwGGGCGCGCCCvCvMCMhCMMhMMMBB", +"csAIAsAsAsAAsAsAcsAIAAsAsAAAAAKKsKKKeKeKkeKmkmkmkQmEQEQoEaoaoaoRRFRFRtfFftftPlPlPlppxpxpbbHprrbrrzrzrdrdrOOddOOjOwOwOwO#OGwGwG#CwCGGCGCGCGMCMCMMMMBCBMBMhB", +"IAsAIAIsIAsIAIAIAsAsAsAsAsAsKsAKeAeeKeKemkmkmkmkQmEQEQEaQoEaoaFoRFRtFFtttftlfltPplplppxpHpbbbbrbbrzrrdrdOdddOdOOOOwOwOwwGwGwGGwGGGCGCvCvCCMCCMCMCMhMMhMBMB", +"sAsAsAsAsAsAsAsAsAsAsAAAKAKKKeKeKeKeekmKkmkmkmQmEQEQEEoEaoaoaoRFaFFRttftftltlPlpllpxpxpbxbpbHrbrrrrdzdrdrOdOdOjOjOwOwwwOGwwGGGCwGCGCGCCCGMCCMCMMhMBMBMBhBu", +"sAAsAsAAAsAAsAAsAAAAAsKsKKsAeKKeKeeKkKmkmkmkmmQEkEQEoQaooaoaRFoRFRFFfFtftftlPlPlplpxpbpbpbbrbrbrzrzrdrdOddOdOOOOOOwOwOwwwwGwGwGGGCGGCGCGCCMvCMMCMMCMMBMuMB", +"AAsAAAAsAAAsAAsKAsKKAKKKeKeKeKeKekkmmemkmmkQmkEQEQEEoEoaoaoRoFRFFttRtftfftlPtllpPpxpxpbbHbHbbrrzrzrdrddrOddOOjOwOwOwO#wGOGGGw#CGCGCCvCvMCvCMMMCMhBMhhMBMBu", +"KKAKKsAKKsAKAKKAKKKKKeAeKeKkKeeekKmKmkmkmkmQEEQEQEoQaoaoaoFaFRFFRFFtfttltlllllplpxpppbpbpbbrbrbrrrdrdrdddOdOdOOOwOwOwGOwGGwGwCwGGCGGCGCCMCMCCMMMMCBMBMBMBB", +"eAeKKeKKKKKKeKAeKAeeKeKeKeeKkmkmKmkmkmkmQmEQQEQEooQaooaoaRoFRFRFttfttfftlPPlpPppxppxbxbHbrbbrzrzrdrddddOddOOjOwOwOwwwOGwGwGGGGGC#CGCCCvCGMCMMCMhMMMhBMhBuB", +"eKeKeKKeKeeKeKeKeeeKeKeKeKmemkKkmkmkmkQQkEkEEQoEQEaEaoaFoaRFRFFRftFftftPltlPlllxppxpbpbpbHbrbrrzrzdrdrdJOdOdOOOOwOwOwwwwGwG#wCGGCGCvCGCCMCMCMhMMCBMBMBMBMB", +"KeKeKeeKeKeKeKeKeKeKekkkmekmKmmkmmkQQmEQEQEQEEoQaooaoaoRFFFRFFtFtftftlllPllpppppxpxbpbbrbrbrrzrrdrdddOddOdOjOwOwOwO#wGwGwGGGCwGCGCGCvCCvCMCCMCMhBCMhBMBuBu", +"kkKeeKeKeeKeKkKkkkkkKmKmkkmkmkkmmkEmmEkQEQEQoQaoaoaoaaFoFRRFFRtFfttltPtfllPllxlpxpbpbpbHbrbrzrrdrdrdrddOdOOOOdwOwOwwGOwwGw#wGGCGCGCGCCCMCMCMMMMMMhMBMMBMBB", +"KmekmekekKmememKmKmemkmkmmkmmmmkQQmkEEQEQoEoaEoEaoaaoFRRFFFRttfttfftllllPlppppxpxpbbHbbrbrrrrzrzdrOddOddOOjOwOwOwwOwwGGGGGCGCGG#CGCCvCvCMCMMChMBMBMMBhBuBu", +"ekmKkmkmkmkkkmkkmkmkmkmkmkmkmkQQEQEEQEQoEEaQoaoaoaoFRFoRFRFtFtFftPtfPltPplplxppxpbbpbHbHrbzrzrrdrdddJddOOdOOOjOwOw#OwwGwwGwGwCGCGCCGCCMCvMCMMMhCMMBMBuBMBB", +"kmkmkmkmkmkmkmkmkmkmkmmkmQmQQEEmkEQEQEEoQooaooaaRoFRoFFFFttFftftftlltllplPpppxpxpbpbbrbrbrrrzrdrddrOdOOOdjOwOwOwwOGGwGwG#GCGCG#CvCvCMGMCMCMMCMBMBMhBMBMBuB", +"mkmmmkmmkmmkmmkmmkmmmkQmQkQEkQEQEEQoEooEaEaoaoaoFaRFFRtRtRtfttftPltPllPllplxpxpbpHbbHbrbrrzrdrddrddOdddOOOOOwOwOwwwwwGwGGGGGGGCGCCGCCMCMCMChMhCMMBMMBuBuBB", +"QQQkQmkmmkmmkQQmkQQkEQEQEQEQEEQEoQoEoaQaoaoaaaoFRoFRFFFtFfttfftlftllPplppxpxpxpbbbprbrbrrrzrzdrdddddOOOjOjwOwOwwOGwOGwG#GCwC#CGCGCCvCCCMCMMMMBMBhMBhBMBMBu", +"EkmEkQQkQQkQQEkQEEQEmQkEQEQEEQoEQoEaQaoaoaoaoRFRRFFFRtRftFftftltllPllPlxppxpbpbbpbbHrbrbzrrdrrddrOdOdOdOOOOwOwOwwwGGGGwGwGGGCGCvCCvCCMvCMMCMhMMMMBuMBuBuBB", +"QEQEQEQEQEQEmQEQmEQEQEEQEEQEoEaQaoaooaoaoRRFFoFRFFRFtFtFftftlPflPlplppppxpxpbxpbbbrbbrrrrzrzdrddOdJOdOOjOwOwOwwOGwwGwG#CGCGCGCGCGCCMvCMMMCMhBCBhBMBMBMBBuB", +"EQEQEQEQEQEQEEQEEEQEEQEEQEoQaQooEaoaoaoaFoaoRFRFFRtFftftftftltltlPlPplxppxpbpbbHbHbrbzrzrdrdrddOrdOdOjOdwOwOwwOwGwGwGGwGwC#GCGCvCMGCCMCCMMMMMMMBMMBMBuBuBB", +"QEEQEEQEEQEEQEQEQEEQooaooaoaooaoaoaaaoRFoFFFRFFFttFttftftPtlPllplpplpxppxpbHbpbbrbrbrrrzrzdrddrOdOdOOOOwOOwOwO#wO#wGGwCGGGCGCGCCvCMCMCMMMChBChMMBhBMBBuBBB", +"EaoEoEoQoEoQoEoEoooEaEoQaoEoaoaoaoaoRFoRFRRRFtRtRttfttftltPltlPlPllpxppxpxbpbbbHbrbrrrzrrdrOrdOdOdOdOjOOwOjwOwwGGwGwGGG#GCGCGCCGCCvCMCMChMMMMBhBMBMBuuBBuL", +"oQaoaoEaEoaEoaoaoaQaoaoaoaaoaaoRRoFFRFRFRFFFFtFtfFftftftlPlPlPlpppplpxxpbpbbHbrbrbrrzrzrdrddddddOdOOOOwOwOwwwwOGwGwG#CwCGGCGCvCCCGMCMCMMMMBCMMBMhBuBBBuBBB", +"oaoaQoaooaEaoQaooaoaoaoaoaoaoaFoaRFoaRFRFFRttRfttftftltfPltlllplllxpxpxpxbHbpHbrbrbrzrrdzddrdOdOdOOjOjOwOwO#OwGwGwGGGwGGGCGCGCCvCMCMCMMChMMMhBMMBMBuMBuBuL", +"oaoaoaoaaoaoaoaoaoaoaoaaoRFRFoFRFFRFFFFFttFtFttftftfltlllllpPplppxppxpbbpbbbrbrbrrzrrzdrdrddOddOOOOOOOwOwwOwGwwGwGGwCGCGCGCGCvCCCCMvMMCMMBCBMMBhBuBBBuBBBB", +"FoaoaaaoaoaoaaoaaoRoaRoFFoRoRFRFRFFRtRttFRtfftftftltflPltlPlplppxppbpbbpbbHbbrbrzrrzrdrdrddddOdOdjdwOwOwOw#OwwGwGwG#GGwCGCGCvCCMvCCMCMMhMMhMhBMBMBMBMBBuBL", +"aRaFaoRoRRoRoFaFoFaFRoFRaFFFRFFRFFFFtFtftfttftfftlPlPtlPpplplpxpxpxpbpbbbprbrbrrrzrzdrdddOrOOdOOOOOjOwOwwOwGwwGwG#GCwCG#CGCCCGCGMMCMMMCMBCBMBMuBMBuBuBuLBB", +"RFoFoRFFoRFRFRoFRRFRFFFRFFRFFRFFRttRttFfttfftfltPltPllpllplpxppxpbpHbHbHbrbrbrbzrrdrdrdOrdOdOdOdOOwOwOwOwwwwwGwGGwGGGGCGCvCvCCCMCMCMCMMhMMMhMMBMBuBBuBLBBL", +"RFRFFFRRFFaFRFFRFRoFRFRFRFFRFtFtFttftfttfftftltllPllPlPplppppxpxpbxpbpbbHrbrrzrrzrzdrddrOOdOdOOjOjOOwwOwwOGwGwGG#CwCGCGCGCGCCvMCCMCMMMBCBMBuBMBuBMBMLBuBLB", +"RFtRFRFFFRFFFRFRFFtFRFtFtttttRttfFftftftftltlPlPllPllpplxlxpxpbpbpbbbrHrbrbzbrzrdrdrdddOddOdOdOOwOOwOwwOwGwGwGwGwGGGC#GCGCCvCCCvMCMChCMMMMBMBMBMBuBBuBLuBL", +"tFRFtFRFFFFRFFFtRFtFtFtRtFtfFftfttftftfltlflPtllPllplplppxpxpxpbHbprbbbrbrrrrzrrzdrddrOddOdOOjOOOwwOwOw#wwO#GGG#GCGCGCGCCvCCCvMCMCMMMMBhBMMhBMBuBBuBBBBBLB", +"fFtFtFtttttttttFtFtRfttftfFtfttftftftltfPltlllPlllpPpxpxppxpbpbbpHbbbHrbrbzrzrdrdrdrOdddOdOOOOjOwOwOwwGOwGGwGwGwCGGGGCGCvCCvCMCMCMMMMhMMhMBMBuBuBMBBuLuLBL", +"ttfttttRtRtFtfRftftftfttftftftftfltlPllltlPlPlllpPppppxpxpxpbHpbbbrHrrbrrrrzrzrdrdOdddOdOOdjOjOOwOwwOwwGwGwGG#GCwGC#CGCvCCGMCMCMMMChBCBMBMuBMBMBBuBLBBBLBL", +"tfttfftfftffttftttftftftftftftPltflPltPPlPlplpplpplxpxppxpbbpbbHbHbbrbrrrzrzrdrdddrdOddOdOOOwOOwOwwOw#OwwGwGGGGwCGCGCvCCGCMCCCMCCMMMMMCBhMBMBuBuBBuBuLuLBL", +"ftffttftftftftftfftftftfftlltlftlltlPlllplpPplppxpxpxpxbpbbpbbbrbrrbrrzrzrzdrddrddOddOdOOjOOOwwOwOwwwGGGwGG#GCwGGCGCGCGCCCvCMMCMMMhBCuMMBMBMBMBBMBBBBBLBLL", +"ltftffftftftfftfPtltltltlltPlPlllPlPlllPplplppxpxppxpbpHbpHbbHbHrbbrbrrzrrdrdrdddOddOdOdOOjOwOOwwwOGOwwwGwGwGwCGCGCGCvCCvCMCMCMMMMCMMBMBMBMBuBuBuBLuBLBLBg", +"PlPtltlltltltlltlflPlPlPlPllPtlPlplplpplpppxpxppxpxpbxpbbbbbprbrbrrrzrzrzdrdrOdrOdOdOOOjOjOOwOwOwwwwGwGwG#GCG#GCGCGCCCvCMCCMCMMCMhBMMhBMhBMBMBBuBLuBLBuLLL", +"ltllPltlPlPlPltPltltlfPlltlPlplplPlpPpPpplxpppxpxpbbpbbrpbHbrbrbrrrrzrrdrdrddddOddOdOdOdwOOwOwwwwOGwwGwGGwGwCGC#GCvCvCCGCMvCMCMhMMCBMBMMBMBuBBuBBBBLBLBLBg", +"lPlPllPlPlPllPlllPllPtllPplllPplpplpppxpxppxxpxpbpbpbbpbrbrrbrrrrzrzrzrdrddrOdrOOdOOOjOOOwwOwOwOw#wO#wGG#GCwGCGCCGCCGCCMCMCMMMMMhBMMhBMBhBuBuBBBMLuBLBLLLL", +"lllllPlPllPlPllPplpllppllplplplplpplxpxppxxppbpbpbHrbHbrbHbbrbzrzrrzrdrddrdddOdOdOOdOOjOwOOwOww#OwwGGGGwGGwCGGCGGCCvCCCMvCMCMCMMMMhMBMMBuBMBuBuBLBBLuLBLBg", +"lpPlPllllPlllPplPlpPpllpPplpppxpxpxppxpxpxpbxbbbbbpbbbbHrrrrrrrzrzrdrddrOdOdddOdOOdjOjOOwOwwwOwwGGGwGw#GCG#GCGCGCGCCCvCCMMCMMMhBCBMBMBhBMBBuBBBuLBLBLBLgLL", +"PplppppppppppplplplplppppppxlxpppxpxxpxpbpbpbpbpHbrHrbrrbrbzrzrrzrdrdrdOrdOrOOdOdjOOOwOwOwwOww#OwwGwGGGGwCGCGCGCCCCGCCMCMCMMCMMMMCBhMBMBuBuBBMBLBuBLBLLBLg", +"pppplplplplplppppppxpxlxxpxppxpxxpbppbbpbbbbbbHbrbbbrHrbrzrrzrzrdrdddddddOdOOdOOOOjOwOwOwOwwO#wGGwG#G#CGGGCGCGCvCvCMCMCMCMMMhMBChBMMBMBuBuBuBLBuBLLBLLgLLg", +"pxxpxpxpxpxpxpxpxpxpppxppxpxpxpxpbpbbpbbHbpHrprbbHrrbrrzrrrzrzrdrdrdrdrdddOdOOdjOOwOOwOwwwOwwGwwGwGwGGwCGC#GCvCCvCCvCMvCMMCMMMhMBMMBMBMBMBBBBuLBLBLBLBLBLg", +"xppxpxpxpxpxpxpxpxpxxpxpxpxpbpbpbHbHpbHprbbrbrbrrbrbrrrrzrzrdrddrdOddOOdOOdOdOOOjOOwwOwOwwGwGwGwGG#GCwGGCGCCGCGCCCvMCMCMMMMhBCBMhBhBMBuBBuBMLBBuLBuLLgLgLL", +"xpxpxpxpxpxpxpxpxpxpbpbpbbpbbbbbpbpbbbbbbbHbHrbbrrrrzrzrrdrdrddrddrdOdddOdOOjOjOOwOwOwOw#OwGOwGwGwGGG#GCGCGGCvCCGMCCMCMCMCMMMMMMBMBMBuBuBMBBLuBLBLLgBLBgLg", +"bpbpbpbpbpbpbpbpbpbpbxpbHpbHpHprbbbHbrHrbrrrbrrrbzrzrrzrzrddrdrOddOddOOdOOOOOjOwOwOwwO#wOGGwGGGG#GCwCGCGCGCCCCvCMCCMCMMMMhBCBhBMhBMBuBBuBBuLBBLBLBLBLgLLgL", +"pbbbbpbbpbbpbbpbHbbbpbbpbbbbbbbbbHbbHbrbrbbrrrbzrrzrrzrdrddrddddddddOdOOdOOjOwOOwOwwOwwwGwwwGwGwGG#GGCGC#CGCGCCvCMvCMCMCMMMhMMMBMBuBMBMBuBLBuLLuBLLLBLgLLg", +"bbpbbbbpbbpbbpbbpbpbbHbbHbprbrHrHbrrrbrbrrrbzrzrrzrzdrdddrddrOddOdOOdOOdjOjOOOwwOwOwwwOGwGGw#GG#CwCGCGGCGCvCCvCCCMCMMMMMhBCBMBMhBMBMBuBBBBuBBLBLLLBgLgLLgL", +"bHbbpbHbbHbbHrbHbbrbHbrbrbrbHbbrbrbbrrrrbrrzrzrrzrdrdrdrdOrOddOdJOdOOOjOOOOOwwOwOwwwOwGwGwwGGwGGGGC#GCGCvCCvCCMCMCMCMChMMMMMBhMBMBuBuBBMLuLBLuBLBgLLgLLgLg", +"bbrHrbrHrbrHbbHrbHbbrbHbrHrbrrbrrrrrbrzrzzrrzrddrdrdrdddrdddddOdOOOdOOOjOwOwOOwwwOww#wwGwGGG#GCwCGGCGCvCCGCCCGMCvMMMMMMBCBMhMBMBMBMBBuBLBBuLBLLLLLBgLLgLgL", +"rbrbrbrbrbrbrrbrbrrHrbrrbrbrbrrbrbrrrzrzrrzdrdrrddrddOrdddOdOOdOOdOOOjOOwOwOwwwOw#OGwwGwGwGwCGwCGGCGCGCCvCCvCMCMMMCMCMhMMCBMBMBMBuBBuBuBuLBBLBBgBLgLLgLgLg", +"rbrbrbrbrbrbrbrbrbrrrrrbrrrzrrzrzrzzrrzrzrrdrdddrdddrdOdOddOddOOdOjOjOOwOwOwOwOwwwGwGwGGG#GGGGCG#CGCGCGCCCvMCMCMCMMMMBCBMBMhBMBuBMBuBBBBBBLBLBLLLgLgLLgLgL", +"zrrrrrrrrrrrrrrrrrrbrbrrrzrrzrzrrzrrzdrdrddrddrddOrddOddOdOdOOOOOOOwOOwOwOwwww#OwGOGwGwGwGG#GCGGCGCGCvCCvCCCMCMCMMCMhMMMMhMBMBMBuBBuBLuLuBLuBLBLBLgLLgLgLg", +"rrzrzrzrzrzrzrzrzrzrzzrzrrzrrrzrdrdrdrdrdrdddrddddOdOdOdOdOOOOOjOjOOwwOwOwwOwO#GwGGwGGG#G#CwCw#CGCvCCCvCCMCMCMCMMMMBCBMBhBMBhBuBBuBBBuBBLLBLLLgLgLLgLgLgLg", +"rzrrzrrzrrzrrzrrzrrzrrzrzzrzdrdrdrddrdrddddrdddOrddOdOdOOOdOOjOOwOjwOwOwwOwOwGwwGwwGGwGwCGwCGGCGCGCCvCCvCCMCMCMMChMhMMhMBMBMBMBMBuLMBBLBLuLBLBLBLLgLLgLgLg", +"zrzrzrzrzrzrzrzrzrzrzrdrdrdrdzrddrdrddddrOddOJddOOOdOOOOdOOjOOjOjwOOwOwwww#GwwwGwG#Gw#GGGCGGCGCvCCvCCCCMCvMCMMMMMBCBMBMBMuBuBuBBuBBBuLBLBLBLLgLgLgLgLgLgLg", +"rdrdrdrdrdrdrdrdrdrdddrdrdrdrddrJdddOrJOddddddOOdOdOdOdOjOjOOwOwOwOwwwwOwOwGOGwGwGwGGGCGCGGCGCGCCvCvCGCCMMCMCMCMMMMMhMhMBMBMBMBuBBuBLBLuLBLBLBLLLgLLgLgLgg", +"drddrddrddrddrddrdrdrddrdddddrOddrdddOddrOOOdOddOOOOOOjOOjOwOjOwOwwwOwww#Gww#GGGGG#GCwGGCGCGCGCvCGCCCMCMCCMMMMMhBCBMBMBuBMBuBBuBBuBLuBLBLLLgLgLgLLggLgLgLg", +"ddrddrdddrddrddrdddddrddOrdrddddOdOJdddOOOdOdOOOdjOOjOOOwOOwOwOwwwwO#OwGOwGwGwGwGwCGGCGCGC#CvCGCCCMvCCMvMMCMCMCBMhMhMBMBMBMBuBBuBLBBBLBLBLBLBLgLgLgLgLgLgg" +}; diff --git a/plugins/styles/metal/stone1.xpm b/plugins/styles/metal/stone1.xpm new file mode 100644 index 0000000..34cd562 --- /dev/null +++ b/plugins/styles/metal/stone1.xpm @@ -0,0 +1,353 @@ +/* XPM */ +static const char *stone1_xpm[] = { +/* width height num_colors chars_per_pixel */ +" 96 96 250 2", +/* colors */ +".. c #343e34", +".# c #94a28c", +".a c #64726c", +".b c #c4d2c4", +".c c #7c8a7c", +".d c #acbaac", +".e c #4c5a4c", +".f c #dceadc", +".g c #949284", +".h c #7c7a6c", +".i c #acaaa4", +".j c #c4c2b4", +".k c #64625c", +".l c #dcdad4", +".m c #8c967c", +".n c #a4ae9c", +".o c #6c7e74", +".p c #f4f2ec", +".q c #444e3c", +".r c #bcc6b4", +".s c #8c8a7c", +".t c #5c6654", +".u c #ccdecc", +".v c #7c826c", +".w c #a4a294", +".x c #949a8c", +".y c #bcbaac", +".z c #747264", +".A c #5c5a4c", +".B c #c4cabc", +".C c #d4d2c4", +".D c #ecf2e4", +".E c #acb2a4", +".F c #646a5c", +".G c #8c867c", +".H c #54524c", +".I c #9c9a8c", +".J c #849284", +".K c #7c827c", +".L c #44463c", +".M c #9caa9c", +".N c #b4c2b4", +".O c #dce2d4", +".P c #cccabc", +".Q c #b4b2a4", +".R c #94a29c", +".S c #848a7c", +".T c #f4faec", +".U c #6c6a5c", +".V c #6c7a6c", +".W c #acbab4", +".X c #546254", +".Y c #4c564c", +".Z c #a4aa9c", +".0 c #747a6c", +".1 c #ccdacc", +".2 c #545a4c", +".3 c #74867c", +".4 c #4c4e44", +".5 c #bcc2b4", +".6 c #5c6254", +".7 c #d4dacc", +".8 c #fcfaf4", +".9 c #3c463c", +"#. c #6c7264", +"## c #e4eadc", +"#a c #949294", +"#b c #847e74", +"#c c #8c968c", +"#d c #a4b6ac", +"#e c #747e6c", +"#f c #949a9c", +"#g c #9c9a9c", +"#h c #84827c", +"#i c #e4e2d4", +"#j c #848a8c", +"#k c #9ca294", +"#l c #ccd2c4", +"#m c #7c7e7c", +"#n c #c4c6c4", +"#o c #a4aeac", +"#p c #bcc6c4", +"#q c #8c8e8c", +"#r c #d4decc", +"#s c #848274", +"#t c #a4a6a4", +"#u c #bcbebc", +"#v c #747674", +"#w c #c4cecc", +"#x c #d4d6d4", +"#y c #acb6b4", +"#z c #646a6c", +"#A c #cccecc", +"#B c #b4b6b4", +"#C c #545e5c", +"#D c #6c7674", +"#E c #747e7c", +"#F c #3c3e34", +"#G c #b4baa4", +"#H c #949684", +"#I c #7c7e6c", +"#J c #acaeac", +"#K c #c4c6b4", +"#L c #646664", +"#M c #dcdedc", +"#N c #8c8e7c", +"#O c #a4a694", +"#P c #949e8c", +"#Q c #bcbeac", +"#R c #747664", +"#S c #5c5e5c", +"#T c #c4cebc", +"#U c #d4d6c4", +"#V c #acb6a4", +"#W c #545654", +"#X c #9c9e8c", +"#Y c #eceedc", +"#Z c #4c4a44", +"#0 c #dce6d4", +"#1 c #cccebc", +"#2 c #b4b6a4", +"#3 c #9ca29c", +"#4 c #848e7c", +"#5 c #8c928c", +"#6 c #b4bab4", +"#7 c #7c8e8c", +"#8 c #44524c", +"#9 c #6c6e6c", +"a. c #e4eeec", +"a# c #d4e2dc", +"aa c #a4aaac", +"ab c #747a7c", +"ac c #5c6264", +"ad c #94a694", +"ae c #acae9c", +"af c #646654", +"ag c #dcdecc", +"ah c #a4b2a4", +"ai c #bccabc", +"aj c #5c6a5c", +"ak c #7c8674", +"al c #5c5e54", +"am c #ecf6ec", +"an c #646e64", +"ao c #545644", +"ap c #7c867c", +"aq c #444a40", +"ar c #f4fef4", +"as c #6c6e64", +"at c #545e54", +"au c #4c5249", +"av c #fcfef7", +"aw c #6c766c", +"ax c #e4eee4", +"ay c #8c9a8e", +"az c #748274", +"aA c #84867d", +"aB c #e4e6dc", +"aC c #ccd6cb", +"aD c #d4e2d4", +"aE c #3c4238", +"aF c #b4beac", +"aG c #9ca69c", +"aH c #b4beb4", +"aI c #f4f6ec", +"aJ c #3c4a3c", +"aK c #949694", +"aL c #949e9c", +"aM c #9c9e9c", +"aN c #848e8c", +"aO c #9ca694", +"aP c #a4b2ac", +"aQ c #bccac4", +"aR c #5c6a64", +"aS c #848674", +"aT c #646e6c", +"aU c #74827c", +"aV c #94a294", +"aW c #7c8a84", +"aX c #dceae4", +"aY c #94928c", +"aZ c #7c7a74", +"a0 c #c4c2bc", +"a1 c #8c9684", +"a2 c #a4aea4", +"a3 c #444e44", +"a4 c #bcc6bc", +"a5 c #8c8a84", +"a6 c #5c665c", +"a7 c #7c8274", +"a8 c #a4a29c", +"a9 c #949a94", +"b. c #bcbab4", +"b# c #74726c", +"ba c #5c5a54", +"bb c #c4cac4", +"bc c #d4d2cc", +"bd c #ecf2ec", +"be c #acb2ac", +"bf c #646a64", +"bg c #8c8684", +"bh c #9c9a94", +"bi c #84928c", +"bj c #eceae4", +"bk c #b4c2bc", +"bl c #dce2dc", +"bm c #cccac4", +"bn c #b4b2ac", +"bo c #848a84", +"bp c #f4faf4", +"bq c #8c9284", +"br c #6c6a64", +"bs c #6c7a74", +"bt c #a4aaa4", +"bu c #747a74", +"bv c #ccdad4", +"bw c #545a54", +"bx c #4c4e4c", +"by c #bcc2bc", +"bz c #5c625c", +"bA c #d4dad4", +"bB c #6c726c", +"bC c #e4eae4", +"bD c #8c9694", +"bE c #747e74", +"bF c #ccd2cc", +"bG c #d4ded4", +"bH c #b4baac", +"bI c #94968c", +"bJ c #7c7e74", +"bK c #c4c6bc", +"bL c #8c8e84", +"bM c #a4a69c", +"bN c #949e94", +"bO c #bcbeb4", +"bP c #74766c", +"bQ c #c4cec4", +"bR c #d4d6cc", +"bS c #acb6ac", +"bT c #9c9e94", +"bU c #eceee4", +"bV c #dce6dc", +"bW c #cccec4", +"bX c #b4b6ac", +"bY c #848e84", +"bZ c #8c9294", +"b0 c #acaea4", +"b1 c #64665c", +"b2 c #dcded4", +"b3 c #54564c", +/* pixels */ +".x.0.OaHbI.2azbK.rbJaF.Zbq.EbqbT#..x#6at.S.KaGbOaz#5albJb1b0bAayaw#..S##.xb0an#IbI#NalaFbH.5a6bN#kbSbobT.5bObu.Z#k.5.ZaYbL.ga9aZ#e.EaDbqap#..Z.S.SbP.ZbMaF.BbI#lbT#3ap.xbYbO.SbL.ZbEbXb0awbL#PbI", +"#k#c#..San#c.5bqa7bqb0bR.SbW#P.KbLawbqbLbCbHbT.5bY.c.ibObMa0aD.5.xbHa9.6bHa1bT.raAbIb0an#3#5bt#caAbXbWbYbtbSbM.SaCbq.t.xa5.SbLaAbLapbP#cbo.SaCbt#kbPaybIaOaGbMaOaG#c#k#S.Z#5#3blbIaO#k.Z.xbHbLaH", +"#3bOaHa1.xb0bH.YasbN#c#kbq#cbM#kbYbMboatbNbTbG.K.B#6.Eb0#t#kbz.cbPbqaw#1bt.EaHa9bTaA.KbCbu#pbobkbo.EapbSbJ.YaGbba7bLbSbMbHaZbIbIaCaH.0bH.D.N#.bSaCbM.ta7#3aB.E.EbJbNbOa7aGb0bY.0#lbT.5bt.0bEbq.S", +"bM#VbJbnbObIb0bMbQbOaqapbM.ZbobL.xbfbT.EbJ#caAbHa4#5bTb2bt#lbqa9#k#caBbtbt.SbJa2bmaY#JbyaMbybz#f#5.5awbOb0.Z.KbXbY.xb2a9bLaSbH.Uapa9bY#c#E#5.N#tbHbtbTbebEbKbebQbP#cb0bFbE.SbJaw.Ba9aG.xbM.Z.EbM", +".l.xbR#P#sbI.0.ZbnbVbNaA.Z#3.0a6bEbJbG#k#6bIbqbebK.EaGbMap.Ka7bIaAbF.ZbqaH.O#3#.boaMbhbf#3aaab#o#kbt.S.5bYbubRau.MaMaAbMbMbM#s.x#5bX#6aEbSbAbEa9.0bHaGbq.B#ca7bI#cbY.0bXa9bMbb#3#4#3bqbSbq#kan#4", +"aY.F#ibha7aA.iasbbbo#3bebybL#ybLbN.xbu#la6bSaBbNbrbl.xbV.W#lalbIa.bI#taHb..KbN.ibPb0.Kbb#va9a9aL.K.ZaCbObea7bo.F#v#5aGbMbL#1.E#I#6bu#3.K#5bP#3aG#Sbta9#JbObBa2bobIbW.Z#6#ka9.Z#5bqbHbO.7#lbK.EbR", +"bUbJ.ia4.wbHbh.Zba.O#3ap#3a4#nbUaA#kbYbI#c.7b0.5a8a9bS.NbQ.BbFaA.Zbtbtbt#6bIbFbtaAaAbXbHbLbNbpap.SbebI#5awbq.xan#cbo.KbobHbT#R#Ha9#E#5.Kbe#catbfbIbSbubIbeaKbtaKbY#casaG#kbH.ZbybTaO#cbJ.O.ZbIaG", +"b2.PbIaAaAb1.sbX#Ebfb1#t#qaAbAaH.Ebua4#6#kasboapb2.x.xaGbEbe.5br#9bubX#6bEaKbo#qag.ZbTa7bPbH.5#5#k#5aGb0a7btbY.K#LbL#5bM#X#2#N.ya2bu#C#y#3bo#jbB#B#qbb#c#9al.K#5bTbNb0#cas#3bN.x.ZbEbXaHbN.0.Z.0", +"bq#6bS.na9#ca4bq.Zbtbu.Ea9a7#LblbXapbebqbo#6bYbPa4bXbYbT#IaAaZbqay.B.ba4bNboa2#5.x.EbYbo.F#5#DaAap#5bI#ka4bX.EbRat#kasbJas.O.Zbq.7a1aO.nas.S#2#e.2.ZbHbX.S#5#L.SaVbY#caV.MbSbG.dbObqbIbMa3bb#c#L", +"#kaG.San.6#l.EbAa2b0#k.Za4.Oa2#3.FbMbb.ObJaH#kbRbGa1.nbn.5bn#sbM#N.Y.EbSbEawbebqaC.BbIbJbq#6.K#J#cbT.B#3.0beb0bQaAb0bLbqbIb.b#bO.baya7.E#P#kbP.z#e.x.db0btbE#6bBbTbT#caHbTa2aGbY#3bAbBbSbTb3.EbK", +"bwbYbMbEbo.Eap.x#5bHbebo.LbLawbE.x.ZbqbYbMa2.x#5.ZbJbXa7.ZauasbPai#kbE.BbYb2bzaHbP.Z#.a4a2bJ#5#6a9bQ#k#3bLbqanbM.xa8.0a0aObM#PbR#Xa7bq#O.gbRbRbK.xaAbUapbJ.KbNb.awa6b0a7bYbN.SbY.ZapaObubYbY.0a9", +".1bqbA#PaHawaCbVb2bNbWaCbG.EbYbXaGbKbSaw.E#W.Sap.IaGaIalbJb.#Hb1bH.Z#3bqbH#6#Sbl#k.xb1btbN#JawaKbI#kbKbQ.Sboasa4#6#IaCbMbXbJaAbIbT#sbLbrbL#ibW.zbI#5bHbObu.SbSbLaG#5bEa2bt.x#3bX.wbEbjbo.7b0apbW", +".ZaDaGbNbTbQ.6.Z#3a2#3#5aA#lbMbFb0blaAbq#5apbqbXbI.5bO.5bIb2.E.Z.Zbq.Sa9.KaCaGbT#cbRaHbI.xb0bua4#5.B#5aGbLapbMbo.g.Ea0#QbF#N#5.Sbr.wb..z#hbLbTbObB.BaGaHbXbEbTa9bH.ZbLbPa7bX#c#.bSbt.E.BbNbKbNbO", +".5bGbKbYbNa2.da6bJbq#6.Za2bNboa4#c#lbEbbbNbXbu#3bTa0asb2.E.YbTb0.E.s.SbK.B#maAbbbI.0.x#3bNbI#B#ha7bGbFbTbq#3.S.ZbebT.SbWbqaB.gb0bObmbtbIbLbT#3b0byaw#tbJbQbO.x.Sbo#Lb3bNbmbobKbOawbRa2bJb0.YaAa2", +"btaGbEa7#cb1byaGbobqbL.Bbe.7bIbqaBbWbq#5bq#3#cbX.ybHbnbqbIbq#ca7a7bTbJbPbmaKbIaMa1a7bJ.6.xa9atboa9.5bWax#6bW.NbXbUbTa5bT.Kbq#3as.waYa7aMb0bH.Ea6bNa5aG#5aCbTak.EbTaA#5bHbL.xbobhbS#5bHbea4bIap#6", +"bN.5a2bX.xbQaH.B.Z#3.dbU#kbNbMbFa4btbWbM.E.S.x#6asbL.ZbLb1.Z.0akb..0aZb0bTbP.ia9aAbHaGbH#L#cbeaAbPa2#lbQbLbHbw#3bHbq.5.SbM.SbMbIbB#qa5.xbbbi.M#c#tbebob.bYbJbTbA.wbo.wa5aAa8#t.h#3#ibS.ObIan#3.0", +"bHb#bM.Zbq.sb2b0.a.SbbazaRbNbN.nay#3aG.J#ybSbNbNbWaB.YbL#6anbYbE.Z.xaO#cbea9a9be.mbH.nbq.EbBbebB.O#.#6.x#6bI.Kb2bybAbqaAbP.5boat#k#c.ca#.ZbQap.MbTa2be.Za7bQaw#Oan#ObP#5bY#5#5bJbu#6bBan.E.xbI#3", +"bWbX.Z#5bKaua5a7bTbNbY.B.5bRbVbt.6.xaHapbO.bbqbz.x#5bNbJ.Z#3bHa9#2.EbebN#k.Z#5#q.Z.ZafbV.ZbMbNbqbXbSbI#5b0aG#5bDb0bKaHa4aAbu.0bIa2.xaG.E.BbAbNbHa9.SbYbI#6.ZbIbQ#2#cbIbQ.0.KbO#6#c#PaHbM.EbfbHbo", +"bKbIbI.i.0bL.7.waG.Tap.Sa4.0buai.KbS.Oaw.Sap.6aGbO#c.Sa2bJa7bebH.x.0.BbI#c#Bbu#cbR.YbRa7a7bM.xbI.x#Tb0bVa9bI#cb1bq#c#hap#c.x#3#kbI.KbT#mbqbO#6bPbYbYa9bNatbWawala2bq.xaAbTbobtbf#hbO#5bo#3bIa6aw", +".Eb#.E#2b0bTbMbe.S#3bP#6bOaHbSbSbMbYbP.xawasblbQa2by.TbJasaHbe.KbT.KasbqbtaAbH#3bIbobybGbWaC.E#G#..EbqbqaA#6a9bYaM.6#caB.Ea9bKay.ibL#5.Pbta8b0bMbFa7bqbIbea2bJ.E.KbqbS#6bJbYa9.O.raubA.xbY#kaAb2", +"bJbO#lbXbM#laYbT.Zbl.F#5bBbX.xb0bHbebI#3bNbtbTa7.5bO#3bo#cbObNb2#6bOb1a0aYaAbWb2#6bC#9asbH.0bHaC#T#kaHbXbqaA#5#h#3bYb1apaAawbTbS.k.ibha9aYbMb#bMblbeb..nbtasbKbEbzblaA.ZbQbJbYbTa4bTa2b1.EaGbIbF", +"bT.xbKbHbWbq.B#ka7aubqb1anbUbL#JbT.5bM#6.xaAbIbubL#ca7.SbUapbM.5bu.ka9aAbMbJaYbT#SbPbBbfa9#ca9bH.S#cbXby#waA#taHala2.5bKbSa9.EbMa9.SbhbLbM#6b3bTala7ana2bLbqbTbe#3aAbQ.6a9bN#Qbtbqa2.xb1a4bzbqa6", +".x#lb0b..Ebhbqb1a8btbmbbbhbJa2#5b0bebTa5b0bJbBbIbNa9#5a9.x#3.SbXaZa5.HbX#B#UbLb1a2bYbYbMa9bobtbF.0bJ.SapaAaGbG#gaGbSbJana9b1bY#3.E.x.Z#cbqbQ#cbqby#cbMbIa6bLawbEbH.KbtbLbeaOa7bqbealbube.5bK#.bo", +"bK.BbLbX.ZbXbL#3bKbhbu.ya5.ibPbTbLbh#5.Qby.k.i.k#5.Bb0.BbPaHa4a9a0a8#qbL.Qbnbq.ga7#laAa9bT#B#v#jbK#k#ka4#kaKbTaHbL.Ebl.5bN.6a4bIaza2apbt.cbY#cbb.ZbI#cbfapbSbIan.iaMa9bN#l.i.5#4bI#c.na9bIa9bHbe", +"btapapaW#kawbe.0#8aVaW#5a4a9.i.IbNa2a7bw.OasaGbh.F.naG#l#5bBa9#qbBbFbO#5bMbOaAbB#k#X#kb0#kb0aZ#kbS.e.S.0ahaObSaybHa7#k#kaA#U.nbH.0.Z.0bHb0#P#k.S.BbHbebMbI.x.Zbt.J.7.Z#k.S#T#k.E#4aObN.daF.e#4#P", +"#kbQa7btaGa9azbY.WaGaGa4a9.Ob0b0a4bJaHbFaza5aAas#VbL#kbe.0bMbWbwb0bL.xa8bIb1bJbJ.O.F.I#ka2#ibHbBbIaFaC.SaHbY#l.0.0asbPaAa1.KapbPbMbS.0bSbq#l.xbqbTbY#kaH.0a9bt.K#O.Y#P.Ja7bSbQbEahbq.E.Zat.BaVbH", +"btaGaH.7aCbHbNbS.WbsapbSbLa5bO#6.b#k#lbo#5.gaGbcbTax.5be#k#xa6#n#3bIboasbFbebJbO.jbRbLaKaMbo#m.ia6.xa4#PaHbOaFbqa7bBaO.xasb0.E.Z.Eas.x#lbqbzbKbV#c.Z#xb0bY.SaH.EaC#m#.axb0bNbMapbL.4#.by.CbTas#l", +"aF.SaHbJbNbMbC.Zapa2bGbQ#6.KbC.IbG#cbq.K.5#m##b1awbX#k.5aGa9bT#5.xbm.Sa0.FbhbH#qau#6#JaA#B#hbc#5.B#k#4bO#.aGbSbIbeaDbM#k#5apbLbu.E#3bXbtbX.nbob0bKbT#Va2#6bJbIaG.KbDbEab#5bEbS#tb0a0as#lbMa5aA#B", +"bHbOakbE.E#..Ba7aLaT#c#3btaG#NbY.dbfbN.ZaIbKbPa8aC#NbNbSbXaGaAbebObR#5.xbBaZbJa7.k#9aZ#Lbu#vbeaZbKbHby.xbHbO#.#PbTatasbyaB.VbS.x#cbt.FaGbXbLbN.Zbi#cbT.Ea6bYaG#kbObY#ubEbobuapaGa5b2aZbPaZbLau.G", +"btaSaB.D#lbT#ObP#ta6#3#3bBbHbe#k#5.5.ZbFbEby#hbqbq#.bu#lbKby#5#BbEbXaYb.bL.9bXbX.i#BbB#Ab0bLbJ#lbM#k.F.5bJbTb0a7#9btbe#5bt#JbebMaMbqaMa2bzbobt#3bTa4bMbo.0bXbIat#J#3bYa2bJ#6bo#6.K#5#mbtbBbKboaA", +"b1#l.j#Q.D#H.B.xaHbyanbYar.1.xaya2a6bY.x.ZasbIaA.Ba4.5asbE#B#5bL.KbLasaCb#bKbXa2#qaAalbua5.S.5.Ebt.zbXbMbTb1.xbzbIaCaAbyatal#5bt#ca8au#6bebRa9#6as#cbN#cbWa9a7#kaH#Va6.E.E#c.xam#lbBaw#5.5bBbEbA", +"#U.4.0.Q.ZbMbObX.KaKawaKbP#5.bbq.M.Ta2bWawa8aAbI#kbRaGa4bJbubPa9#3bIbPb0bTblbWbn#3bLbt.w#V#U.Z.z.I.ZbRbKb1bLbXbWbBbebLbtbfaK#c#uaA#6#6#S#vbSaMbe.EbHbI.0bo.xa9.Zb1#k#V.xbNa1a1.ZaU#q.dbNaL#6aRbN", +"ah#4bS.Va7#e.Maibqan#kbXaw.BbLbYa2aha9bIaAbGahawaAbB.ibXbT#c.xbbbJapalbe.xbO.#asawbJ.QaObXakaZa9bXb0aAbA.0br#5.sbNaha9#cbVaCbYaVbDaw#c.ZbeaBaebMbKbP.qbMaAbYa1b0bEbSbE.Ba7.i.Q.BbObNboa7bM.Sa7bW", +"aOaw.xambN.M#2bGbJ.0.Z.xbT.E.ZbHapa2bt#k#3bIaibQbTaAbRbT#k#BbMbMbybybNbe.S.O#..Zb2.2.5b0#H#kbKbt#5bu.ZbM.k.K.xbe.xapbea7aG.0aG.5a4bEal#6awbT#Ob0akbT#c#.bH.SbLbIaUa2.xalbH.0.S#sbebf#J.ObNbJbN.O", +".7#l#4.SakasanaObMaGbqbN.0b1bQ#..daGbIbJbTbTa6aCbObIbH#S.Za5aY.xa5#jbobo.K#5bFbLbtb##U#Rbq.hblba.0bna0#5.QbO.EbM#haA#.bLbMbKa5aAbCbBbfbTbqas#3bWa7bNas.Za7.EbYa1bMaVbt.EbYa7#O.BaKbXbuaHbqasbH.E", +".S#6.Z#kapbT#4bIanbHbRb2.S#cbO.xaybb.BbX#t.Z.V.abJbTaA#5.i.F.KbKbFbFaa#3bf#vbobbbnapbM.S#2#lbKbra9bXbI.0bebMb0#h#6bXaAbM#3bnbPbubobH#.bzapbLbNbIaHbP#ca2bI#5a4bLbK#k#k.Z.B#3bPa7bYbbbobJaG.Ea9ak", +"bLbq#kbJ.S.x#c.E#PbW.Z#l.6a6.nasbQ#4btap.0bBbS#cb0bTbBbLaIa9bL#5#q#taAaaaK#nbtbt#n.ZbH#Rb1bqbUbJbKbz.K.ZbobLbtaZb.aZ.kbM#vbIbM.ibTbFan.KbRbEaA#5bqa9bebI#cbLa2bu.x.xbFbPbIan#HbeaA.KbT#m#kbo.Zbq", +"aIbMb1bHbP.pbLbP.xaGbJapbSbX#.#caCaUbTbTbAbX#c.JbXalbXbb#ia7bJala4aM.Ka2#LaC.Kbwb2bBbO.BbL#U.0#mbXbJaAb.bIaG.PawbMb0bMbn.0aKbHbXa4ae.iap#lbIbo#kbBb0bo#cbPaGaAbua7bI.ZbE.E.xaybbbBboatby.2.Sbq#V", +"bLbTbMa9bP.S.xbRbLbYbPakaAa7bM.E.N##.K.Fa8.SbtbNaG#kbPbrbTbIb1bK#Ra7a7#3bbbxbu#qaA.x.5.0.x#XaK#3.xbX.Ka7bLbIbyaAbq#cbq.Y#3aObb.S#k.sa7a9bPbt.aa2bTaAaGb#btbubt.KagaSbL.SbLawa9aVbI.KbtbM#3#cbJbX", +"bc.FbT.g.haqbMbPbP#ebIbN.6a7#kaAaV.cbtb0b2apaObEa5aAb2.KbIbubl.K.B.Z.7bM#5.0.KbE#vbHbXaf#ObY.IbobhbNbm.ibTbhbT#u.SaWaVbHaG#c.ZaU.A#YbIbYbfbSbGbibo#3aMa9#mbP.K.Kb0.Q.S.xa2.ZbNaCbb#6bo.5bTa7bq.B", +"aw.S#4.cawaS#P#.bqa2bX#.#c#caPa2bHbQ.FbY.d.3aw.o.J.5.5btaGa8auaY#GaebXbWasaK#v#a.H#ObPbJ#3aAaU#cbL.KbIbK#5.xb0bI.a#4.ZbbbL.SbI#..I.SbT.E#k#1bL.6bTaNbo#5#3.YalbLanbqbSbTa7bPaxbubfa7bz.0.Yaw.5a4", +".Ea1.6#2bSbqazbX#kal#c.xawaGbSaUa1.5.5a2.WaCaybYbEaVaH.SaAbq.kbaak#k.0bX.xaY#v#5as#sbB.S#ca9#ca9bK.I.Kb0b0bI#kbKaO#VbHaw#3.Sa7aebX#I.xao.wbq.5bM#5.Zbua5bEbe#vaGbybB.S.Ka2#cbz.SbYb0bBbB.Z#5bo#k", +"bNaG.6apbY#k.r.7aSawawbXaC#caCaP.xbYak.VbNbb.WaWaxbM#c#lbNbXaAbIae#O#.bq#tbO#9aKbRbT.S.ZbNbyaHbNb0bPaAbBbJ#LbebMa1bq#kaKa9bL.x#NaH#Q.x.Z.S#Hbq#Xbyb0#5bMbFbBb1beaAbL.xbtbP.KagbJbqbtbL.xbubTbqbM", +"awbIaCaC.x.0a2aG#k.O#kbq.xbGbS#6.SbHbMbSaCahaGbB.Saz.ZbLanbPbTaY#l#.bTaAbqbeaA#La7aGbFaBawb1boap#Jasa9bWbWbIbObX.NaGbSbP#5.ZbrbMaAbL#kbIbM#hbKbX#caA#3bebuaAbebfbq#6bNa7#5a7bEbobubEbTbE#4#3aGbL", +"###caG.SbEboaGbMbMbY#Vbea4bvahaW#PaC.Zbq.0#6bz#6.J#Waz#J#lbPbLbt.0b0.xaKbO#mbLa5bwb0#kaH.Sa2bWaAbIbJatb0#6.iap.xa1bY#5awa0a9bnaebaa7aY.EbXb0#l#ka8#Ca9bobTaKbYaK#rasbIbLbN.SasaG.4a2.SbobXbK.Ybq", +"an.5bua4by#5.O#c.haCbJanbY#caJbfbHasbNbY.2aq#JaAa7aGa2bybOaAapaYb2#9bLbPbWbXb2.SaHaHanby#3.hbTaObX#3bL.SbT.x.ibTa2bN#5bBaGbobJbqbt#lb#.EbJ.5a9bL#3beaKbOa9bu.E#vbK.MbtbqbN#5bM#3#k.KbtbMbI#c#cbo", +"bobfbLbYaAayaA.M.Eal.nbybLbubE#caia1.7btbBaM.L#BbSaC.5#kaCb0bOaYbMbAb1btbPbL#nbLaU#u.SbebNb..5#sbMbub0a9a8b3bTbI#V#3bubF#q#vbn.2.KbMbo.kbObLbJbJboboaC.KbY#man#mbqbBbLapbMbbaGbS.5aHa7a7bYbebLaG", +"bT#Eam#p#5aAaL#3bOanbqbVbEajaHapaO.SaH.SbObhbM.H.a.SalaGbTbYbh#6bJbM.p.2a9aA.0aoboay#9.E.x.E.g.2a8.5bn.sboaA.Z#6axbF#Ea5ab.4btbJb#bbbPbzbNaAbxbM#5#5.K.iaqbB.K.Fa9anbTbH#k.EbP.SbIbeb0bYbu.x#3bq", +"#PbN#Ta9aVaWbtaG#VbP.ZbhbXbM#h.G#d...ubYbq.7#k.0bNbwadbSbea6aV.5.X.1bE.J.ZaAbS#5.5.Z#T##bY.E.F#l.EbH#c.Ebu.ZaH.CbTbMbXbT#n.5bMbM.JbEbG.5bBbSah.KasbqbtaYala5bJbJ#cbo#3bNbubnaC.gan.cby.Obu.waAa0", +"#4aGbN.E.BataG#ubY.x.EbLbM.2.iaKa9ap#EaGbAas.S#..BbYbNbN#c.Ea2#3#c.JbN.5apa2bRb0.FbNaA.6bWbQ#.bPa9by.Sb2a2bTbE#6bTbIbq#5aA#5bua0beapbEaGbq#capa7aAbMa0bIbt.KaAb0ay#3.Ka2.BbI.sbqbSay.x.Z.xbo#SbI", +"ak.EbSaVbRbSbbbbapbi.KapbF#5bCbtbBbbbOaAbIbI.EbXbI.0.Ba2bqaG.5.dbSbNaCap#mapbubLaM#kapbFbhapbuapaCbJbobSbqbo#FbHbub#asbJbhbJbh.B.FbHbq.0a2aw.BbtaAbubXbI#kbXbPbAaPasbo#5aC.5a7.hbt#kaH#5#c.IbL#5", +"aB.0bMa4#6bP.KbtbDaW#5.W#yaw#qbybLbI#vbXbT#hbLb0ay#5#3#kbA#cbBa9blaGaMbo#Ebh#W#maG#q#Lb2bobe#vbz#AbNaB#5bo#5aw#v.0b0.KbK.EaAbJb1#3bKa9.KbObJ#c.xaAbLbobLbMbubIaYbDbSa6aAbI.Eb0.5bt.xbubH#ca7bbbL", +"aq.nbX.SaH#3bLa9#B#BbiaTap#wbi#Cbh#kbh#5a5#6bm.ibJbqbMbpbM.0bMbb#p#jbu#m#J#9#9aMblbu#6a9#5bfbIb0a9bfbUbIbyb0bobWb0bt.i.SbX#m.Bbbbq#c.KbNbza4b1bKbWbSbLbObobLbeb0arbbbu#k#6bLbMal.EbMbE.Bala9#k#c", +"#kasbMbybXaZ#v#qbn#3boaAbWaXbK.R#I#hbJ.5bU#ha2a2aAbTbEbO#5aAbM.0b0bb#m#6#tbTbhbnbzbobT#9bobeaAbb#ubIbe#p#q.Kbbbua9bPbI.KaY#kbh#6.8a7a7a5bXbBbJbI#kbu#la8.OaYasbMbN#3bL#5.D.i.S#Hbf#h.EbubNa9.Bbe", +"#QbLbIbPas#5a9bP#Lbra7bBbtbI#c.x.Z.EbKbJaha4.RaNbTbLaZ.ZbMbtbFbJbtaAakbO#q.ibWas#3#I#3bY#2bJaGbHaLbeaAbebybt#9bT#kbPbMbPbtbebH.EbX#nbIbObqb1b0#vbRaZbt.BaYaw.5aA.R#3#8#k#cbHbXbMbhbcb1b0bTawaV.0", +"bTbTa7bmbRbhbma9.g#b.y.waG.UanaCbKaH.Ea4bN.Jaya4aYbKbubTbL#hbr.Z.SbYaY.ObL#sbPaYbq.5ak.E.7a4aebY.kaLaMaM#mbS#qbtbra9bTbobLbhbX#haZbP#hbXa8#h.xb##.aAbPbPbXaYbJ#v.Bawbe.x.KaA#k.QbTbTbXapbE.xaCbQ", +".K.K.E.x.xbY.Ka9.bawaDbq.v.ZaO#da1a2.ca2.aa2aGawbMbTbObTb0bB.zbe#T.V.xb0#ca9a8#Ja4.S#5bH.Oa9.B.SbtbTbL.ZbH#lbBb0aG.ZaAbI.ZbubLb0#k#K.n.bbNazaq#q.SbE#iap#Db1#l.5#3.KbMbAaAbE#BaAaKapaAa5b1bTbua8", +"bwanbObI#r.7bu#ybSaG.5.Q#G#.bVaw#cbLa4.BbObQbqbGbMbLbtb1.KbPbMa9#..MbqbobRbMaBa8a9.5b1awbTbSbybKaAbX.S#3bXbP#NbM#qasa5bMaAbIaAbL.S.x#4.M.SbYa5bLbqbSa9#zaAboan#.bLbwbubebX#qbS#5.x.i.KbI#m.2asaA", +"#6be#3a1.E##bmbMbBbYbP#UbRbRa7#6bObWbXbI.E#qbJbTb0byaqbJbMbXbWbt#X.NbH.ZbNaAbu.i#cbKbKbfa2bBbXbN.ZbTbRbT#sb0#5bJ.Z#.bPbXaMb1#6.E.IbR.naObN#kbTb.bI.EbobMaAbAbHaAaGbJaA#c#qbCbo#5bLbMbL#cbObXbObX", +".KbJ.7#XbSbWbtaG.Sa0#sbTa8a7a8bTbIaKbLbIbJbhbR#3aAbLbMb0bMaAbIaA.7bMbN.ZbS#BbX.Kap#AaibW#kbNbTbIb0bXa7#k#3.IbH.iasboaYa2asbqa5bIbLa7bMaW#ratasa0a1bq#c#va9#3.xak#5#nbe#3#5bebXbIbMbtbJaY#kbXbTbo", +"bFbz.7bT.5#kbybo#hbWbobtb3#na5.7#J.IaYboaYb2bPbOasaCbe.Kb0bPbeaBbWaObMaHbJ#EbY#mbqa2#kaAa2#5aO#c.5b#ag.5b0bObK#2aZbL.EbT#5bLaYbJ.K#vbNaG#k#3bubIbT.F#Lbea9#A.ZbKbQ#3b1bL#3#6bObtaAbOanaBbJaAbTbb", +".Kbna2bq.Z.0#m#vaZbTbo#L#BbubPaAbr#cb1##bM#tbH#vbMbT.Za8beb0#.aA#ka9bPbObL#kbB#5bSb0aGbIbqbT#Ja7b#bIbObnbP.Bb1bEbLbobza0bLbobI.Ka5b0byapapbQ.Ea8bHbLa2bobS#3aG.xb0bfbE#3bub0bz#c#6bIbhbI#6bLbebM", +".KaKbYae.S.B#5bIbqbtbu#y#E#cbSbJ.F#3#ca2awbIa4aHbIa9bIbTbWaA#hbq.h.7bHby.fbt#6bYbqapa9bMbBbYbNb1#k.F#k.0bI.0bh.ZbIbh.Eb0bt.Bbha7#maK#Sbi.V#k.KbX.E#kb0a8bua5.5.0aI#AaKbuaK#5aHb0#hbtbRaGbLbKbLbA", +"b0be#P##.EbBaAapbPa7bNbv#7.a.0bObsaFapaGbGbSa2.6aAbTbMbObJ#5bI#5bIb0bWbtbIa7aWbVbtbM.xa9.ZbTbqap.x.s#3.g#3bL#NbK#3##a9aY.xbh.0#5#Jbh#EbebM#cbT.6bqa4b1aLbNa9bM#VaM#6apaA.xa9aM#5bJbM.BaZbXa9bubX", +"bybIbSaGb0.caMbYbJ.r.5#k#P#XbL#.as#XbJbK.2btaGbD.Z.PaYbH#h.B#cbb#KbebqbbbNbiay.Ya7.Z#UaObH.6#2.7bJbH.0#3asbKaA#5#2bOaSbLbPb0.S.g.d.KbGbEbNb0bXbn#X.B#H.0#2.Z.n.SbYbHbMbE.KbTa2.Za9#caKbo.KbtbMbo", +".5aAbWbS.Ebo.Z.K.BbJbEbX.5aH.5bqaA.EasaHbobeaGaC#s#XbIbLbIap#3.O#3.xbIbtaCa2aLbs.SbObIbU.s.xaAbPbIb0bLaAb1bb#6#mbM.0bt#UbN.g.ZbLbu#VaH#ka0bo.5aK.ZbP.KbJbWa8bJ.Ia7aK.SbEb#a4bLat#nbobebLbNaAbTaM", +"bbapb1a9bobP.xa4aGbqbq.Ba9bOaHbqbT.jbXbI#cbMbiaGbWbI#XapaSbObIbEbqbua2bo#5bV#6aybW#XaF#IbL.Oaea7#O.0#kaBbM#qaA#maA.gbbbTbJ.EbBbJ.dbMaGaAbNbTb0b#b0.hbH.BbRbIbEbWaAawa7beaFaAbMbebtbWbL#t#L#5#3#c", +".5a4.E#kbd#lbXbOa7#cbo.xbHbO.E#3#ka6bobLaGbKbq#3ae#.#Nb0a8a7aH#6#tbzbI#6#cbCapbobMbMbF#k.Bbr#.b#.Zb0#6bOasbMbybMb.a9.i.SbqbLbcbTbNa4#6a7#cbTbJbIbbbT.KbObKbF.g.K.0#3bS.4aG#3bY.xbubTaGapbYbMaAbL", +".5aA.K.K.ZbGbBbVbobHbybz#kbB#c.SbNbebHbea7a4bTbMbTbM.IbT#.aGbJbSbF.E#EbJbebtaYbu#s.SbWb3bybI.5bIbH.gb#bLaAaY#qbIb2bMbY.iaAbXbLbf#eawbOapb3bLbBbT#ha9bIbh.0b0bLbPbY#5bX.BboalbI.Kby#A.KaAbe.K#5aH", +"#kbtaGbqbebX.7bO#c#JaGbPbo#3b0bu#haHbebWbXbBbqbW.Pa7bJbO.EbubKapaM#3bXaYaAbRaZbPbBbP.Qa9.gbI#3bI.xbTbI#cbmbebobJaMbM#3bKbP.Y#ua8#cbG.K#kbebqbnbLas.KbXaAbP#3a9bMasap.5#6#l.x.6awbzbubtbfbbbeaAaK", +".B#5.5bebYbta7#3#6bXaG#x.KbY#qbNboa4.Ma9bNaA.gas#..l.QbMb0#c#5b0#5#j#3bIby.kbWaYbMbBbCbr#3bKb0aAbL#ObLbP#3bhbT#nbLbobPbybeaA#Z.K.MbH.ZaC#6bTbtasaZ.Kbt#5bobLaYbebWaCbya7bNbuby.7bob.bebtbL#nbYaA", +"#t.5bTbMbHapbMa7bea9bobo#maAa9.KaHbl#AbQ.4.5bq#saS#2.Fakbh.x.BbDbo#5a9bMa0b..g.I#qb0a8bJ.Zbrbt#3#HbXbN.ibTbobP#u.i#g#3.iaAaK#6bnaP.xaGbtbM.EaYbLbIaM#ma8bIabaAaKbt#ka9bIbebFbHbqbmanbT#3#5#5#5bl", +".nbH#c.n#lbq#kaHbX.SbTapa7bEbBb2#ca2.J.6a9.ib#bT#cbe#t#3bI#DaAbX#6alaAa9bB.E#mbH.ib0asbebbbKas#3.0.KbPa7#l#cbo.Z#5a2#5aAa9bybTa9#Q.x#N.x.ZbJ#kbqbL.BaebWa7.O.UaSbN#qby.Zbo.0.SbNbqay.E.N.Ea9.MbE", +"a7bYb2.EbYbP.xb0.SbobVb0.KbNb0.Eaya1aGaA.ZbqbtbJbzaAbeaAa4.K#BbTaqbBbIb0bRaYbIbobJ.KbubPbLaAbo.sa9#c#k.KbubIaqb1axaw.0be#.#3#kaGbTbLbIbqbP.jbM.B.S#R.xaO.i#2.x.ZbYbIbua9.BbI#lbKapbfbubMa4a2at.Z", +"bLbH.E.K.Zb0.xaxbYbMbq#6#lbO#3aAapb0bEbEbn#.bOb.#Lbbb1bt.Kbe#.aGbMbLbTa9#.bObJbIbB.z#5bLbobI#ibb.SbebXa9#kaGbz#c.ZbTbN#kbO.Sa7bQ.PbPbobLbI.F#5bXaA#NbMbT#Ia7.IbIboa9btbObNbP#V.ra7bNbNaObw.fbOap", +"apbyaw.5bL.SbEbK.x.E#5.Z#cbA#caGan.Ba4.Faqb.bbaYawaA#5bSbLaMa9#5b#bMbBaAbTa9b0bqbo.Eas#hbWbXbL#3a7bR.FaHbt.6.SbIbqbtbtbJbqbobebEasbybXbfbX#3bJ.F.h#lbI.BaA.sbQbMbP.E.ZbNbIa9bB#k#3asaHawbqbX.K#.", +"aAbSasaGa4bIbS#6bobla7#5bLbS.xbA.x.Nbo#kbEbTbqaMbtbtbt#qawbLaAbt.KbLa8bTb#bIbh.BbXbca9#kbIbNbX.8bF.VbJapbLa9bybNbJ.0.Y#k#6.xbu##bO.xbK.SbIa8#k#tbWaAbIbIbH#lb1.0bt#6b0a2.EbAaCbIbS.EbL.0boaHbRbN", +"bT#6btbt#L.Kbh.KbI.FbobIbJbqaAboaw.BbNbIaHbXb#.U#3bwbT#6a9.Ka9aG.Ha9#kbJbebLaAbU.KbMa9aAbMa9bJbL#3aGb0a9bubL#rbtbNbobO.EboaG.K#6bTaMbOaMbtaYbtaMa7bJaAb0bOaK.Fbo.0bYbqaqaAbt#5aZ#kbebObobX.gbuas", +"#qbSbPbKbubAanboapb0.Eby.5bYb0bYa4#cbRbPa6bObL#qa4a9aA#3#6bubu#5.ga2b1b0bJapbL#3.saA#lb0bTbtbHbIbQ.Da9.7.x.7apbJa2bPaHbLbY#k#6bMbEa8bB.ibJbIbOa9.ibMbqbnbe.Ba5bJbT.0.Z.S#5.B#t#c#q.xaAbta5.SbMaA", +"aHbxa2be#6bBby#t#k.xbua4a4bPa9aHap.0#cbAbWbIa2.l#JbKa9bo#AbTb0bzbeaAaAa0btbI.lbLbybXbAbTa5bLaZbubJbubLbya2anbJbT.2a9a2bXa4bTaHbHbubnaA#Lby#3a5bobubB#q#5#hb0btb0a7bM.xbA.xa9bYaKbKa8asbrbOaY#vbT", +".5a9apbX#cbH.SbybYbM#5bYbKapbIbX.M.Vazay.ObAbI.SbFbPbf.Ca4b0bobLbP.xapbN.7.KbwaAbqbL#ka2.SbLapa2buaGbPa9b0au#c#6.Maw.Va9aAbPbtbL.N#c.cbF.E#6aGalbPbM.YbNbW#cbLaGbHaC#4bLbX#cbIbHaF.Zak#l.B#k#Pa7", +"a9.xaw#kbN#cbo.6bMawbIbMboaFbuap.MaH#ka2.Kaw#3bL.hbPapa8#5bTbLb#bq.Z#kbJa9#JaubebY#6btbP#3bT#c.Ia9bOa9byaAbu#5bea9.0a4aAapbqbOa5bYaQa7.R.0.EbIbIbfahbO.S#3bqbTbo.7.xbf#3.xa9#ebeb1bMa7bo#.#Ha9.E", +".K.nbNa2bA.Z.6bYbY#kbK.M.xaBas#3.Zad#5#.a2#k.EbNaAasbMbTbXbP#3b0bqbNaA.xapbJaHaKbTbfawaHbb.Ea2bK#3bebtbeaKapby#5anap#kbYbT#tbqbT.S.x#5#haC#qaYbJana7#3bY#3#3bHbJbI#6bSaA.FbQbOaw.0bG#kbLb0bQ.rbM", +"bQa4bHbqaCbbajbQapbMby.KbtaG.SbyaGapan#ka9bX.K#6bMbK#cbRbI.7#hbP#4bLaObSasbebB#xaw.E.SbP#lbobQanaKbtbWbtb0bL#Mb0bLa7apa8bObTbHaMbPbT#6a0.zbIaAbh#lbbbLbSbq#5bWaCbo#6bqbybebPbubFbq#kbPbYaCbJbta2", +"awbLa4.S.Map#lblbUaw.xaAbNbr.ZbPaAbIbtaGapbQbRb1awaYbM#vbfbJbtbXaS.xbTbebMbYbfbI.5bSaA#c#6bHb0#cbbbOaLaAbubN#5bo#5bWalbIaAbybJbTa0bobIbTa5bMaMbPbTbSbPb0#5bN.EbybI#c#v#6aA#5btbI#3#cbI.S#6bu.ZbT", +"aGbqboaGbJ.5.K.SbE#c.5bobO.S#5.bb0bh.hb.asbMaG.7bLbzaZ#3#kasbPbI#ka2.ZaH.Ya5awbtbQ.KbMbubY.5bybPasbe#vbQbFbb#JbubXbn.ib0bLa0bTa9bObJ.gbebMbSbJbNaGbqa7bo.xaGbIaHbB#mbobwbe#3.KbBa9#5by.KbEbTbTap", +".xbyawbqa2bzbHbNa9bL.E#3bNaG#3aAa9a8aZbLbKb0anbYaY.SbLbOaAbL#5b0.E#kaGbIbOblbB#vbX.7#5.ZbuaGbMawbBbya9b0#3bfb0#5a5.G#5.ibMbeaAbMa7#xbf.Z.ZbEaC#c.EbTbSbMaG.0bfapbIapbRbtbl#m#3bOa9b#a9bL#mbB#c#n", +"bz.xaGaia6#kay.ZbIapbP.xbYbP#kby#bavbh.Ka9a7be.xbS.i.EbtbJa5.xaA.E#5#kbTat#5boa9bNat.EbTaEbXaGbWa9.KbebE.KbT#5#3bg.k#h.sbnaA.5a9bTbB#Pbo.Ma2adaVb0#cbuap#ka8a4bT#faAabaM#qbobeaA#5bo#v.K#6bE#tas", +".5#4bfb.be#t#k#c.F.0.0bYbO#P#c.FaFakapbYbWbNaM.K.MaGbBbqaH.SbmaZ#d.BaiaGaGaHaCby#P.B#e#PbR.x.xasb0.IbWbTbIbo.ZbMbYa7bIbN#k.E.x.I.6bLbMbYb0bX.M#6#lbJ.Z#NbT.t.s.xa4#3a6bR.S.Ka2bo.WbY.J#cbua7bX#3", +"aG.EbfbebEbE.n.Eb0aw.FbEasbMa1bL#k.naAaGbMaw#.bA#caCbYaAbzaAbMav#T#k#V#lazbT.RbObq.0.7bLaFbIbQa7#kaK.EaKbXbMb0b.aHa9bSbe#kbP.Eae#kbobo.YbuaAa6bT.IbM#..EbIbMbBbTbIbqbL#c#6bMa9bq#fbSa9aH.K#3#can", +"bX#caKas#6#ta7bIa7bBbLbPbYbo#5a2bK#4.JbI.MbBbobbaybqbY.xbJbMa9bI.xaGaqawaHbTbQ#cbW#c.5bfbxbobt#SbtbIbRbJaYasbXbtazbXbobMbPbJbTa8#ca7.ZbN#kaH#3an.B.4aZ.ZbhbK#Q.x.xbt.EbP.EbYbLbt.R#caUb0aGbqbyag", +".5aObobnapa8#c#Pbb#t#3aK#tbo#JbB.JbLbEbQ#kbuaH.Jb0bX.6#5.xa4#5#kbTbNaCbMawbK.KbLbybPbu#6bbbZ#vac.Zbn#kbTbebLbfbIaybobfbo#DbM#nasaHbX#5bMbSaAbMbM.E#5bJbM#3a7a9.ibybSbNaM.xaw#3bHaW#6aLbea9b.#B#.", +"bIbKbeaG#vbe#c.x#3blan#t#k#xbubobRaVa9bNbMa2.EbEbObtbB.0ap#5.0.xawaAbMbHa9bS.S.K.KaKbwbt#q#ubZ#jbLbTbObTbNaYbebTbYbSbY#6aAbt#m#qbqbo#c.S#5bo.O.KbtbTa8.6.Eb.aAbL.5bTa7bHbe.x.ZbtbtbPbYb0be#.bnbH", +"aC#.a9bFbobtbPbLbLbobe#3bbbbbt#qbban.EawbE#.bqbEbHbfb0#5bI.x#c#cbLbXbybtbm.SbI.ybN.Kbe.K#qbD#q#za8.5bfbBbJ.BbTbLaVbMbV#3a6brbT#u.ZbA#kbF#.bMbEbW#B#.bB#naA.K#3bT#cbLapboa2#5#.bobu.KbubyaAbhbIb0", +"#Oa2bX.KbeaA.5a1b0.xaAaAa1#kb1.6a9aA#DbH.ZaVbKbqaA.SbJaA.XbS.S.b#gaA#t.EbL.xbMbWbea2bRbtbubWaM#5.ZaZbP.EbMbJ#mbJ.V#GbHaH#3bc.KaYbL#ca9.0#5a2bqbfbMaZbtaZaAbM#tasbeaCb0bTa4.x.K.E#vbE#LbraKbKbIaA", +".xakaKbybW#6bM#l#ka7#k.nbM.0bH#Pa2#3by#..K#kak#0bnbMaA.5.K.BbNa6aK.ka9bLbc.wbL.7.xaAbqbAbo#JawaB.KbLbq#BbebMbMbL.##Va7#2.S.B.0bIbEb2.7#6.Z.KbJbq#m#5a8bWby#ua8#6#3#lawbTbea7bL#3#3#J#5#.#3.ib#bM" +}; diff --git a/plugins/styles/metal/stonebright.xpm b/plugins/styles/metal/stonebright.xpm new file mode 100644 index 0000000..a538a94 --- /dev/null +++ b/plugins/styles/metal/stonebright.xpm @@ -0,0 +1,353 @@ +/* XPM */ +static const char *stonebright_xpm[] = { +/* width height num_colors chars_per_pixel */ +" 96 96 250 2", +/* colors */ +".. c #7b927b", +".# c #daefcf", +".a c #b5cec3", +".b c #ebfceb", +".c c #cce2cb", +".d c #e5f8e5", +".e c #99b499", +".f c #effeef", +".g c #e8e4cf", +".h c #d7d3bb", +".i c #f3f0e7", +".j c #faf7e6", +".k c #bfbbb0", +".l c #fdfbf4", +".m c #dae9c1", +".n c #e6f4db", +".o c #bbd9c7", +".p c #fffdf7", +".q c #91a680", +".r c #effbe4", +".s c #e3e0c9", +".t c #b0c2a0", +".u c #eafeea", +".v c #d3ddb8", +".w c #f0ecd8", +".x c #e3ecd7", +".y c #f8f5e3", +".z c #d0ccb3", +".A c #b6b297", +".B c #f4fbea", +".C c #fdfaea", +".D c #f9fff0", +".E c #eef6e3", +".F c #bbc6ab", +".G c #e3d9c9", +".H c #ada99d", +".I c #ede9d5", +".J c #d1e7d1", +".K c #d3ddd3", +".L c #989c86", +".M c #dff3df", +".N c #e8fae7", +".O c #f7feee", +".P c #fcf9e9", +".Q c #f6f3e0", +".R c #daefe6", +".S c #d9e2cb", +".T c #f9fff1", +".U c #c8c4ab", +".V c #bdd6bd", +".W c #e5f8f0", +".X c #a2bda2", +".Y c #9baf9b", +".Z c #ebf3df", +".0 c #ccd6bd", +".1 c #edfded", +".2 c #a9b499", +".3 c #c1dfce", +".4 c #a2a690", +".5 c #f3fae7", +".6 c #b2bda2", +".7 c #f6fded", +".8 c #fffdf7", +".9 c #869c86", +"#. c #c4ceb5", +"## c #f8feef", +"#a c #e8e5e8", +"#b c #ded3c3", +"#c c #d9e9d9", +"#d c #dff7e9", +"#e c #c8d9bb", +"#f c #e1eaed", +"#g c #edeaed", +"#h c #dedbd0", +"#i c #fefcec", +"#j c #d7e0e3", +"#k c #e6efda", +"#l c #f5fceb", +"#m c #d5d9d5", +"#n c #f9fbf9", +"#o c #e6f4f1", +"#p c #effbf9", +"#q c #e2e5e2", +"#r c #f3feea", +"#s c #dedac3", +"#t c #eef1ee", +"#u c #f6f9f6", +"#v c #ced2ce", +"#w c #f0fcfa", +"#x c #fbfdfb", +"#y c #e9f7f4", +"#z c #b9c4c8", +"#A c #fafcfa", +"#B c #f4f7f4", +"#C c #a4b8b4", +"#D c #c0d2ce", +"#E c #c7d9d5", +"#F c #8d927b", +"#G c #f0f8db", +"#H c #e6e9cd", +"#I c #d6d9bb", +"#J c #f1f4f1", +"#K c #f9fbe4", +"#L c #bec2be", +"#M c #fcfefc", +"#N c #e2e5c8", +"#O c #eff1d7", +"#P c #dfeed3", +"#Q c #f7f9e1", +"#R c #cfd2b2", +"#S c #b4b8b4", +"#T c #f0fce6", +"#U c #fbfde8", +"#V c #eaf7df", +"#W c #abafab", +"#X c #eceed3", +"#Y c #fdffec", +"#Z c #a39f92", +"#0 c #f3feea", +"#1 c #fafce6", +"#2 c #f5f7df", +"#3 c #e6efe6", +"#4 c #d5e5c8", +"#5 c #dee7de", +"#6 c #f0f8f0", +"#7 c #c8e5e2", +"#8 c #8daa9d", +"#9 c #c6cac6", +"a. c #f4fffd", +"a# c #eefef7", +"aa c #e7f0f3", +"ab c #c9d4d7", +"ac c #b0bcbf", +"ad c #d8f1d7", +"ae c #f2f4db", +"af c #bfc2a0", +"ag c #fcfeea", +"ah c #e3f6e3", +"ai c #eafbea", +"aj c #abc6ab", +"ak c #cfdfc1", +"al c #b4b8a4", +"am c #f5fff5", +"an c #b8cab8", +"ao c #abaf8a", +"ap c #cfdfcf", +"aq c #94a18b", +"ar c #f5fff5", +"as c #c6cab8", +"at c #a4b8a4", +"au c #9daa97", +"av c #fdfff8", +"aw c #c0d2c0", +"ax c #f4fff4", +"ay c #d7ecd9", +"az c #c6ddc6", +"aA c #dcdfd0", +"aB c #fcfef3", +"aC c #f1fdf0", +"aD c #eefeee", +"aE c #899780", +"aF c #ecf9e1", +"aG c #e2f1e2", +"aH c #ecf9ec", +"aI c #fdfff5", +"aJ c #83a182", +"aK c #e6e9e6", +"aL c #dfeeeb", +"aM c #ebeeeb", +"aN c #d5e5e2", +"aO c #e3f1d7", +"aP c #e3f6ed", +"aQ c #eafbf4", +"aR c #abc6bb", +"aS c #dcdfc1", +"aT c #b8cac6", +"aU c #c6ddd3", +"aV c #dbefda", +"aW c #cbe2d8", +"aX c #effef7", +"aY c #e8e5dc", +"aZ c #d7d3c9", +"a0 c #faf7f0", +"a1 c #dae9cd", +"a2 c #e6f4e6", +"a3 c #91a690", +"a4 c #effbef", +"a5 c #e3dfd7", +"a6 c #b0c2b0", +"a7 c #d3ddc6", +"a8 c #f0ede4", +"a9 c #e3ece3", +"b. c #f8f5ee", +"b# c #d0ccc2", +"ba c #b6b2a6", +"bb c #f4fbf4", +"bc c #fdfaf4", +"bd c #f9fff9", +"be c #eef6ee", +"bf c #bbc6bb", +"bg c #e3d9d7", +"bh c #edeae1", +"bi c #d1e7dd", +"bj c #fffdf6", +"bk c #e7faf2", +"bl c #f7fef7", +"bm c #fcf9f2", +"bn c #f6f3ec", +"bo c #d8e2d8", +"bp c #f9fff9", +"bq c #dee7d1", +"br c #c8c4b9", +"bs c #bdd6cb", +"bt c #eaf3ea", +"bu c #cbd6cb", +"bv c #edfdf6", +"bw c #a9b4a8", +"bx c #a2a6a2", +"by c #f2faf2", +"bz c #b2bdb2", +"bA c #f6fdf6", +"bB c #c3cec3", +"bC c #f8fef8", +"bD c #d9e9e6", +"bE c #c9d9c7", +"bF c #f5fcf5", +"bG c #f3fef3", +"bH c #f1f8e5", +"bI c #e6e9d9", +"bJ c #d6d9c7", +"bK c #f9fbef", +"bL c #e2e5d5", +"bM c #eef1e2", +"bN c #dfeedf", +"bO c #f6f9ec", +"bP c #cfd2c0", +"bQ c #f0fcf0", +"bR c #fbfdf1", +"bS c #e9f7e9", +"bT c #ebeedf", +"bU c #fdfff4", +"bV c #f3fef3", +"bW c #fafcf0", +"bX c #f4f7e9", +"bY c #d5e5d5", +"bZ c #dce5e8", +"b0 c #f1f4e6", +"b1 c #bec2b0", +"b2 c #fcfef3", +"b3 c #abaf9b", +/* pixels */ +".x.0.OaHbI.2azbK.rbJaF.Zbq.EbqbT#..x#6at.S.KaGbOaz#5albJb1b0bAayaw#..S##.xb0an#IbI#NalaFbH.5a6bN#kbSbobT.5bObu.Z#k.5.ZaYbL.ga9aZ#e.EaDbqap#..Z.S.SbP.ZbMaF.BbI#lbT#3ap.xbYbO.SbL.ZbEbXb0awbL#PbI", +"#k#c#..San#c.5bqa7bqb0bR.SbW#P.KbLawbqbLbCbHbT.5bY.c.ibObMa0aD.5.xbHa9.6bHa1bT.raAbIb0an#3#5bt#caAbXbWbYbtbSbM.SaCbq.t.xa5.SbLaAbLapbP#cbo.SaCbt#kbPaybIaOaGbMaOaG#c#k#S.Z#5#3blbIaO#k.Z.xbHbLaH", +"#3bOaHa1.xb0bH.YasbN#c#kbq#cbM#kbYbMboatbNbTbG.K.B#6.Eb0#t#kbz.cbPbqaw#1bt.EaHa9bTaA.KbCbu#pbobkbo.EapbSbJ.YaGbba7bLbSbMbHaZbIbIaCaH.0bH.D.N#.bSaCbM.ta7#3aB.E.EbJbNbOa7aGb0bY.0#lbT.5bt.0bEbq.S", +"bM#VbJbnbObIb0bMbQbOaqapbM.ZbobL.xbfbT.EbJ#caAbHa4#5bTb2bt#lbqa9#k#caBbtbt.SbJa2bmaY#JbyaMbybz#f#5.5awbOb0.Z.KbXbY.xb2a9bLaSbH.Uapa9bY#c#E#5.N#tbHbtbTbebEbKbebQbP#cb0bFbE.SbJaw.Ba9aG.xbM.Z.EbM", +".l.xbR#P#sbI.0.ZbnbVbNaA.Z#3.0a6bEbJbG#k#6bIbqbebK.EaGbMap.Ka7bIaAbF.ZbqaH.O#3#.boaMbhbf#3aaab#o#kbt.S.5bYbubRau.MaMaAbMbMbM#s.x#5bX#6aEbSbAbEa9.0bHaGbq.B#ca7bI#cbY.0bXa9bMbb#3#4#3bqbSbq#kan#4", +"aY.F#ibha7aA.iasbbbo#3bebybL#ybLbN.xbu#la6bSaBbNbrbl.xbV.W#lalbIa.bI#taHb..KbN.ibPb0.Kbb#va9a9aL.K.ZaCbObea7bo.F#v#5aGbMbL#1.E#I#6bu#3.K#5bP#3aG#Sbta9#JbObBa2bobIbW.Z#6#ka9.Z#5bqbHbO.7#lbK.EbR", +"bUbJ.ia4.wbHbh.Zba.O#3ap#3a4#nbUaA#kbYbI#c.7b0.5a8a9bS.NbQ.BbFaA.Zbtbtbt#6bIbFbtaAaAbXbHbLbNbpap.SbebI#5awbq.xan#cbo.KbobHbT#R#Ha9#E#5.Kbe#catbfbIbSbubIbeaKbtaKbY#casaG#kbH.ZbybTaO#cbJ.O.ZbIaG", +"b2.PbIaAaAb1.sbX#Ebfb1#t#qaAbAaH.Ebua4#6#kasboapb2.x.xaGbEbe.5br#9bubX#6bEaKbo#qag.ZbTa7bPbH.5#5#k#5aGb0a7btbY.K#LbL#5bM#X#2#N.ya2bu#C#y#3bo#jbB#B#qbb#c#9al.K#5bTbNb0#cas#3bN.x.ZbEbXaHbN.0.Z.0", +"bq#6bS.na9#ca4bq.Zbtbu.Ea9a7#LblbXapbebqbo#6bYbPa4bXbYbT#IaAaZbqay.B.ba4bNboa2#5.x.EbYbo.F#5#DaAap#5bI#ka4bX.EbRat#kasbJas.O.Zbq.7a1aO.nas.S#2#e.2.ZbHbX.S#5#L.SaVbY#caV.MbSbG.dbObqbIbMa3bb#c#L", +"#kaG.San.6#l.EbAa2b0#k.Za4.Oa2#3.FbMbb.ObJaH#kbRbGa1.nbn.5bn#sbM#N.Y.EbSbEawbebqaC.BbIbJbq#6.K#J#cbT.B#3.0beb0bQaAb0bLbqbIb.b#bO.baya7.E#P#kbP.z#e.x.db0btbE#6bBbTbT#caHbTa2aGbY#3bAbBbSbTb3.EbK", +"bwbYbMbEbo.Eap.x#5bHbebo.LbLawbE.x.ZbqbYbMa2.x#5.ZbJbXa7.ZauasbPai#kbE.BbYb2bzaHbP.Z#.a4a2bJ#5#6a9bQ#k#3bLbqanbM.xa8.0a0aObM#PbR#Xa7bq#O.gbRbRbK.xaAbUapbJ.KbNb.awa6b0a7bYbN.SbY.ZapaObubYbY.0a9", +".1bqbA#PaHawaCbVb2bNbWaCbG.EbYbXaGbKbSaw.E#W.Sap.IaGaIalbJb.#Hb1bH.Z#3bqbH#6#Sbl#k.xb1btbN#JawaKbI#kbKbQ.Sboasa4#6#IaCbMbXbJaAbIbT#sbLbrbL#ibW.zbI#5bHbObu.SbSbLaG#5bEa2bt.x#3bX.wbEbjbo.7b0apbW", +".ZaDaGbNbTbQ.6.Z#3a2#3#5aA#lbMbFb0blaAbq#5apbqbXbI.5bO.5bIb2.E.Z.Zbq.Sa9.KaCaGbT#cbRaHbI.xb0bua4#5.B#5aGbLapbMbo.g.Ea0#QbF#N#5.Sbr.wb..z#hbLbTbObB.BaGaHbXbEbTa9bH.ZbLbPa7bX#c#.bSbt.E.BbNbKbNbO", +".5bGbKbYbNa2.da6bJbq#6.Za2bNboa4#c#lbEbbbNbXbu#3bTa0asb2.E.YbTb0.E.s.SbK.B#maAbbbI.0.x#3bNbI#B#ha7bGbFbTbq#3.S.ZbebT.SbWbqaB.gb0bObmbtbIbLbT#3b0byaw#tbJbQbO.x.Sbo#Lb3bNbmbobKbOawbRa2bJb0.YaAa2", +"btaGbEa7#cb1byaGbobqbL.Bbe.7bIbqaBbWbq#5bq#3#cbX.ybHbnbqbIbq#ca7a7bTbJbPbmaKbIaMa1a7bJ.6.xa9atboa9.5bWax#6bW.NbXbUbTa5bT.Kbq#3as.waYa7aMb0bH.Ea6bNa5aG#5aCbTak.EbTaA#5bHbL.xbobhbS#5bHbea4bIap#6", +"bN.5a2bX.xbQaH.B.Z#3.dbU#kbNbMbFa4btbWbM.E.S.x#6asbL.ZbLb1.Z.0akb..0aZb0bTbP.ia9aAbHaGbH#L#cbeaAbPa2#lbQbLbHbw#3bHbq.5.SbM.SbMbIbB#qa5.xbbbi.M#c#tbebob.bYbJbTbA.wbo.wa5aAa8#t.h#3#ibS.ObIan#3.0", +"bHb#bM.Zbq.sb2b0.a.SbbazaRbNbN.nay#3aG.J#ybSbNbNbWaB.YbL#6anbYbE.Z.xaO#cbea9a9be.mbH.nbq.EbBbebB.O#.#6.x#6bI.Kb2bybAbqaAbP.5boat#k#c.ca#.ZbQap.MbTa2be.Za7bQaw#Oan#ObP#5bY#5#5bJbu#6bBan.E.xbI#3", +"bWbX.Z#5bKaua5a7bTbNbY.B.5bRbVbt.6.xaHapbO.bbqbz.x#5bNbJ.Z#3bHa9#2.EbebN#k.Z#5#q.Z.ZafbV.ZbMbNbqbXbSbI#5b0aG#5bDb0bKaHa4aAbu.0bIa2.xaG.E.BbAbNbHa9.SbYbI#6.ZbIbQ#2#cbIbQ.0.KbO#6#c#PaHbM.EbfbHbo", +"bKbIbI.i.0bL.7.waG.Tap.Sa4.0buai.KbS.Oaw.Sap.6aGbO#c.Sa2bJa7bebH.x.0.BbI#c#Bbu#cbR.YbRa7a7bM.xbI.x#Tb0bVa9bI#cb1bq#c#hap#c.x#3#kbI.KbT#mbqbO#6bPbYbYa9bNatbWawala2bq.xaAbTbobtbf#hbO#5bo#3bIa6aw", +".Eb#.E#2b0bTbMbe.S#3bP#6bOaHbSbSbMbYbP.xawasblbQa2by.TbJasaHbe.KbT.KasbqbtaAbH#3bIbobybGbWaC.E#G#..EbqbqaA#6a9bYaM.6#caB.Ea9bKay.ibL#5.Pbta8b0bMbFa7bqbIbea2bJ.E.KbqbS#6bJbYa9.O.raubA.xbY#kaAb2", +"bJbO#lbXbM#laYbT.Zbl.F#5bBbX.xb0bHbebI#3bNbtbTa7.5bO#3bo#cbObNb2#6bOb1a0aYaAbWb2#6bC#9asbH.0bHaC#T#kaHbXbqaA#5#h#3bYb1apaAawbTbS.k.ibha9aYbMb#bMblbeb..nbtasbKbEbzblaA.ZbQbJbYbTa4bTa2b1.EaGbIbF", +"bT.xbKbHbWbq.B#ka7aubqb1anbUbL#JbT.5bM#6.xaAbIbubL#ca7.SbUapbM.5bu.ka9aAbMbJaYbT#SbPbBbfa9#ca9bH.S#cbXby#waA#taHala2.5bKbSa9.EbMa9.SbhbLbM#6b3bTala7ana2bLbqbTbe#3aAbQ.6a9bN#Qbtbqa2.xb1a4bzbqa6", +".x#lb0b..Ebhbqb1a8btbmbbbhbJa2#5b0bebTa5b0bJbBbIbNa9#5a9.x#3.SbXaZa5.HbX#B#UbLb1a2bYbYbMa9bobtbF.0bJ.SapaAaGbG#gaGbSbJana9b1bY#3.E.x.Z#cbqbQ#cbqby#cbMbIa6bLawbEbH.KbtbLbeaOa7bqbealbube.5bK#.bo", +"bK.BbLbX.ZbXbL#3bKbhbu.ya5.ibPbTbLbh#5.Qby.k.i.k#5.Bb0.BbPaHa4a9a0a8#qbL.Qbnbq.ga7#laAa9bT#B#v#jbK#k#ka4#kaKbTaHbL.Ebl.5bN.6a4bIaza2apbt.cbY#cbb.ZbI#cbfapbSbIan.iaMa9bN#l.i.5#4bI#c.na9bIa9bHbe", +"btapapaW#kawbe.0#8aVaW#5a4a9.i.IbNa2a7bw.OasaGbh.F.naG#l#5bBa9#qbBbFbO#5bMbOaAbB#k#X#kb0#kb0aZ#kbS.e.S.0ahaObSaybHa7#k#kaA#U.nbH.0.Z.0bHb0#P#k.S.BbHbebMbI.x.Zbt.J.7.Z#k.S#T#k.E#4aObN.daF.e#4#P", +"#kbQa7btaGa9azbY.WaGaGa4a9.Ob0b0a4bJaHbFaza5aAas#VbL#kbe.0bMbWbwb0bL.xa8bIb1bJbJ.O.F.I#ka2#ibHbBbIaFaC.SaHbY#l.0.0asbPaAa1.KapbPbMbS.0bSbq#l.xbqbTbY#kaH.0a9bt.K#O.Y#P.Ja7bSbQbEahbq.E.Zat.BaVbH", +"btaGaH.7aCbHbNbS.WbsapbSbLa5bO#6.b#k#lbo#5.gaGbcbTax.5be#k#xa6#n#3bIboasbFbebJbO.jbRbLaKaMbo#m.ia6.xa4#PaHbOaFbqa7bBaO.xasb0.E.Z.Eas.x#lbqbzbKbV#c.Z#xb0bY.SaH.EaC#m#.axb0bNbMapbL.4#.by.CbTas#l", +"aF.SaHbJbNbMbC.Zapa2bGbQ#6.KbC.IbG#cbq.K.5#m##b1awbX#k.5aGa9bT#5.xbm.Sa0.FbhbH#qau#6#JaA#B#hbc#5.B#k#4bO#.aGbSbIbeaDbM#k#5apbLbu.E#3bXbtbX.nbob0bKbT#Va2#6bJbIaG.KbDbEab#5bEbS#tb0a0as#lbMa5aA#B", +"bHbOakbE.E#..Ba7aLaT#c#3btaG#NbY.dbfbN.ZaIbKbPa8aC#NbNbSbXaGaAbebObR#5.xbBaZbJa7.k#9aZ#Lbu#vbeaZbKbHby.xbHbO#.#PbTatasbyaB.VbS.x#cbt.FaGbXbLbN.Zbi#cbT.Ea6bYaG#kbObY#ubEbobuapaGa5b2aZbPaZbLau.G", +"btaSaB.D#lbT#ObP#ta6#3#3bBbHbe#k#5.5.ZbFbEby#hbqbq#.bu#lbKby#5#BbEbXaYb.bL.9bXbX.i#BbB#Ab0bLbJ#lbM#k.F.5bJbTb0a7#9btbe#5bt#JbebMaMbqaMa2bzbobt#3bTa4bMbo.0bXbIat#J#3bYa2bJ#6bo#6.K#5#mbtbBbKboaA", +"b1#l.j#Q.D#H.B.xaHbyanbYar.1.xaya2a6bY.x.ZasbIaA.Ba4.5asbE#B#5bL.KbLasaCb#bKbXa2#qaAalbua5.S.5.Ebt.zbXbMbTb1.xbzbIaCaAbyatal#5bt#ca8au#6bebRa9#6as#cbN#cbWa9a7#kaH#Va6.E.E#c.xam#lbBaw#5.5bBbEbA", +"#U.4.0.Q.ZbMbObX.KaKawaKbP#5.bbq.M.Ta2bWawa8aAbI#kbRaGa4bJbubPa9#3bIbPb0bTblbWbn#3bLbt.w#V#U.Z.z.I.ZbRbKb1bLbXbWbBbebLbtbfaK#c#uaA#6#6#S#vbSaMbe.EbHbI.0bo.xa9.Zb1#k#V.xbNa1a1.ZaU#q.dbNaL#6aRbN", +"ah#4bS.Va7#e.Maibqan#kbXaw.BbLbYa2aha9bIaAbGahawaAbB.ibXbT#c.xbbbJapalbe.xbO.#asawbJ.QaObXakaZa9bXb0aAbA.0br#5.sbNaha9#cbVaCbYaVbDaw#c.ZbeaBaebMbKbP.qbMaAbYa1b0bEbSbE.Ba7.i.Q.BbObNboa7bM.Sa7bW", +"aOaw.xambN.M#2bGbJ.0.Z.xbT.E.ZbHapa2bt#k#3bIaibQbTaAbRbT#k#BbMbMbybybNbe.S.O#..Zb2.2.5b0#H#kbKbt#5bu.ZbM.k.K.xbe.xapbea7aG.0aG.5a4bEal#6awbT#Ob0akbT#c#.bH.SbLbIaUa2.xalbH.0.S#sbebf#J.ObNbJbN.O", +".7#l#4.SakasanaObMaGbqbN.0b1bQ#..daGbIbJbTbTa6aCbObIbH#S.Za5aY.xa5#jbobo.K#5bFbLbtb##U#Rbq.hblba.0bna0#5.QbO.EbM#haA#.bLbMbKa5aAbCbBbfbTbqas#3bWa7bNas.Za7.EbYa1bMaVbt.EbYa7#O.BaKbXbuaHbqasbH.E", +".S#6.Z#kapbT#4bIanbHbRb2.S#cbO.xaybb.BbX#t.Z.V.abJbTaA#5.i.F.KbKbFbFaa#3bf#vbobbbnapbM.S#2#lbKbra9bXbI.0bebMb0#h#6bXaAbM#3bnbPbubobH#.bzapbLbNbIaHbP#ca2bI#5a4bLbK#k#k.Z.B#3bPa7bYbbbobJaG.Ea9ak", +"bLbq#kbJ.S.x#c.E#PbW.Z#l.6a6.nasbQ#4btap.0bBbS#cb0bTbBbLaIa9bL#5#q#taAaaaK#nbtbt#n.ZbH#Rb1bqbUbJbKbz.K.ZbobLbtaZb.aZ.kbM#vbIbM.ibTbFan.KbRbEaA#5bqa9bebI#cbLa2bu.x.xbFbPbIan#HbeaA.KbT#m#kbo.Zbq", +"aIbMb1bHbP.pbLbP.xaGbJapbSbX#.#caCaUbTbTbAbX#c.JbXalbXbb#ia7bJala4aM.Ka2#LaC.Kbwb2bBbO.BbL#U.0#mbXbJaAb.bIaG.PawbMb0bMbn.0aKbHbXa4ae.iap#lbIbo#kbBb0bo#cbPaGaAbua7bI.ZbE.E.xaybbbBboatby.2.Sbq#V", +"bLbTbMa9bP.S.xbRbLbYbPakaAa7bM.E.N##.K.Fa8.SbtbNaG#kbPbrbTbIb1bK#Ra7a7#3bbbxbu#qaA.x.5.0.x#XaK#3.xbX.Ka7bLbIbyaAbq#cbq.Y#3aObb.S#k.sa7a9bPbt.aa2bTaAaGb#btbubt.KagaSbL.SbLawa9aVbI.KbtbM#3#cbJbX", +"bc.FbT.g.haqbMbPbP#ebIbN.6a7#kaAaV.cbtb0b2apaObEa5aAb2.KbIbubl.K.B.Z.7bM#5.0.KbE#vbHbXaf#ObY.IbobhbNbm.ibTbhbT#u.SaWaVbHaG#c.ZaU.A#YbIbYbfbSbGbibo#3aMa9#mbP.K.Kb0.Q.S.xa2.ZbNaCbb#6bo.5bTa7bq.B", +"aw.S#4.cawaS#P#.bqa2bX#.#c#caPa2bHbQ.FbY.d.3aw.o.J.5.5btaGa8auaY#GaebXbWasaK#v#a.H#ObPbJ#3aAaU#cbL.KbIbK#5.xb0bI.a#4.ZbbbL.SbI#..I.SbT.E#k#1bL.6bTaNbo#5#3.YalbLanbqbSbTa7bPaxbubfa7bz.0.Yaw.5a4", +".Ea1.6#2bSbqazbX#kal#c.xawaGbSaUa1.5.5a2.WaCaybYbEaVaH.SaAbq.kbaak#k.0bX.xaY#v#5as#sbB.S#ca9#ca9bK.I.Kb0b0bI#kbKaO#VbHaw#3.Sa7aebX#I.xao.wbq.5bM#5.Zbua5bEbe#vaGbybB.S.Ka2#cbz.SbYb0bBbB.Z#5bo#k", +"bNaG.6apbY#k.r.7aSawawbXaC#caCaP.xbYak.VbNbb.WaWaxbM#c#lbNbXaAbIae#O#.bq#tbO#9aKbRbT.S.ZbNbyaHbNb0bPaAbBbJ#LbebMa1bq#kaKa9bL.x#NaH#Q.x.Z.S#Hbq#Xbyb0#5bMbFbBb1beaAbL.xbtbP.KagbJbqbtbL.xbubTbqbM", +"awbIaCaC.x.0a2aG#k.O#kbq.xbGbS#6.SbHbMbSaCahaGbB.Saz.ZbLanbPbTaY#l#.bTaAbqbeaA#La7aGbFaBawb1boap#Jasa9bWbWbIbObX.NaGbSbP#5.ZbrbMaAbL#kbIbM#hbKbX#caA#3bebuaAbebfbq#6bNa7#5a7bEbobubEbTbE#4#3aGbL", +"###caG.SbEboaGbMbMbY#Vbea4bvahaW#PaC.Zbq.0#6bz#6.J#Waz#J#lbPbLbt.0b0.xaKbO#mbLa5bwb0#kaH.Sa2bWaAbIbJatb0#6.iap.xa1bY#5awa0a9bnaebaa7aY.EbXb0#l#ka8#Ca9bobTaKbYaK#rasbIbLbN.SasaG.4a2.SbobXbK.Ybq", +"an.5bua4by#5.O#c.haCbJanbY#caJbfbHasbNbY.2aq#JaAa7aGa2bybOaAapaYb2#9bLbPbWbXb2.SaHaHanby#3.hbTaObX#3bL.SbT.x.ibTa2bN#5bBaGbobJbqbt#lb#.EbJ.5a9bL#3beaKbOa9bu.E#vbK.MbtbqbN#5bM#3#k.KbtbMbI#c#cbo", +"bobfbLbYaAayaA.M.Eal.nbybLbubE#caia1.7btbBaM.L#BbSaC.5#kaCb0bOaYbMbAb1btbPbL#nbLaU#u.SbebNb..5#sbMbub0a9a8b3bTbI#V#3bubF#q#vbn.2.KbMbo.kbObLbJbJboboaC.KbY#man#mbqbBbLapbMbbaGbS.5aHa7a7bYbebLaG", +"bT#Eam#p#5aAaL#3bOanbqbVbEajaHapaO.SaH.SbObhbM.H.a.SalaGbTbYbh#6bJbM.p.2a9aA.0aoboay#9.E.x.E.g.2a8.5bn.sboaA.Z#6axbF#Ea5ab.4btbJb#bbbPbzbNaAbxbM#5#5.K.iaqbB.K.Fa9anbTbH#k.EbP.SbIbeb0bYbu.x#3bq", +"#PbN#Ta9aVaWbtaG#VbP.ZbhbXbM#h.G#d...ubYbq.7#k.0bNbwadbSbea6aV.5.X.1bE.J.ZaAbS#5.5.Z#T##bY.E.F#l.EbH#c.Ebu.ZaH.CbTbMbXbT#n.5bMbM.JbEbG.5bBbSah.KasbqbtaYala5bJbJ#cbo#3bNbubnaC.gan.cby.Obu.waAa0", +"#4aGbN.E.BataG#ubY.x.EbLbM.2.iaKa9ap#EaGbAas.S#..BbYbNbN#c.Ea2#3#c.JbN.5apa2bRb0.FbNaA.6bWbQ#.bPa9by.Sb2a2bTbE#6bTbIbq#5aA#5bua0beapbEaGbq#capa7aAbMa0bIbt.KaAb0ay#3.Ka2.BbI.sbqbSay.x.Z.xbo#SbI", +"ak.EbSaVbRbSbbbbapbi.KapbF#5bCbtbBbbbOaAbIbI.EbXbI.0.Ba2bqaG.5.dbSbNaCap#mapbubLaM#kapbFbhapbuapaCbJbobSbqbo#FbHbub#asbJbhbJbh.B.FbHbq.0a2aw.BbtaAbubXbI#kbXbPbAaPasbo#5aC.5a7.hbt#kaH#5#c.IbL#5", +"aB.0bMa4#6bP.KbtbDaW#5.W#yaw#qbybLbI#vbXbT#hbLb0ay#5#3#kbA#cbBa9blaGaMbo#Ebh#W#maG#q#Lb2bobe#vbz#AbNaB#5bo#5aw#v.0b0.KbK.EaAbJb1#3bKa9.KbObJ#c.xaAbLbobLbMbubIaYbDbSa6aAbI.Eb0.5bt.xbubH#ca7bbbL", +"aq.nbX.SaH#3bLa9#B#BbiaTap#wbi#Cbh#kbh#5a5#6bm.ibJbqbMbpbM.0bMbb#p#jbu#m#J#9#9aMblbu#6a9#5bfbIb0a9bfbUbIbyb0bobWb0bt.i.SbX#m.Bbbbq#c.KbNbza4b1bKbWbSbLbObobLbeb0arbbbu#k#6bLbMal.EbMbE.Bala9#k#c", +"#kasbMbybXaZ#v#qbn#3boaAbWaXbK.R#I#hbJ.5bU#ha2a2aAbTbEbO#5aAbM.0b0bb#m#6#tbTbhbnbzbobT#9bobeaAbb#ubIbe#p#q.Kbbbua9bPbI.KaY#kbh#6.8a7a7a5bXbBbJbI#kbu#la8.OaYasbMbN#3bL#5.D.i.S#Hbf#h.EbubNa9.Bbe", +"#QbLbIbPas#5a9bP#Lbra7bBbtbI#c.x.Z.EbKbJaha4.RaNbTbLaZ.ZbMbtbFbJbtaAakbO#q.ibWas#3#I#3bY#2bJaGbHaLbeaAbebybt#9bT#kbPbMbPbtbebH.EbX#nbIbObqb1b0#vbRaZbt.BaYaw.5aA.R#3#8#k#cbHbXbMbhbcb1b0bTawaV.0", +"bTbTa7bmbRbhbma9.g#b.y.waG.UanaCbKaH.Ea4bN.Jaya4aYbKbubTbL#hbr.Z.SbYaY.ObL#sbPaYbq.5ak.E.7a4aebY.kaLaMaM#mbS#qbtbra9bTbobLbhbX#haZbP#hbXa8#h.xb##.aAbPbPbXaYbJ#v.Bawbe.x.KaA#k.QbTbTbXapbE.xaCbQ", +".K.K.E.x.xbY.Ka9.bawaDbq.v.ZaO#da1a2.ca2.aa2aGawbMbTbObTb0bB.zbe#T.V.xb0#ca9a8#Ja4.S#5bH.Oa9.B.SbtbTbL.ZbH#lbBb0aG.ZaAbI.ZbubLb0#k#K.n.bbNazaq#q.SbE#iap#Db1#l.5#3.KbMbAaAbE#BaAaKapaAa5b1bTbua8", +"bwanbObI#r.7bu#ybSaG.5.Q#G#.bVaw#cbLa4.BbObQbqbGbMbLbtb1.KbPbMa9#..MbqbobRbMaBa8a9.5b1awbTbSbybKaAbX.S#3bXbP#NbM#qasa5bMaAbIaAbL.S.x#4.M.SbYa5bLbqbSa9#zaAboan#.bLbwbubebX#qbS#5.x.i.KbI#m.2asaA", +"#6be#3a1.E##bmbMbBbYbP#UbRbRa7#6bObWbXbI.E#qbJbTb0byaqbJbMbXbWbt#X.NbH.ZbNaAbu.i#cbKbKbfa2bBbXbN.ZbTbRbT#sb0#5bJ.Z#.bPbXaMb1#6.E.IbR.naObN#kbTb.bI.EbobMaAbAbHaAaGbJaA#c#qbCbo#5bLbMbL#cbObXbObX", +".KbJ.7#XbSbWbtaG.Sa0#sbTa8a7a8bTbIaKbLbIbJbhbR#3aAbLbMb0bMaAbIaA.7bMbN.ZbS#BbX.Kap#AaibW#kbNbTbIb0bXa7#k#3.IbH.iasboaYa2asbqa5bIbLa7bMaW#ratasa0a1bq#c#va9#3.xak#5#nbe#3#5bebXbIbMbtbJaY#kbXbTbo", +"bFbz.7bT.5#kbybo#hbWbobtb3#na5.7#J.IaYboaYb2bPbOasaCbe.Kb0bPbeaBbWaObMaHbJ#EbY#mbqa2#kaAa2#5aO#c.5b#ag.5b0bObK#2aZbL.EbT#5bLaYbJ.K#vbNaG#k#3bubIbT.F#Lbea9#A.ZbKbQ#3b1bL#3#6bObtaAbOanaBbJaAbTbb", +".Kbna2bq.Z.0#m#vaZbTbo#L#BbubPaAbr#cb1##bM#tbH#vbMbT.Za8beb0#.aA#ka9bPbObL#kbB#5bSb0aGbIbqbT#Ja7b#bIbObnbP.Bb1bEbLbobza0bLbobI.Ka5b0byapapbQ.Ea8bHbLa2bobS#3aG.xb0bfbE#3bub0bz#c#6bIbhbI#6bLbebM", +".KaKbYae.S.B#5bIbqbtbu#y#E#cbSbJ.F#3#ca2awbIa4aHbIa9bIbTbWaA#hbq.h.7bHby.fbt#6bYbqapa9bMbBbYbNb1#k.F#k.0bI.0bh.ZbIbh.Eb0bt.Bbha7#maK#Sbi.V#k.KbX.E#kb0a8bua5.5.0aI#AaKbuaK#5aHb0#hbtbRaGbLbKbLbA", +"b0be#P##.EbBaAapbPa7bNbv#7.a.0bObsaFapaGbGbSa2.6aAbTbMbObJ#5bI#5bIb0bWbtbIa7aWbVbtbM.xa9.ZbTbqap.x.s#3.g#3bL#NbK#3##a9aY.xbh.0#5#Jbh#EbebM#cbT.6bqa4b1aLbNa9bM#VaM#6apaA.xa9aM#5bJbM.BaZbXa9bubX", +"bybIbSaGb0.caMbYbJ.r.5#k#P#XbL#.as#XbJbK.2btaGbD.Z.PaYbH#h.B#cbb#KbebqbbbNbiay.Ya7.Z#UaObH.6#2.7bJbH.0#3asbKaA#5#2bOaSbLbPb0.S.g.d.KbGbEbNb0bXbn#X.B#H.0#2.Z.n.SbYbHbMbE.KbTa2.Za9#caKbo.KbtbMbo", +".5aAbWbS.Ebo.Z.K.BbJbEbX.5aH.5bqaA.EasaHbobeaGaC#s#XbIbLbIap#3.O#3.xbIbtaCa2aLbs.SbObIbU.s.xaAbPbIb0bLaAb1bb#6#mbM.0bt#UbN.g.ZbLbu#VaH#ka0bo.5aK.ZbP.KbJbWa8bJ.Ia7aK.SbEb#a4bLat#nbobebLbNaAbTaM", +"bbapb1a9bobP.xa4aGbqbq.Ba9bOaHbqbT.jbXbI#cbMbiaGbWbI#XapaSbObIbEbqbua2bo#5bV#6aybW#XaF#IbL.Oaea7#O.0#kaBbM#qaA#maA.gbbbTbJ.EbBbJ.dbMaGaAbNbTb0b#b0.hbH.BbRbIbEbWaAawa7beaFaAbMbebtbWbL#t#L#5#3#c", +".5a4.E#kbd#lbXbOa7#cbo.xbHbO.E#3#ka6bobLaGbKbq#3ae#.#Nb0a8a7aH#6#tbzbI#6#cbCapbobMbMbF#k.Bbr#.b#.Zb0#6bOasbMbybMb.a9.i.SbqbLbcbTbNa4#6a7#cbTbJbIbbbT.KbObKbF.g.K.0#3bS.4aG#3bY.xbubTaGapbYbMaAbL", +".5aA.K.K.ZbGbBbVbobHbybz#kbB#c.SbNbebHbea7a4bTbMbTbM.IbT#.aGbJbSbF.E#EbJbebtaYbu#s.SbWb3bybI.5bIbH.gb#bLaAaY#qbIb2bMbY.iaAbXbLbf#eawbOapb3bLbBbT#ha9bIbh.0b0bLbPbY#5bX.BboalbI.Kby#A.KaAbe.K#5aH", +"#kbtaGbqbebX.7bO#c#JaGbPbo#3b0bu#haHbebWbXbBbqbW.Pa7bJbO.EbubKapaM#3bXaYaAbRaZbPbBbP.Qa9.gbI#3bI.xbTbI#cbmbebobJaMbM#3bKbP.Y#ua8#cbG.K#kbebqbnbLas.KbXaAbP#3a9bMasap.5#6#l.x.6awbzbubtbfbbbeaAaK", +".B#5.5bebYbta7#3#6bXaG#x.KbY#qbNboa4.Ma9bNaA.gas#..l.QbMb0#c#5b0#5#j#3bIby.kbWaYbMbBbCbr#3bKb0aAbL#ObLbP#3bhbT#nbLbobPbybeaA#Z.K.MbH.ZaC#6bTbtasaZ.Kbt#5bobLaYbebWaCbya7bNbuby.7bob.bebtbL#nbYaA", +"#t.5bTbMbHapbMa7bea9bobo#maAa9.KaHbl#AbQ.4.5bq#saS#2.Fakbh.x.BbDbo#5a9bMa0b..g.I#qb0a8bJ.Zbrbt#3#HbXbN.ibTbobP#u.i#g#3.iaAaK#6bnaP.xaGbtbM.EaYbLbIaM#ma8bIabaAaKbt#ka9bIbebFbHbqbmanbT#3#5#5#5bl", +".nbH#c.n#lbq#kaHbX.SbTapa7bEbBb2#ca2.J.6a9.ib#bT#cbe#t#3bI#DaAbX#6alaAa9bB.E#mbH.ib0asbebbbKas#3.0.KbPa7#l#cbo.Z#5a2#5aAa9bybTa9#Q.x#N.x.ZbJ#kbqbL.BaebWa7.O.UaSbN#qby.Zbo.0.SbNbqay.E.N.Ea9.MbE", +"a7bYb2.EbYbP.xb0.SbobVb0.KbNb0.Eaya1aGaA.ZbqbtbJbzaAbeaAa4.K#BbTaqbBbIb0bRaYbIbobJ.KbubPbLaAbo.sa9#c#k.KbubIaqb1axaw.0be#.#3#kaGbTbLbIbqbP.jbM.B.S#R.xaO.i#2.x.ZbYbIbua9.BbI#lbKapbfbubMa4a2at.Z", +"bLbH.E.K.Zb0.xaxbYbMbq#6#lbO#3aAapb0bEbEbn#.bOb.#Lbbb1bt.Kbe#.aGbMbLbTa9#.bObJbIbB.z#5bLbobI#ibb.SbebXa9#kaGbz#c.ZbTbN#kbO.Sa7bQ.PbPbobLbI.F#5bXaA#NbMbT#Ia7.IbIboa9btbObNbP#V.ra7bNbNaObw.fbOap", +"apbyaw.5bL.SbEbK.x.E#5.Z#cbA#caGan.Ba4.Faqb.bbaYawaA#5bSbLaMa9#5b#bMbBaAbTa9b0bqbo.Eas#hbWbXbL#3a7bR.FaHbt.6.SbIbqbtbtbJbqbobebEasbybXbfbX#3bJ.F.h#lbI.BaA.sbQbMbP.E.ZbNbIa9bB#k#3asaHawbqbX.K#.", +"aAbSasaGa4bIbS#6bobla7#5bLbS.xbA.x.Nbo#kbEbTbqaMbtbtbt#qawbLaAbt.KbLa8bTb#bIbh.BbXbca9#kbIbNbX.8bF.VbJapbLa9bybNbJ.0.Y#k#6.xbu##bO.xbK.SbIa8#k#tbWaAbIbIbH#lb1.0bt#6b0a2.EbAaCbIbS.EbL.0boaHbRbN", +"bT#6btbt#L.Kbh.KbI.FbobIbJbqaAboaw.BbNbIaHbXb#.U#3bwbT#6a9.Ka9aG.Ha9#kbJbebLaAbU.KbMa9aAbMa9bJbL#3aGb0a9bubL#rbtbNbobO.EboaG.K#6bTaMbOaMbtaYbtaMa7bJaAb0bOaK.Fbo.0bYbqaqaAbt#5aZ#kbebObobX.gbuas", +"#qbSbPbKbubAanboapb0.Eby.5bYb0bYa4#cbRbPa6bObL#qa4a9aA#3#6bubu#5.ga2b1b0bJapbL#3.saA#lb0bTbtbHbIbQ.Da9.7.x.7apbJa2bPaHbLbY#k#6bMbEa8bB.ibJbIbOa9.ibMbqbnbe.Ba5bJbT.0.Z.S#5.B#t#c#q.xaAbta5.SbMaA", +"aHbxa2be#6bBby#t#k.xbua4a4bPa9aHap.0#cbAbWbIa2.l#JbKa9bo#AbTb0bzbeaAaAa0btbI.lbLbybXbAbTa5bLaZbubJbubLbya2anbJbT.2a9a2bXa4bTaHbHbubnaA#Lby#3a5bobubB#q#5#hb0btb0a7bM.xbA.xa9bYaKbKa8asbrbOaY#vbT", +".5a9apbX#cbH.SbybYbM#5bYbKapbIbX.M.Vazay.ObAbI.SbFbPbf.Ca4b0bobLbP.xapbN.7.KbwaAbqbL#ka2.SbLapa2buaGbPa9b0au#c#6.Maw.Va9aAbPbtbL.N#c.cbF.E#6aGalbPbM.YbNbW#cbLaGbHaC#4bLbX#cbIbHaF.Zak#l.B#k#Pa7", +"a9.xaw#kbN#cbo.6bMawbIbMboaFbuap.MaH#ka2.Kaw#3bL.hbPapa8#5bTbLb#bq.Z#kbJa9#JaubebY#6btbP#3bT#c.Ia9bOa9byaAbu#5bea9.0a4aAapbqbOa5bYaQa7.R.0.EbIbIbfahbO.S#3bqbTbo.7.xbf#3.xa9#ebeb1bMa7bo#.#Ha9.E", +".K.nbNa2bA.Z.6bYbY#kbK.M.xaBas#3.Zad#5#.a2#k.EbNaAasbMbTbXbP#3b0bqbNaA.xapbJaHaKbTbfawaHbb.Ea2bK#3bebtbeaKapby#5anap#kbYbT#tbqbT.S.x#5#haC#qaYbJana7#3bY#3#3bHbJbI#6bSaA.FbQbOaw.0bG#kbLb0bQ.rbM", +"bQa4bHbqaCbbajbQapbMby.KbtaG.SbyaGapan#ka9bX.K#6bMbK#cbRbI.7#hbP#4bLaObSasbebB#xaw.E.SbP#lbobQanaKbtbWbtb0bL#Mb0bLa7apa8bObTbHaMbPbT#6a0.zbIaAbh#lbbbLbSbq#5bWaCbo#6bqbybebPbubFbq#kbPbYaCbJbta2", +"awbLa4.S.Map#lblbUaw.xaAbNbr.ZbPaAbIbtaGapbQbRb1awaYbM#vbfbJbtbXaS.xbTbebMbYbfbI.5bSaA#c#6bHb0#cbbbOaLaAbubN#5bo#5bWalbIaAbybJbTa0bobIbTa5bMaMbPbTbSbPb0#5bN.EbybI#c#v#6aA#5btbI#3#cbI.S#6bu.ZbT", +"aGbqboaGbJ.5.K.SbE#c.5bobO.S#5.bb0bh.hb.asbMaG.7bLbzaZ#3#kasbPbI#ka2.ZaH.Ya5awbtbQ.KbMbubY.5bybPasbe#vbQbFbb#JbubXbn.ib0bLa0bTa9bObJ.gbebMbSbJbNaGbqa7bo.xaGbIaHbB#mbobwbe#3.KbBa9#5by.KbEbTbTap", +".xbyawbqa2bzbHbNa9bL.E#3bNaG#3aAa9a8aZbLbKb0anbYaY.SbLbOaAbL#5b0.E#kaGbIbOblbB#vbX.7#5.ZbuaGbMawbBbya9b0#3bfb0#5a5.G#5.ibMbeaAbMa7#xbf.Z.ZbEaC#c.EbTbSbMaG.0bfapbIapbRbtbl#m#3bOa9b#a9bL#mbB#c#n", +"bz.xaGaia6#kay.ZbIapbP.xbYbP#kby#bavbh.Ka9a7be.xbS.i.EbtbJa5.xaA.E#5#kbTat#5boa9bNat.EbTaEbXaGbWa9.KbebE.KbT#5#3bg.k#h.sbnaA.5a9bTbB#Pbo.Ma2adaVb0#cbuap#ka8a4bT#faAabaM#qbobeaA#5bo#v.K#6bE#tas", +".5#4bfb.be#t#k#c.F.0.0bYbO#P#c.FaFakapbYbWbNaM.K.MaGbBbqaH.SbmaZ#d.BaiaGaGaHaCby#P.B#e#PbR.x.xasb0.IbWbTbIbo.ZbMbYa7bIbN#k.E.x.I.6bLbMbYb0bX.M#6#lbJ.Z#NbT.t.s.xa4#3a6bR.S.Ka2bo.WbY.J#cbua7bX#3", +"aG.EbfbebEbE.n.Eb0aw.FbEasbMa1bL#k.naAaGbMaw#.bA#caCbYaAbzaAbMav#T#k#V#lazbT.RbObq.0.7bLaFbIbQa7#kaK.EaKbXbMb0b.aHa9bSbe#kbP.Eae#kbobo.YbuaAa6bT.IbM#..EbIbMbBbTbIbqbL#c#6bMa9bq#fbSa9aH.K#3#can", +"bX#caKas#6#ta7bIa7bBbLbPbYbo#5a2bK#4.JbI.MbBbobbaybqbY.xbJbMa9bI.xaGaqawaHbTbQ#cbW#c.5bfbxbobt#SbtbIbRbJaYasbXbtazbXbobMbPbJbTa8#ca7.ZbN#kaH#3an.B.4aZ.ZbhbK#Q.x.xbt.EbP.EbYbLbt.R#caUb0aGbqbyag", +".5aObobnapa8#c#Pbb#t#3aK#tbo#JbB.JbLbEbQ#kbuaH.Jb0bX.6#5.xa4#5#kbTbNaCbMawbK.KbLbybPbu#6bbbZ#vac.Zbn#kbTbebLbfbIaybobfbo#DbM#nasaHbX#5bMbSaAbMbM.E#5bJbM#3a7a9.ibybSbNaM.xaw#3bHaW#6aLbea9b.#B#.", +"bIbKbeaG#vbe#c.x#3blan#t#k#xbubobRaVa9bNbMa2.EbEbObtbB.0ap#5.0.xawaAbMbHa9bS.S.K.KaKbwbt#q#ubZ#jbLbTbObTbNaYbebTbYbSbY#6aAbt#m#qbqbo#c.S#5bo.O.KbtbTa8.6.Eb.aAbL.5bTa7bHbe.x.ZbtbtbPbYb0be#.bnbH", +"aC#.a9bFbobtbPbLbLbobe#3bbbbbt#qbban.EawbE#.bqbEbHbfb0#5bI.x#c#cbLbXbybtbm.SbI.ybN.Kbe.K#qbD#q#za8.5bfbBbJ.BbTbLaVbMbV#3a6brbT#u.ZbA#kbF#.bMbEbW#B#.bB#naA.K#3bT#cbLapboa2#5#.bobu.KbubyaAbhbIb0", +"#Oa2bX.KbeaA.5a1b0.xaAaAa1#kb1.6a9aA#DbH.ZaVbKbqaA.SbJaA.XbS.S.b#gaA#t.EbL.xbMbWbea2bRbtbubWaM#5.ZaZbP.EbMbJ#mbJ.V#GbHaH#3bc.KaYbL#ca9.0#5a2bqbfbMaZbtaZaAbM#tasbeaCb0bTa4.x.K.E#vbE#LbraKbKbIaA", +".xakaKbybW#6bM#l#ka7#k.nbM.0bH#Pa2#3by#..K#kak#0bnbMaA.5.K.BbNa6aK.ka9bLbc.wbL.7.xaAbqbAbo#JawaB.KbLbq#BbebMbMbL.##Va7#2.S.B.0bIbEb2.7#6.Z.KbJbq#m#5a8bWby#ua8#6#3#lawbTbea7bL#3#3#J#5#.#3.ib#bM" +}; diff --git a/plugins/styles/metal/stonedark.xpm b/plugins/styles/metal/stonedark.xpm new file mode 100644 index 0000000..bae15c2 --- /dev/null +++ b/plugins/styles/metal/stonedark.xpm @@ -0,0 +1,353 @@ +/* XPM */ +static const char *stonedark_xpm[] = { +/* width height num_colors chars_per_pixel */ +" 96 96 250 2", +/* colors */ +".. c #020202", +".# c #4e554a", +".a c #1f2321", +".b c #838c83", +".c c #343a34", +".d c #697169", +".e c #0e100e", +".f c #9ca59c", +".g c #45443d", +".h c #2b2a25", +".i c #61605d", +".j c #7c7b72", +".k c #171615", +".l c #969490", +".m c #43473b", +".n c #5e6359", +".o c #272e2b", +".p c #afada9", +".q c #090909", +".r c #797f73", +".s c #3c3b35", +".t c #171915", +".u c #8c988c", +".v c #2f322a", +".w c #57564e", +".x c #484b44", +".y c #737269", +".z c #24231f", +".A c #11110e", +".B c #80847b", +".C c #8e8c83", +".D c #a9ada3", +".E c #656860", +".F c #1a1c19", +".G c #3c3935", +".H c #0c0c0c", +".I c #4e4d46", +".J c #3d433d", +".K c #30322f", +".L c #060606", +".M c #565e56", +".N c #717a71", +".O c #989c93", +".P c #86847c", +".Q c #6a6961", +".R c #4e5551", +".S c #383a34", +".T c #b0b4aa", +".U c #1e1d1a", +".V c #252a25", +".W c #69716d", +".X c #121512", +".Y c #0c0e0c", +".Z c #5b5e56", +".0 c #282a25", +".1 c #8b948b", +".2 c #0f100e", +".3 c #2e3632", +".4 c #090909", +".5 c #767a71", +".6 c #131512", +".7 c #90948b", +".8 c #b6b4b0", +".9 c #060606", +"#. c #21231f", +"## c #a1a59c", +"#a c #454445", +"#b c #33302d", +"#c c #434743", +"#d c #626d67", +"#e c #2b2e27", +"#f c #4a4d4e", +"#g c #4e4d4e", +"#h c #333230", +"#i c #9e9c93", +"#j c #393b3c", +"#k c #52554e", +"#l c #888c83", +"#m c #2d2e2d", +"#n c #7e7f7e", +"#o c #5e6362", +"#p c #797f7e", +"#q c #3d3e3d", +"#r c #92988c", +"#s c #33322d", +"#t c #595a59", +"#u c #757675", +"#v c #252625", +"#w c #828887", +"#x c #8f908f", +"#y c #676d6c", +"#z c #1c1d1e", +"#A c #878887", +"#B c #6c6d6c", +"#C c #111312", +"#D c #232625", +"#E c #2b2e2d", +"#F c #020202", +"#G c #6e7163", +"#H c #46473e", +"#I c #2d2e27", +"#J c #626362", +"#K c #7e7f73", +"#L c #181918", +"#M c #979897", +"#N c #3d3e36", +"#O c #595a50", +"#P c #4b5047", +"#Q c #75766b", +"#R c #252620", +"#S c #131313", +"#T c #82887c", +"#U c #8f9084", +"#V c #676d62", +"#W c #0e0e0e", +"#X c #4f5047", +"#Y c #a8a99c", +"#Z c #080808", +"#0 c #9aa094", +"#1 c #87887c", +"#2 c #6c6d62", +"#3 c #525551", +"#4 c #3a3e36", +"#5 c #404340", +"#6 c #6d716d", +"#7 c #363e3d", +"#8 c #0b0b0b", +"#9 c #1e1f1e", +"a. c #a1a9a7", +"a# c #939c98", +"aa c #5d6061", +"ab c #292a2b", +"ac c #151617", +"ad c #505a50", +"ae c #626359", +"af c #181915", +"ag c #97988c", +"ah c #606860", +"ai c #7b847b", +"aj c #191c19", +"ak c #32362e", +"al c #131311", +"am c #aab1a9", +"an c #1d1f1d", +"ao c #0e0e0b", +"ap c #323632", +"aq c #070707", +"ar c #b1b8b0", +"as c #1e1f1d", +"at c #111311", +"au c #0b0b0b", +"av c #b6b8b3", +"aw c #232623", +"ax c #a2a9a1", +"ay c #444b45", +"az c #2d322d", +"aA c #353633", +"aB c #9fa099", +"aC c #8a9089", +"aD c #939c93", +"aE c #040404", +"aF c #70766b", +"aG c #555a55", +"aH c #707670", +"aI c #afb1a9", +"aJ c #070707", +"aK c #464746", +"aL c #4b504f", +"aM c #4f504f", +"aN c #3a3e3d", +"aO c #555a50", +"aP c #606864", +"aQ c #7b8480", +"aR c #191c1a", +"aS c #35362e", +"aT c #1d1f1e", +"aU c #2d322f", +"aV c #4e554e", +"aW c #343a37", +"aX c #9ca5a0", +"aY c #454442", +"aZ c #2b2a29", +"a0 c #7c7b77", +"a1 c #43473e", +"a2 c #5e635e", +"a3 c #090909", +"a4 c #797f79", +"a5 c #3c3b39", +"a6 c #171917", +"a7 c #2f322d", +"a8 c #575653", +"a9 c #484b48", +"b. c #73726e", +"b# c #242322", +"ba c #11110f", +"bb c #808480", +"bc c #8e8c88", +"bd c #a8ada8", +"be c #646864", +"bf c #1a1c1a", +"bg c #3c3939", +"bh c #4e4d4a", +"bi c #3d4340", +"bj c #a7a5a1", +"bk c #717a76", +"bl c #989c98", +"bm c #868480", +"bn c #6a6966", +"bo c #373a37", +"bp c #afb4af", +"bq c #40433d", +"br c #1e1d1c", +"bs c #252a28", +"bt c #5a5e5a", +"bu c #282a28", +"bv c #8b9490", +"bw c #0f100f", +"bx c #090909", +"by c #767a76", +"bz c #131513", +"bA c #909490", +"bB c #212321", +"bC c #a1a5a1", +"bD c #434746", +"bE c #2b2e2b", +"bF c #888c88", +"bG c #919891", +"bH c #6d7169", +"bI c #464743", +"bJ c #2d2e2b", +"bK c #7e7f79", +"bL c #3d3e3a", +"bM c #595a55", +"bN c #4b504b", +"bO c #757670", +"bP c #252623", +"bQ c #828882", +"bR c #8f9089", +"bS c #676d67", +"bT c #4f504b", +"bU c #a7a9a1", +"bV c #99a099", +"bW c #878882", +"bX c #6c6d67", +"bY c #3a3e3a", +"bZ c #424445", +"b0 c #62635e", +"b1 c #181917", +"b2 c #979891", +"b3 c #0e0e0c", +/* pixels */ +".x.0.OaHbI.2azbK.rbJaF.Zbq.EbqbT#..x#6at.S.KaGbOaz#5albJb1b0bAayaw#..S##.xb0an#IbI#NalaFbH.5a6bN#kbSbobT.5bObu.Z#k.5.ZaYbL.ga9aZ#e.EaDbqap#..Z.S.SbP.ZbMaF.BbI#lbT#3ap.xbYbO.SbL.ZbEbXb0awbL#PbI", +"#k#c#..San#c.5bqa7bqb0bR.SbW#P.KbLawbqbLbCbHbT.5bY.c.ibObMa0aD.5.xbHa9.6bHa1bT.raAbIb0an#3#5bt#caAbXbWbYbtbSbM.SaCbq.t.xa5.SbLaAbLapbP#cbo.SaCbt#kbPaybIaOaGbMaOaG#c#k#S.Z#5#3blbIaO#k.Z.xbHbLaH", +"#3bOaHa1.xb0bH.YasbN#c#kbq#cbM#kbYbMboatbNbTbG.K.B#6.Eb0#t#kbz.cbPbqaw#1bt.EaHa9bTaA.KbCbu#pbobkbo.EapbSbJ.YaGbba7bLbSbMbHaZbIbIaCaH.0bH.D.N#.bSaCbM.ta7#3aB.E.EbJbNbOa7aGb0bY.0#lbT.5bt.0bEbq.S", +"bM#VbJbnbObIb0bMbQbOaqapbM.ZbobL.xbfbT.EbJ#caAbHa4#5bTb2bt#lbqa9#k#caBbtbt.SbJa2bmaY#JbyaMbybz#f#5.5awbOb0.Z.KbXbY.xb2a9bLaSbH.Uapa9bY#c#E#5.N#tbHbtbTbebEbKbebQbP#cb0bFbE.SbJaw.Ba9aG.xbM.Z.EbM", +".l.xbR#P#sbI.0.ZbnbVbNaA.Z#3.0a6bEbJbG#k#6bIbqbebK.EaGbMap.Ka7bIaAbF.ZbqaH.O#3#.boaMbhbf#3aaab#o#kbt.S.5bYbubRau.MaMaAbMbMbM#s.x#5bX#6aEbSbAbEa9.0bHaGbq.B#ca7bI#cbY.0bXa9bMbb#3#4#3bqbSbq#kan#4", +"aY.F#ibha7aA.iasbbbo#3bebybL#ybLbN.xbu#la6bSaBbNbrbl.xbV.W#lalbIa.bI#taHb..KbN.ibPb0.Kbb#va9a9aL.K.ZaCbObea7bo.F#v#5aGbMbL#1.E#I#6bu#3.K#5bP#3aG#Sbta9#JbObBa2bobIbW.Z#6#ka9.Z#5bqbHbO.7#lbK.EbR", +"bUbJ.ia4.wbHbh.Zba.O#3ap#3a4#nbUaA#kbYbI#c.7b0.5a8a9bS.NbQ.BbFaA.Zbtbtbt#6bIbFbtaAaAbXbHbLbNbpap.SbebI#5awbq.xan#cbo.KbobHbT#R#Ha9#E#5.Kbe#catbfbIbSbubIbeaKbtaKbY#casaG#kbH.ZbybTaO#cbJ.O.ZbIaG", +"b2.PbIaAaAb1.sbX#Ebfb1#t#qaAbAaH.Ebua4#6#kasboapb2.x.xaGbEbe.5br#9bubX#6bEaKbo#qag.ZbTa7bPbH.5#5#k#5aGb0a7btbY.K#LbL#5bM#X#2#N.ya2bu#C#y#3bo#jbB#B#qbb#c#9al.K#5bTbNb0#cas#3bN.x.ZbEbXaHbN.0.Z.0", +"bq#6bS.na9#ca4bq.Zbtbu.Ea9a7#LblbXapbebqbo#6bYbPa4bXbYbT#IaAaZbqay.B.ba4bNboa2#5.x.EbYbo.F#5#DaAap#5bI#ka4bX.EbRat#kasbJas.O.Zbq.7a1aO.nas.S#2#e.2.ZbHbX.S#5#L.SaVbY#caV.MbSbG.dbObqbIbMa3bb#c#L", +"#kaG.San.6#l.EbAa2b0#k.Za4.Oa2#3.FbMbb.ObJaH#kbRbGa1.nbn.5bn#sbM#N.Y.EbSbEawbebqaC.BbIbJbq#6.K#J#cbT.B#3.0beb0bQaAb0bLbqbIb.b#bO.baya7.E#P#kbP.z#e.x.db0btbE#6bBbTbT#caHbTa2aGbY#3bAbBbSbTb3.EbK", +"bwbYbMbEbo.Eap.x#5bHbebo.LbLawbE.x.ZbqbYbMa2.x#5.ZbJbXa7.ZauasbPai#kbE.BbYb2bzaHbP.Z#.a4a2bJ#5#6a9bQ#k#3bLbqanbM.xa8.0a0aObM#PbR#Xa7bq#O.gbRbRbK.xaAbUapbJ.KbNb.awa6b0a7bYbN.SbY.ZapaObubYbY.0a9", +".1bqbA#PaHawaCbVb2bNbWaCbG.EbYbXaGbKbSaw.E#W.Sap.IaGaIalbJb.#Hb1bH.Z#3bqbH#6#Sbl#k.xb1btbN#JawaKbI#kbKbQ.Sboasa4#6#IaCbMbXbJaAbIbT#sbLbrbL#ibW.zbI#5bHbObu.SbSbLaG#5bEa2bt.x#3bX.wbEbjbo.7b0apbW", +".ZaDaGbNbTbQ.6.Z#3a2#3#5aA#lbMbFb0blaAbq#5apbqbXbI.5bO.5bIb2.E.Z.Zbq.Sa9.KaCaGbT#cbRaHbI.xb0bua4#5.B#5aGbLapbMbo.g.Ea0#QbF#N#5.Sbr.wb..z#hbLbTbObB.BaGaHbXbEbTa9bH.ZbLbPa7bX#c#.bSbt.E.BbNbKbNbO", +".5bGbKbYbNa2.da6bJbq#6.Za2bNboa4#c#lbEbbbNbXbu#3bTa0asb2.E.YbTb0.E.s.SbK.B#maAbbbI.0.x#3bNbI#B#ha7bGbFbTbq#3.S.ZbebT.SbWbqaB.gb0bObmbtbIbLbT#3b0byaw#tbJbQbO.x.Sbo#Lb3bNbmbobKbOawbRa2bJb0.YaAa2", +"btaGbEa7#cb1byaGbobqbL.Bbe.7bIbqaBbWbq#5bq#3#cbX.ybHbnbqbIbq#ca7a7bTbJbPbmaKbIaMa1a7bJ.6.xa9atboa9.5bWax#6bW.NbXbUbTa5bT.Kbq#3as.waYa7aMb0bH.Ea6bNa5aG#5aCbTak.EbTaA#5bHbL.xbobhbS#5bHbea4bIap#6", +"bN.5a2bX.xbQaH.B.Z#3.dbU#kbNbMbFa4btbWbM.E.S.x#6asbL.ZbLb1.Z.0akb..0aZb0bTbP.ia9aAbHaGbH#L#cbeaAbPa2#lbQbLbHbw#3bHbq.5.SbM.SbMbIbB#qa5.xbbbi.M#c#tbebob.bYbJbTbA.wbo.wa5aAa8#t.h#3#ibS.ObIan#3.0", +"bHb#bM.Zbq.sb2b0.a.SbbazaRbNbN.nay#3aG.J#ybSbNbNbWaB.YbL#6anbYbE.Z.xaO#cbea9a9be.mbH.nbq.EbBbebB.O#.#6.x#6bI.Kb2bybAbqaAbP.5boat#k#c.ca#.ZbQap.MbTa2be.Za7bQaw#Oan#ObP#5bY#5#5bJbu#6bBan.E.xbI#3", +"bWbX.Z#5bKaua5a7bTbNbY.B.5bRbVbt.6.xaHapbO.bbqbz.x#5bNbJ.Z#3bHa9#2.EbebN#k.Z#5#q.Z.ZafbV.ZbMbNbqbXbSbI#5b0aG#5bDb0bKaHa4aAbu.0bIa2.xaG.E.BbAbNbHa9.SbYbI#6.ZbIbQ#2#cbIbQ.0.KbO#6#c#PaHbM.EbfbHbo", +"bKbIbI.i.0bL.7.waG.Tap.Sa4.0buai.KbS.Oaw.Sap.6aGbO#c.Sa2bJa7bebH.x.0.BbI#c#Bbu#cbR.YbRa7a7bM.xbI.x#Tb0bVa9bI#cb1bq#c#hap#c.x#3#kbI.KbT#mbqbO#6bPbYbYa9bNatbWawala2bq.xaAbTbobtbf#hbO#5bo#3bIa6aw", +".Eb#.E#2b0bTbMbe.S#3bP#6bOaHbSbSbMbYbP.xawasblbQa2by.TbJasaHbe.KbT.KasbqbtaAbH#3bIbobybGbWaC.E#G#..EbqbqaA#6a9bYaM.6#caB.Ea9bKay.ibL#5.Pbta8b0bMbFa7bqbIbea2bJ.E.KbqbS#6bJbYa9.O.raubA.xbY#kaAb2", +"bJbO#lbXbM#laYbT.Zbl.F#5bBbX.xb0bHbebI#3bNbtbTa7.5bO#3bo#cbObNb2#6bOb1a0aYaAbWb2#6bC#9asbH.0bHaC#T#kaHbXbqaA#5#h#3bYb1apaAawbTbS.k.ibha9aYbMb#bMblbeb..nbtasbKbEbzblaA.ZbQbJbYbTa4bTa2b1.EaGbIbF", +"bT.xbKbHbWbq.B#ka7aubqb1anbUbL#JbT.5bM#6.xaAbIbubL#ca7.SbUapbM.5bu.ka9aAbMbJaYbT#SbPbBbfa9#ca9bH.S#cbXby#waA#taHala2.5bKbSa9.EbMa9.SbhbLbM#6b3bTala7ana2bLbqbTbe#3aAbQ.6a9bN#Qbtbqa2.xb1a4bzbqa6", +".x#lb0b..Ebhbqb1a8btbmbbbhbJa2#5b0bebTa5b0bJbBbIbNa9#5a9.x#3.SbXaZa5.HbX#B#UbLb1a2bYbYbMa9bobtbF.0bJ.SapaAaGbG#gaGbSbJana9b1bY#3.E.x.Z#cbqbQ#cbqby#cbMbIa6bLawbEbH.KbtbLbeaOa7bqbealbube.5bK#.bo", +"bK.BbLbX.ZbXbL#3bKbhbu.ya5.ibPbTbLbh#5.Qby.k.i.k#5.Bb0.BbPaHa4a9a0a8#qbL.Qbnbq.ga7#laAa9bT#B#v#jbK#k#ka4#kaKbTaHbL.Ebl.5bN.6a4bIaza2apbt.cbY#cbb.ZbI#cbfapbSbIan.iaMa9bN#l.i.5#4bI#c.na9bIa9bHbe", +"btapapaW#kawbe.0#8aVaW#5a4a9.i.IbNa2a7bw.OasaGbh.F.naG#l#5bBa9#qbBbFbO#5bMbOaAbB#k#X#kb0#kb0aZ#kbS.e.S.0ahaObSaybHa7#k#kaA#U.nbH.0.Z.0bHb0#P#k.S.BbHbebMbI.x.Zbt.J.7.Z#k.S#T#k.E#4aObN.daF.e#4#P", +"#kbQa7btaGa9azbY.WaGaGa4a9.Ob0b0a4bJaHbFaza5aAas#VbL#kbe.0bMbWbwb0bL.xa8bIb1bJbJ.O.F.I#ka2#ibHbBbIaFaC.SaHbY#l.0.0asbPaAa1.KapbPbMbS.0bSbq#l.xbqbTbY#kaH.0a9bt.K#O.Y#P.Ja7bSbQbEahbq.E.Zat.BaVbH", +"btaGaH.7aCbHbNbS.WbsapbSbLa5bO#6.b#k#lbo#5.gaGbcbTax.5be#k#xa6#n#3bIboasbFbebJbO.jbRbLaKaMbo#m.ia6.xa4#PaHbOaFbqa7bBaO.xasb0.E.Z.Eas.x#lbqbzbKbV#c.Z#xb0bY.SaH.EaC#m#.axb0bNbMapbL.4#.by.CbTas#l", +"aF.SaHbJbNbMbC.Zapa2bGbQ#6.KbC.IbG#cbq.K.5#m##b1awbX#k.5aGa9bT#5.xbm.Sa0.FbhbH#qau#6#JaA#B#hbc#5.B#k#4bO#.aGbSbIbeaDbM#k#5apbLbu.E#3bXbtbX.nbob0bKbT#Va2#6bJbIaG.KbDbEab#5bEbS#tb0a0as#lbMa5aA#B", +"bHbOakbE.E#..Ba7aLaT#c#3btaG#NbY.dbfbN.ZaIbKbPa8aC#NbNbSbXaGaAbebObR#5.xbBaZbJa7.k#9aZ#Lbu#vbeaZbKbHby.xbHbO#.#PbTatasbyaB.VbS.x#cbt.FaGbXbLbN.Zbi#cbT.Ea6bYaG#kbObY#ubEbobuapaGa5b2aZbPaZbLau.G", +"btaSaB.D#lbT#ObP#ta6#3#3bBbHbe#k#5.5.ZbFbEby#hbqbq#.bu#lbKby#5#BbEbXaYb.bL.9bXbX.i#BbB#Ab0bLbJ#lbM#k.F.5bJbTb0a7#9btbe#5bt#JbebMaMbqaMa2bzbobt#3bTa4bMbo.0bXbIat#J#3bYa2bJ#6bo#6.K#5#mbtbBbKboaA", +"b1#l.j#Q.D#H.B.xaHbyanbYar.1.xaya2a6bY.x.ZasbIaA.Ba4.5asbE#B#5bL.KbLasaCb#bKbXa2#qaAalbua5.S.5.Ebt.zbXbMbTb1.xbzbIaCaAbyatal#5bt#ca8au#6bebRa9#6as#cbN#cbWa9a7#kaH#Va6.E.E#c.xam#lbBaw#5.5bBbEbA", +"#U.4.0.Q.ZbMbObX.KaKawaKbP#5.bbq.M.Ta2bWawa8aAbI#kbRaGa4bJbubPa9#3bIbPb0bTblbWbn#3bLbt.w#V#U.Z.z.I.ZbRbKb1bLbXbWbBbebLbtbfaK#c#uaA#6#6#S#vbSaMbe.EbHbI.0bo.xa9.Zb1#k#V.xbNa1a1.ZaU#q.dbNaL#6aRbN", +"ah#4bS.Va7#e.Maibqan#kbXaw.BbLbYa2aha9bIaAbGahawaAbB.ibXbT#c.xbbbJapalbe.xbO.#asawbJ.QaObXakaZa9bXb0aAbA.0br#5.sbNaha9#cbVaCbYaVbDaw#c.ZbeaBaebMbKbP.qbMaAbYa1b0bEbSbE.Ba7.i.Q.BbObNboa7bM.Sa7bW", +"aOaw.xambN.M#2bGbJ.0.Z.xbT.E.ZbHapa2bt#k#3bIaibQbTaAbRbT#k#BbMbMbybybNbe.S.O#..Zb2.2.5b0#H#kbKbt#5bu.ZbM.k.K.xbe.xapbea7aG.0aG.5a4bEal#6awbT#Ob0akbT#c#.bH.SbLbIaUa2.xalbH.0.S#sbebf#J.ObNbJbN.O", +".7#l#4.SakasanaObMaGbqbN.0b1bQ#..daGbIbJbTbTa6aCbObIbH#S.Za5aY.xa5#jbobo.K#5bFbLbtb##U#Rbq.hblba.0bna0#5.QbO.EbM#haA#.bLbMbKa5aAbCbBbfbTbqas#3bWa7bNas.Za7.EbYa1bMaVbt.EbYa7#O.BaKbXbuaHbqasbH.E", +".S#6.Z#kapbT#4bIanbHbRb2.S#cbO.xaybb.BbX#t.Z.V.abJbTaA#5.i.F.KbKbFbFaa#3bf#vbobbbnapbM.S#2#lbKbra9bXbI.0bebMb0#h#6bXaAbM#3bnbPbubobH#.bzapbLbNbIaHbP#ca2bI#5a4bLbK#k#k.Z.B#3bPa7bYbbbobJaG.Ea9ak", +"bLbq#kbJ.S.x#c.E#PbW.Z#l.6a6.nasbQ#4btap.0bBbS#cb0bTbBbLaIa9bL#5#q#taAaaaK#nbtbt#n.ZbH#Rb1bqbUbJbKbz.K.ZbobLbtaZb.aZ.kbM#vbIbM.ibTbFan.KbRbEaA#5bqa9bebI#cbLa2bu.x.xbFbPbIan#HbeaA.KbT#m#kbo.Zbq", +"aIbMb1bHbP.pbLbP.xaGbJapbSbX#.#caCaUbTbTbAbX#c.JbXalbXbb#ia7bJala4aM.Ka2#LaC.Kbwb2bBbO.BbL#U.0#mbXbJaAb.bIaG.PawbMb0bMbn.0aKbHbXa4ae.iap#lbIbo#kbBb0bo#cbPaGaAbua7bI.ZbE.E.xaybbbBboatby.2.Sbq#V", +"bLbTbMa9bP.S.xbRbLbYbPakaAa7bM.E.N##.K.Fa8.SbtbNaG#kbPbrbTbIb1bK#Ra7a7#3bbbxbu#qaA.x.5.0.x#XaK#3.xbX.Ka7bLbIbyaAbq#cbq.Y#3aObb.S#k.sa7a9bPbt.aa2bTaAaGb#btbubt.KagaSbL.SbLawa9aVbI.KbtbM#3#cbJbX", +"bc.FbT.g.haqbMbPbP#ebIbN.6a7#kaAaV.cbtb0b2apaObEa5aAb2.KbIbubl.K.B.Z.7bM#5.0.KbE#vbHbXaf#ObY.IbobhbNbm.ibTbhbT#u.SaWaVbHaG#c.ZaU.A#YbIbYbfbSbGbibo#3aMa9#mbP.K.Kb0.Q.S.xa2.ZbNaCbb#6bo.5bTa7bq.B", +"aw.S#4.cawaS#P#.bqa2bX#.#c#caPa2bHbQ.FbY.d.3aw.o.J.5.5btaGa8auaY#GaebXbWasaK#v#a.H#ObPbJ#3aAaU#cbL.KbIbK#5.xb0bI.a#4.ZbbbL.SbI#..I.SbT.E#k#1bL.6bTaNbo#5#3.YalbLanbqbSbTa7bPaxbubfa7bz.0.Yaw.5a4", +".Ea1.6#2bSbqazbX#kal#c.xawaGbSaUa1.5.5a2.WaCaybYbEaVaH.SaAbq.kbaak#k.0bX.xaY#v#5as#sbB.S#ca9#ca9bK.I.Kb0b0bI#kbKaO#VbHaw#3.Sa7aebX#I.xao.wbq.5bM#5.Zbua5bEbe#vaGbybB.S.Ka2#cbz.SbYb0bBbB.Z#5bo#k", +"bNaG.6apbY#k.r.7aSawawbXaC#caCaP.xbYak.VbNbb.WaWaxbM#c#lbNbXaAbIae#O#.bq#tbO#9aKbRbT.S.ZbNbyaHbNb0bPaAbBbJ#LbebMa1bq#kaKa9bL.x#NaH#Q.x.Z.S#Hbq#Xbyb0#5bMbFbBb1beaAbL.xbtbP.KagbJbqbtbL.xbubTbqbM", +"awbIaCaC.x.0a2aG#k.O#kbq.xbGbS#6.SbHbMbSaCahaGbB.Saz.ZbLanbPbTaY#l#.bTaAbqbeaA#La7aGbFaBawb1boap#Jasa9bWbWbIbObX.NaGbSbP#5.ZbrbMaAbL#kbIbM#hbKbX#caA#3bebuaAbebfbq#6bNa7#5a7bEbobubEbTbE#4#3aGbL", +"###caG.SbEboaGbMbMbY#Vbea4bvahaW#PaC.Zbq.0#6bz#6.J#Waz#J#lbPbLbt.0b0.xaKbO#mbLa5bwb0#kaH.Sa2bWaAbIbJatb0#6.iap.xa1bY#5awa0a9bnaebaa7aY.EbXb0#l#ka8#Ca9bobTaKbYaK#rasbIbLbN.SasaG.4a2.SbobXbK.Ybq", +"an.5bua4by#5.O#c.haCbJanbY#caJbfbHasbNbY.2aq#JaAa7aGa2bybOaAapaYb2#9bLbPbWbXb2.SaHaHanby#3.hbTaObX#3bL.SbT.x.ibTa2bN#5bBaGbobJbqbt#lb#.EbJ.5a9bL#3beaKbOa9bu.E#vbK.MbtbqbN#5bM#3#k.KbtbMbI#c#cbo", +"bobfbLbYaAayaA.M.Eal.nbybLbubE#caia1.7btbBaM.L#BbSaC.5#kaCb0bOaYbMbAb1btbPbL#nbLaU#u.SbebNb..5#sbMbub0a9a8b3bTbI#V#3bubF#q#vbn.2.KbMbo.kbObLbJbJboboaC.KbY#man#mbqbBbLapbMbbaGbS.5aHa7a7bYbebLaG", +"bT#Eam#p#5aAaL#3bOanbqbVbEajaHapaO.SaH.SbObhbM.H.a.SalaGbTbYbh#6bJbM.p.2a9aA.0aoboay#9.E.x.E.g.2a8.5bn.sboaA.Z#6axbF#Ea5ab.4btbJb#bbbPbzbNaAbxbM#5#5.K.iaqbB.K.Fa9anbTbH#k.EbP.SbIbeb0bYbu.x#3bq", +"#PbN#Ta9aVaWbtaG#VbP.ZbhbXbM#h.G#d...ubYbq.7#k.0bNbwadbSbea6aV.5.X.1bE.J.ZaAbS#5.5.Z#T##bY.E.F#l.EbH#c.Ebu.ZaH.CbTbMbXbT#n.5bMbM.JbEbG.5bBbSah.KasbqbtaYala5bJbJ#cbo#3bNbubnaC.gan.cby.Obu.waAa0", +"#4aGbN.E.BataG#ubY.x.EbLbM.2.iaKa9ap#EaGbAas.S#..BbYbNbN#c.Ea2#3#c.JbN.5apa2bRb0.FbNaA.6bWbQ#.bPa9by.Sb2a2bTbE#6bTbIbq#5aA#5bua0beapbEaGbq#capa7aAbMa0bIbt.KaAb0ay#3.Ka2.BbI.sbqbSay.x.Z.xbo#SbI", +"ak.EbSaVbRbSbbbbapbi.KapbF#5bCbtbBbbbOaAbIbI.EbXbI.0.Ba2bqaG.5.dbSbNaCap#mapbubLaM#kapbFbhapbuapaCbJbobSbqbo#FbHbub#asbJbhbJbh.B.FbHbq.0a2aw.BbtaAbubXbI#kbXbPbAaPasbo#5aC.5a7.hbt#kaH#5#c.IbL#5", +"aB.0bMa4#6bP.KbtbDaW#5.W#yaw#qbybLbI#vbXbT#hbLb0ay#5#3#kbA#cbBa9blaGaMbo#Ebh#W#maG#q#Lb2bobe#vbz#AbNaB#5bo#5aw#v.0b0.KbK.EaAbJb1#3bKa9.KbObJ#c.xaAbLbobLbMbubIaYbDbSa6aAbI.Eb0.5bt.xbubH#ca7bbbL", +"aq.nbX.SaH#3bLa9#B#BbiaTap#wbi#Cbh#kbh#5a5#6bm.ibJbqbMbpbM.0bMbb#p#jbu#m#J#9#9aMblbu#6a9#5bfbIb0a9bfbUbIbyb0bobWb0bt.i.SbX#m.Bbbbq#c.KbNbza4b1bKbWbSbLbObobLbeb0arbbbu#k#6bLbMal.EbMbE.Bala9#k#c", +"#kasbMbybXaZ#v#qbn#3boaAbWaXbK.R#I#hbJ.5bU#ha2a2aAbTbEbO#5aAbM.0b0bb#m#6#tbTbhbnbzbobT#9bobeaAbb#ubIbe#p#q.Kbbbua9bPbI.KaY#kbh#6.8a7a7a5bXbBbJbI#kbu#la8.OaYasbMbN#3bL#5.D.i.S#Hbf#h.EbubNa9.Bbe", +"#QbLbIbPas#5a9bP#Lbra7bBbtbI#c.x.Z.EbKbJaha4.RaNbTbLaZ.ZbMbtbFbJbtaAakbO#q.ibWas#3#I#3bY#2bJaGbHaLbeaAbebybt#9bT#kbPbMbPbtbebH.EbX#nbIbObqb1b0#vbRaZbt.BaYaw.5aA.R#3#8#k#cbHbXbMbhbcb1b0bTawaV.0", +"bTbTa7bmbRbhbma9.g#b.y.waG.UanaCbKaH.Ea4bN.Jaya4aYbKbubTbL#hbr.Z.SbYaY.ObL#sbPaYbq.5ak.E.7a4aebY.kaLaMaM#mbS#qbtbra9bTbobLbhbX#haZbP#hbXa8#h.xb##.aAbPbPbXaYbJ#v.Bawbe.x.KaA#k.QbTbTbXapbE.xaCbQ", +".K.K.E.x.xbY.Ka9.bawaDbq.v.ZaO#da1a2.ca2.aa2aGawbMbTbObTb0bB.zbe#T.V.xb0#ca9a8#Ja4.S#5bH.Oa9.B.SbtbTbL.ZbH#lbBb0aG.ZaAbI.ZbubLb0#k#K.n.bbNazaq#q.SbE#iap#Db1#l.5#3.KbMbAaAbE#BaAaKapaAa5b1bTbua8", +"bwanbObI#r.7bu#ybSaG.5.Q#G#.bVaw#cbLa4.BbObQbqbGbMbLbtb1.KbPbMa9#..MbqbobRbMaBa8a9.5b1awbTbSbybKaAbX.S#3bXbP#NbM#qasa5bMaAbIaAbL.S.x#4.M.SbYa5bLbqbSa9#zaAboan#.bLbwbubebX#qbS#5.x.i.KbI#m.2asaA", +"#6be#3a1.E##bmbMbBbYbP#UbRbRa7#6bObWbXbI.E#qbJbTb0byaqbJbMbXbWbt#X.NbH.ZbNaAbu.i#cbKbKbfa2bBbXbN.ZbTbRbT#sb0#5bJ.Z#.bPbXaMb1#6.E.IbR.naObN#kbTb.bI.EbobMaAbAbHaAaGbJaA#c#qbCbo#5bLbMbL#cbObXbObX", +".KbJ.7#XbSbWbtaG.Sa0#sbTa8a7a8bTbIaKbLbIbJbhbR#3aAbLbMb0bMaAbIaA.7bMbN.ZbS#BbX.Kap#AaibW#kbNbTbIb0bXa7#k#3.IbH.iasboaYa2asbqa5bIbLa7bMaW#ratasa0a1bq#c#va9#3.xak#5#nbe#3#5bebXbIbMbtbJaY#kbXbTbo", +"bFbz.7bT.5#kbybo#hbWbobtb3#na5.7#J.IaYboaYb2bPbOasaCbe.Kb0bPbeaBbWaObMaHbJ#EbY#mbqa2#kaAa2#5aO#c.5b#ag.5b0bObK#2aZbL.EbT#5bLaYbJ.K#vbNaG#k#3bubIbT.F#Lbea9#A.ZbKbQ#3b1bL#3#6bObtaAbOanaBbJaAbTbb", +".Kbna2bq.Z.0#m#vaZbTbo#L#BbubPaAbr#cb1##bM#tbH#vbMbT.Za8beb0#.aA#ka9bPbObL#kbB#5bSb0aGbIbqbT#Ja7b#bIbObnbP.Bb1bEbLbobza0bLbobI.Ka5b0byapapbQ.Ea8bHbLa2bobS#3aG.xb0bfbE#3bub0bz#c#6bIbhbI#6bLbebM", +".KaKbYae.S.B#5bIbqbtbu#y#E#cbSbJ.F#3#ca2awbIa4aHbIa9bIbTbWaA#hbq.h.7bHby.fbt#6bYbqapa9bMbBbYbNb1#k.F#k.0bI.0bh.ZbIbh.Eb0bt.Bbha7#maK#Sbi.V#k.KbX.E#kb0a8bua5.5.0aI#AaKbuaK#5aHb0#hbtbRaGbLbKbLbA", +"b0be#P##.EbBaAapbPa7bNbv#7.a.0bObsaFapaGbGbSa2.6aAbTbMbObJ#5bI#5bIb0bWbtbIa7aWbVbtbM.xa9.ZbTbqap.x.s#3.g#3bL#NbK#3##a9aY.xbh.0#5#Jbh#EbebM#cbT.6bqa4b1aLbNa9bM#VaM#6apaA.xa9aM#5bJbM.BaZbXa9bubX", +"bybIbSaGb0.caMbYbJ.r.5#k#P#XbL#.as#XbJbK.2btaGbD.Z.PaYbH#h.B#cbb#KbebqbbbNbiay.Ya7.Z#UaObH.6#2.7bJbH.0#3asbKaA#5#2bOaSbLbPb0.S.g.d.KbGbEbNb0bXbn#X.B#H.0#2.Z.n.SbYbHbMbE.KbTa2.Za9#caKbo.KbtbMbo", +".5aAbWbS.Ebo.Z.K.BbJbEbX.5aH.5bqaA.EasaHbobeaGaC#s#XbIbLbIap#3.O#3.xbIbtaCa2aLbs.SbObIbU.s.xaAbPbIb0bLaAb1bb#6#mbM.0bt#UbN.g.ZbLbu#VaH#ka0bo.5aK.ZbP.KbJbWa8bJ.Ia7aK.SbEb#a4bLat#nbobebLbNaAbTaM", +"bbapb1a9bobP.xa4aGbqbq.Ba9bOaHbqbT.jbXbI#cbMbiaGbWbI#XapaSbObIbEbqbua2bo#5bV#6aybW#XaF#IbL.Oaea7#O.0#kaBbM#qaA#maA.gbbbTbJ.EbBbJ.dbMaGaAbNbTb0b#b0.hbH.BbRbIbEbWaAawa7beaFaAbMbebtbWbL#t#L#5#3#c", +".5a4.E#kbd#lbXbOa7#cbo.xbHbO.E#3#ka6bobLaGbKbq#3ae#.#Nb0a8a7aH#6#tbzbI#6#cbCapbobMbMbF#k.Bbr#.b#.Zb0#6bOasbMbybMb.a9.i.SbqbLbcbTbNa4#6a7#cbTbJbIbbbT.KbObKbF.g.K.0#3bS.4aG#3bY.xbubTaGapbYbMaAbL", +".5aA.K.K.ZbGbBbVbobHbybz#kbB#c.SbNbebHbea7a4bTbMbTbM.IbT#.aGbJbSbF.E#EbJbebtaYbu#s.SbWb3bybI.5bIbH.gb#bLaAaY#qbIb2bMbY.iaAbXbLbf#eawbOapb3bLbBbT#ha9bIbh.0b0bLbPbY#5bX.BboalbI.Kby#A.KaAbe.K#5aH", +"#kbtaGbqbebX.7bO#c#JaGbPbo#3b0bu#haHbebWbXbBbqbW.Pa7bJbO.EbubKapaM#3bXaYaAbRaZbPbBbP.Qa9.gbI#3bI.xbTbI#cbmbebobJaMbM#3bKbP.Y#ua8#cbG.K#kbebqbnbLas.KbXaAbP#3a9bMasap.5#6#l.x.6awbzbubtbfbbbeaAaK", +".B#5.5bebYbta7#3#6bXaG#x.KbY#qbNboa4.Ma9bNaA.gas#..l.QbMb0#c#5b0#5#j#3bIby.kbWaYbMbBbCbr#3bKb0aAbL#ObLbP#3bhbT#nbLbobPbybeaA#Z.K.MbH.ZaC#6bTbtasaZ.Kbt#5bobLaYbebWaCbya7bNbuby.7bob.bebtbL#nbYaA", +"#t.5bTbMbHapbMa7bea9bobo#maAa9.KaHbl#AbQ.4.5bq#saS#2.Fakbh.x.BbDbo#5a9bMa0b..g.I#qb0a8bJ.Zbrbt#3#HbXbN.ibTbobP#u.i#g#3.iaAaK#6bnaP.xaGbtbM.EaYbLbIaM#ma8bIabaAaKbt#ka9bIbebFbHbqbmanbT#3#5#5#5bl", +".nbH#c.n#lbq#kaHbX.SbTapa7bEbBb2#ca2.J.6a9.ib#bT#cbe#t#3bI#DaAbX#6alaAa9bB.E#mbH.ib0asbebbbKas#3.0.KbPa7#l#cbo.Z#5a2#5aAa9bybTa9#Q.x#N.x.ZbJ#kbqbL.BaebWa7.O.UaSbN#qby.Zbo.0.SbNbqay.E.N.Ea9.MbE", +"a7bYb2.EbYbP.xb0.SbobVb0.KbNb0.Eaya1aGaA.ZbqbtbJbzaAbeaAa4.K#BbTaqbBbIb0bRaYbIbobJ.KbubPbLaAbo.sa9#c#k.KbubIaqb1axaw.0be#.#3#kaGbTbLbIbqbP.jbM.B.S#R.xaO.i#2.x.ZbYbIbua9.BbI#lbKapbfbubMa4a2at.Z", +"bLbH.E.K.Zb0.xaxbYbMbq#6#lbO#3aAapb0bEbEbn#.bOb.#Lbbb1bt.Kbe#.aGbMbLbTa9#.bObJbIbB.z#5bLbobI#ibb.SbebXa9#kaGbz#c.ZbTbN#kbO.Sa7bQ.PbPbobLbI.F#5bXaA#NbMbT#Ia7.IbIboa9btbObNbP#V.ra7bNbNaObw.fbOap", +"apbyaw.5bL.SbEbK.x.E#5.Z#cbA#caGan.Ba4.Faqb.bbaYawaA#5bSbLaMa9#5b#bMbBaAbTa9b0bqbo.Eas#hbWbXbL#3a7bR.FaHbt.6.SbIbqbtbtbJbqbobebEasbybXbfbX#3bJ.F.h#lbI.BaA.sbQbMbP.E.ZbNbIa9bB#k#3asaHawbqbX.K#.", +"aAbSasaGa4bIbS#6bobla7#5bLbS.xbA.x.Nbo#kbEbTbqaMbtbtbt#qawbLaAbt.KbLa8bTb#bIbh.BbXbca9#kbIbNbX.8bF.VbJapbLa9bybNbJ.0.Y#k#6.xbu##bO.xbK.SbIa8#k#tbWaAbIbIbH#lb1.0bt#6b0a2.EbAaCbIbS.EbL.0boaHbRbN", +"bT#6btbt#L.Kbh.KbI.FbobIbJbqaAboaw.BbNbIaHbXb#.U#3bwbT#6a9.Ka9aG.Ha9#kbJbebLaAbU.KbMa9aAbMa9bJbL#3aGb0a9bubL#rbtbNbobO.EboaG.K#6bTaMbOaMbtaYbtaMa7bJaAb0bOaK.Fbo.0bYbqaqaAbt#5aZ#kbebObobX.gbuas", +"#qbSbPbKbubAanboapb0.Eby.5bYb0bYa4#cbRbPa6bObL#qa4a9aA#3#6bubu#5.ga2b1b0bJapbL#3.saA#lb0bTbtbHbIbQ.Da9.7.x.7apbJa2bPaHbLbY#k#6bMbEa8bB.ibJbIbOa9.ibMbqbnbe.Ba5bJbT.0.Z.S#5.B#t#c#q.xaAbta5.SbMaA", +"aHbxa2be#6bBby#t#k.xbua4a4bPa9aHap.0#cbAbWbIa2.l#JbKa9bo#AbTb0bzbeaAaAa0btbI.lbLbybXbAbTa5bLaZbubJbubLbya2anbJbT.2a9a2bXa4bTaHbHbubnaA#Lby#3a5bobubB#q#5#hb0btb0a7bM.xbA.xa9bYaKbKa8asbrbOaY#vbT", +".5a9apbX#cbH.SbybYbM#5bYbKapbIbX.M.Vazay.ObAbI.SbFbPbf.Ca4b0bobLbP.xapbN.7.KbwaAbqbL#ka2.SbLapa2buaGbPa9b0au#c#6.Maw.Va9aAbPbtbL.N#c.cbF.E#6aGalbPbM.YbNbW#cbLaGbHaC#4bLbX#cbIbHaF.Zak#l.B#k#Pa7", +"a9.xaw#kbN#cbo.6bMawbIbMboaFbuap.MaH#ka2.Kaw#3bL.hbPapa8#5bTbLb#bq.Z#kbJa9#JaubebY#6btbP#3bT#c.Ia9bOa9byaAbu#5bea9.0a4aAapbqbOa5bYaQa7.R.0.EbIbIbfahbO.S#3bqbTbo.7.xbf#3.xa9#ebeb1bMa7bo#.#Ha9.E", +".K.nbNa2bA.Z.6bYbY#kbK.M.xaBas#3.Zad#5#.a2#k.EbNaAasbMbTbXbP#3b0bqbNaA.xapbJaHaKbTbfawaHbb.Ea2bK#3bebtbeaKapby#5anap#kbYbT#tbqbT.S.x#5#haC#qaYbJana7#3bY#3#3bHbJbI#6bSaA.FbQbOaw.0bG#kbLb0bQ.rbM", +"bQa4bHbqaCbbajbQapbMby.KbtaG.SbyaGapan#ka9bX.K#6bMbK#cbRbI.7#hbP#4bLaObSasbebB#xaw.E.SbP#lbobQanaKbtbWbtb0bL#Mb0bLa7apa8bObTbHaMbPbT#6a0.zbIaAbh#lbbbLbSbq#5bWaCbo#6bqbybebPbubFbq#kbPbYaCbJbta2", +"awbLa4.S.Map#lblbUaw.xaAbNbr.ZbPaAbIbtaGapbQbRb1awaYbM#vbfbJbtbXaS.xbTbebMbYbfbI.5bSaA#c#6bHb0#cbbbOaLaAbubN#5bo#5bWalbIaAbybJbTa0bobIbTa5bMaMbPbTbSbPb0#5bN.EbybI#c#v#6aA#5btbI#3#cbI.S#6bu.ZbT", +"aGbqboaGbJ.5.K.SbE#c.5bobO.S#5.bb0bh.hb.asbMaG.7bLbzaZ#3#kasbPbI#ka2.ZaH.Ya5awbtbQ.KbMbubY.5bybPasbe#vbQbFbb#JbubXbn.ib0bLa0bTa9bObJ.gbebMbSbJbNaGbqa7bo.xaGbIaHbB#mbobwbe#3.KbBa9#5by.KbEbTbTap", +".xbyawbqa2bzbHbNa9bL.E#3bNaG#3aAa9a8aZbLbKb0anbYaY.SbLbOaAbL#5b0.E#kaGbIbOblbB#vbX.7#5.ZbuaGbMawbBbya9b0#3bfb0#5a5.G#5.ibMbeaAbMa7#xbf.Z.ZbEaC#c.EbTbSbMaG.0bfapbIapbRbtbl#m#3bOa9b#a9bL#mbB#c#n", +"bz.xaGaia6#kay.ZbIapbP.xbYbP#kby#bavbh.Ka9a7be.xbS.i.EbtbJa5.xaA.E#5#kbTat#5boa9bNat.EbTaEbXaGbWa9.KbebE.KbT#5#3bg.k#h.sbnaA.5a9bTbB#Pbo.Ma2adaVb0#cbuap#ka8a4bT#faAabaM#qbobeaA#5bo#v.K#6bE#tas", +".5#4bfb.be#t#k#c.F.0.0bYbO#P#c.FaFakapbYbWbNaM.K.MaGbBbqaH.SbmaZ#d.BaiaGaGaHaCby#P.B#e#PbR.x.xasb0.IbWbTbIbo.ZbMbYa7bIbN#k.E.x.I.6bLbMbYb0bX.M#6#lbJ.Z#NbT.t.s.xa4#3a6bR.S.Ka2bo.WbY.J#cbua7bX#3", +"aG.EbfbebEbE.n.Eb0aw.FbEasbMa1bL#k.naAaGbMaw#.bA#caCbYaAbzaAbMav#T#k#V#lazbT.RbObq.0.7bLaFbIbQa7#kaK.EaKbXbMb0b.aHa9bSbe#kbP.Eae#kbobo.YbuaAa6bT.IbM#..EbIbMbBbTbIbqbL#c#6bMa9bq#fbSa9aH.K#3#can", +"bX#caKas#6#ta7bIa7bBbLbPbYbo#5a2bK#4.JbI.MbBbobbaybqbY.xbJbMa9bI.xaGaqawaHbTbQ#cbW#c.5bfbxbobt#SbtbIbRbJaYasbXbtazbXbobMbPbJbTa8#ca7.ZbN#kaH#3an.B.4aZ.ZbhbK#Q.x.xbt.EbP.EbYbLbt.R#caUb0aGbqbyag", +".5aObobnapa8#c#Pbb#t#3aK#tbo#JbB.JbLbEbQ#kbuaH.Jb0bX.6#5.xa4#5#kbTbNaCbMawbK.KbLbybPbu#6bbbZ#vac.Zbn#kbTbebLbfbIaybobfbo#DbM#nasaHbX#5bMbSaAbMbM.E#5bJbM#3a7a9.ibybSbNaM.xaw#3bHaW#6aLbea9b.#B#.", +"bIbKbeaG#vbe#c.x#3blan#t#k#xbubobRaVa9bNbMa2.EbEbObtbB.0ap#5.0.xawaAbMbHa9bS.S.K.KaKbwbt#q#ubZ#jbLbTbObTbNaYbebTbYbSbY#6aAbt#m#qbqbo#c.S#5bo.O.KbtbTa8.6.Eb.aAbL.5bTa7bHbe.x.ZbtbtbPbYb0be#.bnbH", +"aC#.a9bFbobtbPbLbLbobe#3bbbbbt#qbban.EawbE#.bqbEbHbfb0#5bI.x#c#cbLbXbybtbm.SbI.ybN.Kbe.K#qbD#q#za8.5bfbBbJ.BbTbLaVbMbV#3a6brbT#u.ZbA#kbF#.bMbEbW#B#.bB#naA.K#3bT#cbLapboa2#5#.bobu.KbubyaAbhbIb0", +"#Oa2bX.KbeaA.5a1b0.xaAaAa1#kb1.6a9aA#DbH.ZaVbKbqaA.SbJaA.XbS.S.b#gaA#t.EbL.xbMbWbea2bRbtbubWaM#5.ZaZbP.EbMbJ#mbJ.V#GbHaH#3bc.KaYbL#ca9.0#5a2bqbfbMaZbtaZaAbM#tasbeaCb0bTa4.x.K.E#vbE#LbraKbKbIaA", +".xakaKbybW#6bM#l#ka7#k.nbM.0bH#Pa2#3by#..K#kak#0bnbMaA.5.K.BbNa6aK.ka9bLbc.wbL.7.xaAbqbAbo#JawaB.KbLbq#BbebMbMbL.##Va7#2.S.B.0bIbEb2.7#6.Z.KbJbq#m#5a8bWby#ua8#6#3#lawbTbea7bL#3#3#J#5#.#3.ib#bM" +}; diff --git a/plugins/styles/styles.cpp b/plugins/styles/styles.cpp new file mode 100644 index 0000000..6e75fcd --- /dev/null +++ b/plugins/styles/styles.cpp @@ -0,0 +1,164 @@ +/*************************************************************************** + styles.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include +#include +#include + +#include "simgui/fontedit.h" + +#include "misc.h" + +#include "profile.h" +#include "profilemanager.h" + +#include "styles.h" +#include "stylescfg.h" + +using namespace SIM; + +Plugin *createStylesPlugin(unsigned base, bool, Buffer *config) +{ + Plugin *plugin = new StylesPlugin(base, config); + return plugin; +} + +static PluginInfo info = + { + I18N_NOOP("Styles"), + I18N_NOOP("Plugin provides styles"), + VERSION, + createStylesPlugin, + PLUGIN_NOLOAD_DEFAULT + }; + +EXPORT_PROC PluginInfo* GetPluginInfo() +{ + return &info; +} + +StylesPlugin::StylesPlugin(unsigned base, Buffer *config) + : QObject(), Plugin(base) + , m_saveBaseFont(NULL) + , m_saveMenuFont(NULL) +{ + m_propertyHub = SIM::PropertyHub::create("styles"); + m_savePalette = new QPalette(QApplication::palette()); +} + +StylesPlugin::~StylesPlugin() +{ + delete m_saveBaseFont; + delete m_saveMenuFont; + delete m_savePalette; +} + +QByteArray StylesPlugin::getConfig() +{ + return QByteArray();//Fixme +} + +QWidget *StylesPlugin::createConfigWindow(QWidget *parent) +{ + return new StylesConfig(parent, this); +} + +void StylesPlugin::setFonts() +{ + if (value("SystemFonts").toBool()){ + if (m_saveBaseFont) + QApplication::setFont(*m_saveBaseFont); + if (m_saveMenuFont) + QApplication::setFont(*m_saveMenuFont, "QMenu"); + }else{ + setupDefaultFonts(); + QApplication::setFont(FontEdit::str2font(value("BaseFont").toString(), *m_saveBaseFont)); + QApplication::setFont(FontEdit::str2font(value("MenuFont").toString(), *m_saveMenuFont), "QMenu"); + } +} + +void StylesPlugin::setupDefaultFonts() +{ + if (m_saveBaseFont == NULL) + m_saveBaseFont = new QFont(QApplication::font()); + if (m_saveMenuFont == NULL){ + QMenu menu; + m_saveMenuFont = new QFont(QApplication::font(&menu)); + } +} + +void StylesPlugin::setColors() +{ + if (value("SystemColors").toBool()){ + QApplication::setPalette(*m_savePalette); + }else{ + QApplication::setPalette(QPalette(QColor(value("BtnColor").toUInt()), QColor(value("BgColor").toUInt()))); + } +} + +void StylesPlugin::setStyles() +{ + QString sStyle = value("Style").toString(); + QStyle *style = QStyleFactory::create(sStyle); + if (style){ + QApplication::setStyle(style); + if (!value("SystemColors").toBool()) + setColors(); + }else{ + setValue("Style", QString()); + } +} + +bool StylesPlugin::processEvent(SIM::Event *e) +{ + if(e->type() == eEventPluginLoadConfig) + { + PropertyHubPtr hub = ProfileManager::instance()->getPropertyHub("style"); + if(!hub.isNull()) + setPropertyHub(hub); + setFonts(); + if (value("SystemColors").toBool()){ + setValue("BtnColor", m_savePalette->color(QPalette::Active, QPalette::Button).rgb()); + setValue("BgColor", m_savePalette->color(QPalette::Active, QPalette::Background).rgb()); + } + setColors(); + setStyles(); + } + return false; +} + +void StylesPlugin::setPropertyHub(SIM::PropertyHubPtr hub) +{ + m_propertyHub = hub; +} + +SIM::PropertyHubPtr StylesPlugin::propertyHub() +{ + return m_propertyHub; +} + +QVariant StylesPlugin::value(const QString& key) +{ + return m_propertyHub->value(key); +} + +void StylesPlugin::setValue(const QString& key, const QVariant& v) +{ + m_propertyHub->setValue(key, v); +} diff --git a/plugins/styles/styles.h b/plugins/styles/styles.h new file mode 100644 index 0000000..bf79f36 --- /dev/null +++ b/plugins/styles/styles.h @@ -0,0 +1,58 @@ +/*************************************************************************** + styles.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _STYLES_H +#define _STYLES_H + +#include "cfg.h" +#include "plugins.h" +#include "propertyhub.h" +#include "event.h" + +class QFont; +class QStyle; +class QPalette; + +class StylesPlugin : public QObject, public SIM::Plugin, public SIM::EventReceiver +{ +public: + StylesPlugin(unsigned, Buffer*); + ~StylesPlugin(); + virtual QByteArray getConfig(); + QWidget *createConfigWindow(QWidget *parent); + void setFonts(); + void setupDefaultFonts(); + void setColors(); + void setStyles(); + void setPropertyHub(SIM::PropertyHubPtr hub); + SIM::PropertyHubPtr propertyHub(); + QVariant value(const QString& key); + void setValue(const QString& key, const QVariant& v); +protected: + virtual bool processEvent(SIM::Event *e); + + QFont *m_saveBaseFont; + QFont *m_saveMenuFont; + QPalette *m_savePalette; + QStyle *m_saveStyle; + friend class FontConfig; +private: + SIM::PropertyHubPtr m_propertyHub; +}; + +#endif + diff --git a/plugins/styles/styles.rc b/plugins/styles/styles.rc new file mode 100644 index 0000000..e06247b --- /dev/null +++ b/plugins/styles/styles.rc @@ -0,0 +1,97 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,0,0,0 + PRODUCTVERSION 0,0,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Vladimir Shutoff\0" + VALUE "FileDescription", "Styles plugin\0" + VALUE "FileVersion", "0, 9, 5, 0\0" + VALUE "InternalName", "styles\0" + VALUE "LegalCopyright", "Copyright © 2002-2003\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "styles.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "SIM\0" + VALUE "ProductVersion", "0, 9, 5, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/styles/styles.vcproj b/plugins/styles/styles.vcproj new file mode 100644 index 0000000..c1c4551 --- /dev/null +++ b/plugins/styles/styles.vcproj @@ -0,0 +1,466 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/styles/stylescfg.cpp b/plugins/styles/stylescfg.cpp new file mode 100644 index 0000000..ab79fd4 --- /dev/null +++ b/plugins/styles/stylescfg.cpp @@ -0,0 +1,64 @@ +/*************************************************************************** + stylescfg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include +#include + +#include "fontconfig.h" +#include "misc.h" + +#include "stylescfg.h" +#include "styles.h" + +StylesConfig::StylesConfig(QWidget *parent, StylesPlugin *plugin) + : QWidget(parent) + , m_plugin(plugin) +{ + setupUi(this); + for (QObject *p = parent; p != NULL; p = p->parent()){ + QTabWidget *tab = qobject_cast(p); + if (!tab) + continue; + font_cfg = new FontConfig(tab, m_plugin); + tab->addTab(font_cfg, i18n("Fonts and colors")); + break; + } + lstStyle->addItems(QStyleFactory::keys()); + if (!m_plugin->value("Style").toString().isEmpty()){ + QList items; + items = lstStyle->findItems(m_plugin->value("Style").toString(), Qt::MatchExactly); + if (items.count()) + lstStyle->setCurrentItem(items[0]); + } +} + +StylesConfig::~StylesConfig() +{ +} + +void StylesConfig::apply() +{ + font_cfg->apply(); + QListWidgetItem *item = lstStyle->currentItem(); + if (item) { + m_plugin->setValue("Style", item->text()); + m_plugin->setStyles(); + } +} + diff --git a/plugins/styles/stylescfg.h b/plugins/styles/stylescfg.h new file mode 100644 index 0000000..55b2b56 --- /dev/null +++ b/plugins/styles/stylescfg.h @@ -0,0 +1,41 @@ +/*************************************************************************** + stylescfg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _STYLESCFG_H +#define _STYLESCFG_H + +#include "ui_stylescfgbase.h" + +class StylesPlugin; + +class FontConfig; + +class StylesConfig : public QWidget, public Ui::StylesConfigBase +{ + Q_OBJECT +public: + StylesConfig(QWidget *parent, StylesPlugin*); + ~StylesConfig(); +public slots: + void apply(); +protected: + FontConfig *font_cfg; + StylesPlugin *m_plugin; +}; + +#endif + diff --git a/plugins/styles/stylescfgbase.ui b/plugins/styles/stylescfgbase.ui new file mode 100644 index 0000000..6927606 --- /dev/null +++ b/plugins/styles/stylescfgbase.ui @@ -0,0 +1,34 @@ + + + StylesConfigBase + + + + 0 + 0 + 366 + 245 + + + + Form1 + + + + 6 + + + 11 + + + + + true + + + + + + + + diff --git a/plugins/styles/wood/CMakeLists.txt b/plugins/styles/wood/CMakeLists.txt new file mode 100644 index 0000000..7526375 --- /dev/null +++ b/plugins/styles/wood/CMakeLists.txt @@ -0,0 +1,31 @@ +################ +# wood library # +################ +PROJECT(wood) + +SET(wood_LIB_SRCS + wood.cpp +) + +SET(wood_LIB_HDRS + wood.h +) + +# moc, if needed +KDE3_AUTOMOC(${wood_LIB_SRCS}) + +ADD_LIBRARY(wood SHARED ${wood_LIB_SRCS} ${wood_LIB_HDRS}) + +# some needed include dirs +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) + +TARGET_LINK_LIBRARIES(wood simlib) + +SET_TARGET_PROPERTIES(wood PROPERTIES PREFIX "") + +# install target +INSTALL(TARGETS wood LIBRARY DESTINATION ${SIM_PLUGIN_DIR}/styles RUNTIME DESTINATION ${SIM_PLUGIN_DIR}/styles) + +IF(WIN32) + SET(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/plugins/styles) +ENDIF(WIN32) diff --git a/plugins/styles/wood/wood.cpp b/plugins/styles/wood/wood.cpp new file mode 100644 index 0000000..a685766 --- /dev/null +++ b/plugins/styles/wood/wood.cpp @@ -0,0 +1,1452 @@ +/**************************************************************************** +** $Id: wood.cpp,v 1.1.1.7 2006/05/07 17:31:30 chehrlic Exp $ +** +** Copyright (C) 1992-2005 Trolltech AS. All rights reserved. +** +** This file is part of an example program for Qt. This example +** program may be used, distributed and modified without limitation. +** +*****************************************************************************/ + +#include "wood.h" + +#ifndef QT_NO_STYLE_WINDOWS + +#include +#include +#include +#include // for now +#include // for now +#include // for now +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* XPM */ +static const char *polish_xpm[] = { +/* width height num_colors chars_per_pixel */ +" 96 96 254 2", +/* colors */ +".. c #9c4a34", +".# c #a4825c", +".a c #bc5e2c", +".b c #d48432", +".c c #dc9f51", +".d c #bc6e1c", +".e c #d4855d", +".f c #94664c", +".g c #bc714e", +".h c #8c6664", +".i c #d4923c", +".j c #bc8444", +".k c #d49360", +".l c #d4794e", +".m c #ecaf68", +".n c #bc8365", +".o c #d47439", +".p c #a46954", +".q c #dc9f70", +".r c #e48544", +".s c #bc7b51", +".t c #a47761", +".u c #bc7b42", +".v c #a4523c", +".w c #e4945e", +".x c #9c784c", +".y c #d4844a", +".z c #eca053", +".A c #bc614c", +".B c #e4855c", +".C c #bc8350", +".D c #c48e68", +".E c #b16634", +".F c #e49339", +".G c #bc703a", +".H c #bc7c67", +".I c #a45f34", +".J c #cc714d", +".K c #d48c5f", +".L c #a47057", +".M c #cc703a", +".N c #dca674", +".O c #b47859", +".P c #bc6729", +".Q c #d49475", +".R c #d48b4a", +".S c #cc8351", +".T c #cc8466", +".U c #ac6841", +".V c #e4a651", +".W c #e49576", +".X c #d47d31", +".Y c #ac6e4b", +".Z c #c07650", +".0 c #e48c43", +".1 c #e49452", +".2 c #9c745f", +".3 c #e47e54", +".4 c #cc7c4f", +".5 c #cc7c32", +".6 c #b46133", +".7 c #d49a68", +".8 c #d67e4f", +".9 c #bc7643", +"#. c #b47056", +"## c #d48b3a", +"#a c #dc9f5e", +"#b c #e49a60", +"#c c #cc6a31", +"#d c #8c6244", +"#e c #dc9a41", +"#f c #eca753", +"#g c #bc8a58", +"#h c #d48c76", +"#i c #bc693f", +"#j c #bc715d", +"#k c #9c6857", +"#l c #f4b171", +"#m c #bc8a6a", +"#n c #eca16d", +"#o c #a87e58", +"#p c #a4613f", +"#q c #a48569", +"#r c #d4846d", +"#s c #dc935f", +"#t c #c47c50", +"#u c #dc8449", +"#v c #bc6950", +"#w c #cc9678", +"#x c #c4703a", +"#y c #cc7b67", +"#z c #dc8c5e", +"#A c #ac7067", +"#B c #eca86e", +"#C c #b4786d", +"#D c #dc8c4a", +"#E c #b46842", +"#F c #d47c41", +"#G c #e48d51", +"#H c #e59a52", +"#I c #9c6e3f", +"#J c #d49351", +"#K c #cc843b", +"#L c #ecb678", +"#M c #9c5a38", +"#N c #d4795c", +"#O c #c47b39", +"#P c #ec9560", +"#Q c #ac764c", +"#R c #c48351", +"#S c #c48e74", +"#T c #cc7650", +"#U c #cc8a84", +"#V c #bc6a5c", +"#W c #e4af74", +"#X c #b46855", +"#Y c #e4a06e", +"#Z c #ac775b", +"#0 c #e48d5d", +"#1 c #c47d65", +"#2 c #cc763f", +"#3 c #b47e5d", +"#4 c #cc8a55", +"#5 c #cc8a67", +"#6 c #bf622f", +"#7 c #dc853b", +"#8 c #e49f4a", +"#9 c #9c505c", +"a. c #8c5644", +"a# c #cc7329", +"aa c #a45a51", +"ab c #b48264", +"ac c #9c7a7c", +"ad c #9c5f4f", +"ae c #b4844c", +"af c #a46749", +"ag c #dca664", +"ah c #b46e1c", +"ai c #c4762c", +"aj c #a45a3c", +"ak c #dc9a74", +"al c #ac7e46", +"am c #ac6a6c", +"an c #eca862", +"ao c #e49a41", +"ap c #e49a78", +"aq c #bc7660", +"ar c #d57e5e", +"as c #9c6e5c", +"at c #ab7e65", +"au c #cc8a44", +"av c #9c6240", +"aw c #bc6244", +"ax c #bc5d3f", +"ay c #e48550", +"az c #eca060", +"aA c #cc7160", +"aB c #cc7c42", +"aC c #b46241", +"aD c #b4726c", +"aE c #eca67f", +"aF c #9c6a3c", +"aG c #94685a", +"aH c #c48240", +"aI c #c48465", +"aJ c #dc7640", +"aK c #cc8f54", +"aL c #e4a76f", +"aM c #c4692e", +"aN c #dc9474", +"aO c #ac6050", +"aP c #b47048", +"aQ c #94614b", +"aR c #ac836c", +"aS c #a47048", +"aT c #b4764a", +"aU c #ec8e5c", +"aV c #dc9a53", +"aW c #cc765e", +"aX c #b48a64", +"aY c #dc9a63", +"aZ c #c47640", +"a0 c #ec9a60", +"a1 c #c48a54", +"a2 c #c48a67", +"a3 c #ac5a3c", +"a4 c #ac8458", +"a5 c #dc855d", +"a6 c #c4714d", +"a7 c #dc9243", +"a8 c #dc794e", +"a9 c #ac6955", +"b. c #cc8f67", +"b# c #ac6032", +"ba c #ac7056", +"bb c #dc7a34", +"bc c #ec9553", +"bd c #dc8d3b", +"be c #e4a060", +"bf c #f4a654", +"bg c #c46842", +"bh c #c46f62", +"bi c #ac613d", +"bj c #dc866c", +"bk c #c4694e", +"bl c #dc7d42", +"bm c #ec8d4f", +"bn c #dc9351", +"bo c #cc9177", +"bp c #c4695f", +"bq c #ecb075", +"br c #e4a75f", +"bs c #d4843c", +"bt c #bc722c", +"bu c #d4936c", +"bv c #d47644", +"bw c #bc7d5c", +"bx c #ac563c", +"by c #e4956c", +"bz c #a47a4c", +"bA c #d48454", +"bB c #bc825c", +"bC c #e49544", +"bD c #bc7044", +"bE c #bc7e74", +"bF c #d48d6c", +"bG c #cc7144", +"bH c #b47864", +"bI c #bc6a34", +"bJ c #d49684", +"bK c #d48b54", +"bL c #cc845c", +"bM c #cc8474", +"bN c #ac684c", +"bO c #cc7d5c", +"bP c #eca27c", +"bQ c #dc946c", +"bR c #c47c5c", +"bS c #dc8554", +"bT c #c47244", +"bU c #dc8c6c", +"bV c #dc8c54", +"bW c #b4684c", +"bX c #cc8344", +"bY c #c47b44", +"bZ c #c4825c", +"b0 c #e4a17c", +"b1 c #ac7a64", +"b2 c #e48c6c", +"b3 c #c47a74", +"b4 c #e49f54", +"b5 c #9c674c", +"b6 c #946764", +"b7 c #c48674", +/* pixels */ +"#u#G#G#P#G#G#G.1#G#G.1.1.1.w#G.r#D.1.1.1#D#DbVbV.K.K.K.KbO.Z.Z#TaP.GaT.Z.O.O.O.H.9aP.ZaPaPaPbZbo.i.k#J.k#JbKbnbn#b#sbVbV#G#G.r.ray.r.0#G.0#G.1bc.r.0.0bc.0.0.0.r.1.1.1.1#G#D.0#D.0.0.0bcbcbc.1.0", +"#aagaLbrag#a#a#a#DbVbn#G#0.1#0#Da5#za5.4.J.Jbk#vbt.G#x.9bY.4#tbYbw.saPaP.Ub#af.Y.s.s.Z.saP#E.gbw.U.U.UaObWbWbWaPb#b#.E#t.K.K#z#s#s#sbQ#s#sbn#s#sbn#s.w#s.w#s#sbn.ybV#s#sbV#s#sbQ#aak.7.k.7.k.k.k", +"#..g#.#.#j#.#XbW#Z#o.O.O#3.n.n.Halalalala4aXaXa4#t.u.9#R#5bu.k#5bob7aIaI.nbwbw#m#5aIa2#5#5aIb7#5.DbBbB#3bwbw.C.O#oabab.naI.C#t#R.9#tbY#tbY.ZbY.s#t#t#t#R.sbY.s#tbD.Z.Z#t.9.Z#t.4bBbw.s.saT.9aTaT", +".ybS.ybSbVbVbVbVbl#u#u#ubSaybSay#s#za5#z#z#z.KbA.Qb.aIbZbZbB.g.U.gaP#.aP#.aPaP.O.9aP.g.s.O.ZaP.Z#CaD#Aamamamam#X#3#Z.OaPaPaPaP.saZbY#t#t#tbY#tbY#t#tbLbZ.SbR#t#tbZbRbZbRbR.sbRbR.4aBaB.4bY.4.4.4", +"bKbV#zbKbA.ybK#zbV#z#0bS#0#0#0aya5bA.4.4.4#T#xbgbwaq.O.g.O#j#.aPaCaC#v.g.gaPaP.Z#R#R#t#t#t.Z.s.Z#O#O.5aH#KbY.S#4bD.G#xaZaZ#2.SbVbV#s.wbV#zbSbAa5.e.KbQbQbU#s#z.K#5.K#5.T#4#5.Kb..4bZbL.T.ebL.K.K", +"#A#A#C#C#AaD#CbEatataRb1b1abb1.t#I.f#IaSbz.x.#.##v.g.g#1bR.T#5#hbObO.T.K.K#5.KbubL.4.4#t.4.Z#tbL.e#r.K.K.e.e.T#r.K#z.K#z#sbVbS#zbV#u#ubVbl#F.8.l#2.4.8bAbA.l.4bva6.g#x.g#x#i#i#i.L.Lba#Z#Z#Z#Zba", +"aPaT.u.u.s.C.C.C.SbA.S.4.SbA.8.8#r#rbF#h.TbO.T#h.KbF.e.e.S.S.S.S#u.y.8bA.e.4bA.e.K#zbQ#s.K.KbUbQ.y.R.y.yaB#O#xbT#t.4bLbLbL.4bL.S.4.S.4#T.Za6.Z.JbD.g.Z.g.Z.g.Z.ZaP.g#iaP#i#E#EaC.Obababa.ObH#Z.O", +"#zbSbA.e#za5.e.8bV.KbV.ybAbK#zbK.8.ybV#z.y#F.y#sbKbA.Rbn#sbn#b#b#Y.w#sbV.y.4.lbA.y.y.ybA#T.MbG.4bObO.4.SbLbOaq#..O.Yaf#p#p.I.U.UaT.Z.O.Oaq.O.H.Hb1b1#Z#Z.L#Zat#3bw.s.HbBb7aIaIaIbA.l.4aBbAbA.e.e", +"#DbVbn.w#s.w#sbVbAbSbSbV#D#GbS#0.1#H#H#H#b.1bn.1#4.S#t#t.S.TbL.S.K.K.K.S.SbK.e.S#t.4#t#tbDaPb#b#.U#E.9.S.ebVbS#G.K.K#r.l#y#T.Z.Z#2aB.S.ybS#u.8#F#Kau.y.S.y.y.R.y#z#z#sbn.1bna7bd#F#DbVbVbV#s.w#s", +".1#s.1#s.1bVbS.y.K#z#sbVbVbA.8#FbA.8ar.8.e#r.e#NbKbA.S.S.S.SbLbLaBaBaB#2aB.SbKbAbVbVbV#s.w#YbebQ.KbA.e.KbV.ybl.ybsbsbs#D#u#D#u.R.y#D#DbVbV#s#0.wbebe#b#bbQ.wbn#GbV#G#D#G#D#GbV#D.ybV#sbV#s#s.w#s", +".wbn.w.w#bbQbVbV.4.4.ybKbnbV#z#z#G#D#D#D#u#D.y.R#2aB#2.M#x.M#2#2#z#s.w#sbV#s.w#s.1.w.w#b.w.1#G#G#s#zbVbVbVbSbVbVbd#ubd.r#D#D#D#D.1bC.1.1.1.1#D.1bV#G#0#0#G.w.1a0bC#G.0aybS.Ba5a5bVbVbV.w#z.w#sbV", +"#ubVbVbVbV#GbV#D#s#sbn#b.w.w.1bVb2b2a5#z#z.K#zbA.w#s.w#sbV#s#z#s.w#b.w.w#GbV.w.w.X#Da0a0#G.1bcaz#G#GbS#GbV#ubV#0#z#0#0a5#0#0b2#0.0.r.0.0#u#u#F.o.M.M.M#F#ubV#G.1#b#P.w.w.w#0aya5.y#u.y.ybVbnbVbV", +".wbV#GbV#G#s#G#0.1#G.1.1.1#G#G.0#0#0.w.wby.wbQbn.w.w#G.w.wa0#b#P#u#G#G#0#G#G#G.w#baz#Yaz.1.0#D.0#G#G#G#GbVbl.8blbva8.8.B#z.Ba5#0ay#G#G#z#G#z#z#z#zbU#z#z#zbQbybQ#zbK#z#s#sbn.R.y#2#2aB.8bVbV#0bV", +".w.w.w#z.w.w.w.w#GbV.r.0.0#G#G#Gbda7a7#H#8#8#8#H#u#u#F#u#D#GbV#u#G#G.w.1.w#G.wa0bV#D#DbV.w#baz.w#G#G#G#G#0.BbSa5#u#u#D.1.1bn.0#7#z#0bSbSbSa5#z#z#r.e.e.4.4#2#2bT.4.4.4.S.R.Rbn.i#s.K#zbV#s#0bV.w", +"#u.8#u#u#ubV#GbVby.wbQ.w#b.wbVbl#T#T.l.ear.Ba5.8.w#G#G#G.w.1.1.1.1#G#G.w.1#G#G.w#P.w#G.1.w#P.w#0#D#DbV.w.w#0#0#0.w#b#baVaVbn.1#G.y.y#F#F#2.obv#Fay#z#GbVbV#z.e.e#z#z#zbV#s#s#s#sbQbQ#sbQ.wbV#G#0", +"#0#0#0#G#0#u#ublbDbT.4#4#zbQ.e.e#s#s#s#z.w#0#0aU#DbSbVbV#D#D#D#G.w#G#G.w#P.w.w.w#Gbmbmbmay#u#G.waz#b.w.w#Ga5bl#uaraW#i#i#ia6.4.ebVbnbQ#b.w.w#GbV#u.r.r#G#G#G#0a5.1.wbV#zbSar.J.JbT#x#2.y#F.8#u#G", +"#5.TbL#tbD#i.g.Z.SbA#zbAbKbSbSbA#u#D#G#u#u#u#DbV#GbVay#G#0#G#G.r#D#Gbn.w#b#b#HaY.1bVbV.y#u.y#F#Fbv.o.M#2#2#2aBbG.9#OaB.y#D.1.1.1.w#s.1.w#G#G#G.rbdbda7bdbnbn#sbQ.nbw.s.Z.4.8.8.8.obl#u#zbV#z.K.K", +"#i#x.Z#tbL.K.kbQbAbVbK#u.ybSbV#z#G.w.w#G#D#G#0#G.1#G#D.1.1.1.1.1bVbV#z.yaBaM.M.5.y.y.y#ubV.w#P.w.w.w#b.1.1.w.wby#b.w#b.w#b.w.1.1#u#u#ubVbAbK#z.S.T.TbO.Z#vbga3axbD#xaZ.8bAbAbAbA.e#4bA#ta6.P.6.6", +".S.4bL.e.e.e.ebA.8bSbSbSbVay#0#G.1.1a0.1#ba0#H#bbc#Hbc#Ha0bc.1.0#z.8#T.J.l.ebVbV#G#G#G.w.w.w.w#P.w#b#n#b.1.1.w#n.1.1.1#G#G#D#ublbl#2.4.4.g.Z#ZbN#9#9aa#X.g.ZbOar.Mbvbla5#z#zbA.laPbNbi.U.U#..Zbw", +"bL.e.e.e#zbSbSbl#u#DbS#G#G#0#G#G.1.1.1.1bc#Ha0.1#G.1.1a0#b.1#u#F.e.4#T.8by#b#na0a0#b.w.w.w.w#P#0bVbV.1.1#G#G#u#G.1#G#G#ubS.8.l#T.Z.g#ibW.UbNa9#p.UaP.9.S.ybVbV#Dayay#z#z.e.4bT#i.pad#pbN#.bRaI.T", +".4.e.KbS.8blblbSbSbS#GbV#G#0#G#G#G.0.1.1bcaz#H.1#G.1.w#P.w.w#z.8bK.KbQbQbV#u#D.1#0#G#G#G#G#G.1#P.1.1beazbe.1#G#u#zbK.K.4bO.Z#j#v#A#ka9.YbW.ZbL.4.R.R.ibn#D#u#F#FbS.S.4aqaPbNbi.I#.bWaP.gbObL.8bL", +".K.K#z.e#F.lbv#F#z#GbS#u#u#G.w#G#u#G#G#G.1a0bc.1#P#P#P.w#GbVarar.R#J#HaY.1.1.1#H#H#b.1.1bc.1#P.1.w#b#bazbe.w#zbA#t#t.Z.Z.Z.g#.#.b1ba#..Z.Z.lbS#u.y#u#ubSbS#N.laA#j.ga9#kad#ka9#..g.g#tbO.e.e.ebA", +".l.l.8.y.8bAbAa5bSbS#ubSbS#0.w#G#G#G#G#G.1bc.1bCbm.1.1.0#Dblbv#T#D.R.ybVbe#nazanananbeaz#b#bbc#H.wa0.1#sbV.S.S#t#t.s.Z.sbwaIaIaI#t#t.4bA.lbl#ubl.3a5a5.e.4bh#V#XbN#k#kaG#k.L.OaIbL.e.K.ebA.y.4.8", +"bSbAbAa5.ebA.8.4.8.ybS#z#G.w#0bSay#0bm#G#G.0.1.0bc#H.zbf.zbe.1#z.KbVbSbA.y#D#D.1bebebe#HbeazazazazazbebV.S.4#1bMbZbR.Z.Z.Z#t#tbYbl.o#ubS#Gay#0#uarbl.laB#t.uaT.Oad#kaGb6#ka9.g.Z#t#t.4.4#t.4bK.K", +"aBbs.y.ybA.l.lar.4aBaB.8.y#F#u.wbn#D#D#G.0.0a7.FbdbCbc.1.1.0.1bc.F#8#H.1.ybG.4.ebn#s#s#baY#saYaV#b.w#s#J.SaZbD.sbR#t.S#z#ubs#F.R#D#D.0#G#G#G#G.0#D.R.yaBbDbDaP.g#Zb1.L.fb6.h.hac.I.YaT.u#t.Z.Z#2", +"b3bR#1.4.4.4bX.R.K.KbV.ybl#F#F#F#za5a5.B#z#0#sby.1#G.1.1.1bm#G.1a0a0#H#H#b#b#s.ya#.X.y.ybVbn.w#bbebeaY#sbAbRbZa2au.S.R#s#z.y.e#zbs#ubn.1.1.1#G#D.0#D#D.RbA.4bO.4aPbD#Eb#af.I#Maf.2.x.L.L#Z.O.n#S", +"aObi#Xbw.s.sbY.SbXbK#z#z.w.w.wa0#z#za5bS.l.l.8bVbSbVbS#G#G#G.w#Pbe.w#b#bazbrb4#Hbebebe.1#u#F.5.X#F.y#s#Y.NaN.Q.Q.T.Tbu.w#sbn.1be#sbVbV.y.y.ybn#b#G#G#G#G#0bn#zbSbn#bbn#D.R.RaBbX#3.O.Yaf.I.Ibi#E", +"aVbX.G.6a3aCb3#U.y#z#s#0#z.w.w#s#H#H.1.1.0#G#Hb4bVbV#u#u#u#D.0#D.1.1.1#D#7#D#Hb4bCbc.1.w#b#b#n#nbe.1#u.yaBbX.S.kb4.cb4aYbA#T.4#r.4.K.K#s#s#s#D.y#GaybV.w.w.w.w.w#G.w.w.w#b.1bn.1#P.w.w#0#0aybS#G", +"bnaVaYbeaNarbp.A.P#2#F.y#u#s.w#sb4b4.1.1.1.1#H#H#nbeaz#b#HbnbCa7.zbe.z.1#D#D.w#Baz.z#H.w#P.w.w.wbebeanbrbebn.RbX.4bQb0aL#BaYa7.bbA.4#xaMaZ.ybK.kbA.4.4#F.8.ybA.ybv#u#ubS#sbV#D#zbl.ray#G#G#P.w#P", +".w#0bSbVbV#D#D.1aY#b.w#zbS#FaBaB#x.M.l.8a5byap#bbn.1bebebebebeaza7.0bd#u#ubSbS.BbC#D.0#D#G.w.w.1anazb4bebebebr#B.V.c#D#Oai.S#s.WaE#Y#Y#YaY.kaB#x#4.S.S.4aBbX.y.y.y.K#z.KbV#z.ybV.ybKbKbK.K.K#z.k", +".8.8#u#G.w#HaV.1#s.w#s#0#zbV.wbQ#na0by#0a5bSbvbg.M#F.y#ubSbA#z.k.w.w.w.wa0a0.w.w#H.w#HbV#D#u#G.1.1.1#b.w.1.1#D#DbVakaLaLaLbq#B.VaB.XaB.ybKbQaLaL.q.qaY#a#b.w#b#b#b#b.wbn#s#D.y#D#s#s#s#JbKau.SbA", +"b4#Hbe#baY#s.K.S.y#F.ybSbS.R#zbe#H#H.1#Gbc#b#bbn.w#bbybQ.4#xbga6#T.l#za5bV#G#Gbc.w#b#b.wbV#D.1beby.wbVbV#z#s.w#Y#bbeaY#J#s#Ybe.1#B#B#Bbr#s.RbA.KbKbnaV.w#b.w#Ha0b4anbe#Hbe.1.1#bbC#8bc#Ha0a0#Pbc", +"b4#8#8#H#HbCbC.1b4#b.w.1#P#G#G.0akbVbXaB#2#2.4bAbA.KbAbV#s#b#YaY.1bV.8aZ.GbYaB.S.RaV#abebn.1#8az#b.w.w#b#ba0by.w.1#Hazbebe.1#s#b#ebnbnbnaVaVaYbnbnb4bebe#abe#abebnbnbnbn.ibnbnbn##a7#8#8#ea7beaL", +"#Y.w.w#s.w#0#z#0#D#DbVbVbVbV#bana7#D.1.1#b.1#D#D#u#u#Fa#.o.y#D#D.r.r.w#b#Y#b#b.w.gbkbg#Tar#za5a5####.5.b.Ra7.1bn#HaV#H#Hbn#D#D.ybQbQ#z.K.e.K.e.ea7bnaVa7bnaY#aaL.m#Wbrbr#Ybr#W.m#L#L#L.mbeb4.w#b", +"#sbK.ybS#z#zbSbS.k.k.K.S.SbAbKbn.w.1#D#GbV#GbV.w#G#G#G#u#u#ubl#7.r#G#G#0#zayay.0#Y.wa5bS#zbS.8.M.4.Z#xbka6#TbObO#D.Rbn#s#bbebebebV.R.R.y.R#D#DbVbebe#BbqaLbebn.Rbnbnbebr#BbrbeaV#Da7bran.mbr.1#D", +"anazbean#Banbe#H.y#O#x#x.ybKbK.R.Jbvar.ebja5#N#TbvbS#z#0#0.1#0bV#G#u#u.o#Fbb#7bm#F#7#u#D#Dbn#bbe#s#s#sbn.w#zbVbVbkbpbpbpbhbhbhbhaAaAaWaW#N#r#rbFbs.ybKbn#b#YaLbq#Bbrbebebebr#BbqbeaLbe#Y#B#B#B#B", +"a7#DbCb4azananan#BaL#b#Yby#b#G#ub0aN.e#x#i#xaWbObAa5.e.8.4#2.4.4.w.wbQ#zbSbSbVbV.w#z#zbS.JbGbG.l#D#GbV.1.w.1#G#G#H#8#8#8aoa7#8#8#D#Dbn.1bnbC.1bC#b.w#D#D.y.5bs.y##a7#Hbranbe.1.i#sbn#D.Rbsbs#ubs", +"#b#0.y.8#2#2#2#2#F#u#G.w#0#G#Pazb4b4beb4bnbn##.5#xaB.4.4.4.e#z.K.e.SbA.8bA.ebK.K#zbV.y#ubVbVbVbVar.8ara8ara8a5ar.RbV#zbVbA.y#D#sbSa5a5bV#zbSbVbS#G#DbV#b#b.1bn#bananbeb4b4anananbean#B#B#Bazbebe", +"#0a5bSbV.w#Y#BaE.1#0.wbSay#uay#Gbd.FbCbC#H.zanaz#b#b#b.w#zbA#2#c.P#6#6.M#2.e.K.k#KaB.Xbsbn.1.1#7#Hbna7#D#D#D#D.0#0#zbVbV#u#F#FblbdbCbC.1bC#G.1.1bV#u#D#G#Hbean.manbeanan#B.manan.mbebe.1bV.1.1.1", +".zbCa7#Hazanb4#8#Y.w.y.8#z.w#G#D#G#0#P#0#0#0#uaJ#D#u#ubl#D#0.wb2.w.1#0#0.w#z.4.G#vbhbRbO#rar#N.l#4bL.S.4.4.4.4bLay#D#uay.1#Ha0.w.1.w.1.w#G#s#0.w#G.1.1an#Bazb4b4anazb4b4.zananan#f#f#8#b#H.w.1#b", +"b4#Hbd#Ha7#H.1.0a7#H#b.wbV#s.w#0#D#D#D#D#G#u#u#G#G#G#GbV#u.8.y#ubs#7#G.1.1bn#D.y#xbXbAbAbYbt.Z#RbXbK#s.k.R.S.RbAbl#F.o.o#Fbv.yblbV#u#7#G.1.z.z.z.w.1#G#u#D.0#G#nb4#H.1.1#b.zb4.z#H.1.1.1#Hbe.m#B", +"#Y.w#D.1ay.w.w#Ga7#H#H.w#G#G#G#G#D.wbV#G.1.w#G.1#D#D#ubSbA#u.KbV#s#G#u#u#ubVbn#s.zb4b4#sbO.g#V#X.MaB.yaBaB#2aZ#2.y.y.R.KbQ.KbQbu#zbAbK#s#bbe#Ybea0be#bbn.w#D.y#G.1bC.1.1a0#b.z.z.zbc#H.zbCao#HbC", +".wbS#0.wa0a0#na0azaz#b#H.1#G.0.0.w#P.w#G#0#G#uay#D#DbAbK#z.KbSbK.l.4bv.8#F.l.e.S#ubAbA.RbK.K.K#s.4bAa5#z#z#z#z#z#w#m#3ba.p.p.L.L.ZaZbD#t#R.SaKaKakap#Y#bak#s#zakbn#D#u#D.y#7bs#7#F#F#u#0#0#0by.w", +"bna7anbran#8az#8.1#ba0#bbcbeaza0a0.w#G#G.1bm#G#0.1#z#GbV#z#0#s#G.e#z#z#za5.8bGbgaAbv#T.l#F#Da7a7bQbybQ#z.e#z.ebAblblay.0ay.raJ.obR.s#tbR#t.s.s#tbDaZa6bT.Z.gbT.SbA.S.S.KbQ.q.q#YbqaLbeaV#D#u#D#u", +"auauaL#W#Wbr#L#Wbe#nbe.w.w.w.1a7.1#H.1.0#u#7#7.r.0#ubl#uay#Gay#u#z#za5#u#ubS#za5#D#u#u.8.8.8.8#r.4bYaZ.G.GaZaZaZ#t.SbLbFb.#5bO.Z#t.Z.Z#t.Z#iaC.E.Z#1.g.ga6#ibWbR.C.s#..OaPbNbi.Ua9ajaO#X#v#y#r#h", +"bL#1b.aI.g.I.UaP.GaZ#t.4.SbK#sbQbe#Bbe#b.1#D#D.w#G#DbSbl.8bl#u#F.8aB#F#F#F#ubV.w.ybSbS#u.8.8a5#z.k.K.KbK.KbQaYakbu.K.S.4.4.4.S.e.4.8.4.ebF.Kb.#h.gbR#taq.ZbW#E.gaP.YbNba#.babaaP#3.u.s#R#R.S.KbK", +"a6a6.Z.ebO.T.QaNa2a2aIaT.Ub#.6.EbIaZaZ.4.S.SbA.kakbQ.k.KbF.ebA.y.e.ebSbS#u.8#FbG#r#r#r.e#F.ybsbdbV#zbV.yaBaB#2#2#MavaS#Z.O.O.OaPa6#i#i.ZbRaI.H.n.ZaIaI.T#5aIbRb.b.bLaIbRbR.gbWaP.g#v.g.Z#x.gbT#i", +"#H.1#DaY.ybV.SaB.Y.O.O#.#X.ObBaIbR.T#1#t#1.Z.g.ZaP.U.U#EbW.g.g.g#T#T.4.l.l.8bS.e#F.8#F.l.8arararblbSa5#0bS.BbS#ubV#u#ubl#ublblbl#5bZ.gaP#.babN.pb##E#E#E.Z.g.gaIaB#2.ZbL.T.e.e.K#z.kby#b#b#Y#Baz", +"brbrb4#Hb4.1#D.0.R.y.y#F.yaBbvaB.Z.g.g.g#jaOaxbxaFaS.Y.O.s.s#ta2#Fbla5bSay#ua8bl.y.y.RbK#J.KbKbK.S#F.y.8.8bA#F.l.y.y.8.8.4.4.4.4aPbtaPaP#E.YaPbNaP.Z.sbwbw.C.CbZbB.C.Z#..O.H.OaP#RbX.SbK#JbnaV#a", +"aZ#taZ.Z.4bLbO.ebLbR.S.TbL.T#4buaK.S#R#R#4.Sbw#t#3aT.Z.ZbD#i.E#i#Z#ZafafbN#Z.na2.3ay.B.Bay.B.8a8bn.y.4.4.4.8.8bAbl.y.ybKbS.e.e.8#F.K#s#s.k.KbLbObL#t.Z.9.G.GbI.E.G.9aP.g.ZbZbZ#tbJaI#.#EbW#E.g.Z", +"aKaKaH.u.C.C.sbw.O.O.O.O.Y.Uba.O.uaPbtaT.u.s.s#Rb.#4#5bLbL#T.Z.4.4#t.4.4#t.4.y.ebKbAbV.KbAbAbA.K.KbVbAa5#z#z#z.y#z#zbS.8aB#2.M#2.o#F#ubl#F#u#G.wbQbKbKbnbQ#YaL#Y#saY.KbAbYaBaBbY#.bibiaPaI.Tb7bR", +"#h#5#1#X#jaOaaaa#M#paf.Ybaba.n#S.H#.#.aDaqaqaq.HaPbW#x.Z.4.Z.4bR#RbLb.b..k#4#R.4#RaH.u.u.u.ja1aK#F.S.4.K#zbQ#zbVbSbSbS.ybS#DbVbVayayayblbbbl#u#G#D#u#u#D.1.1#b#H#H#b#b#GbV#s#b.1#L#WaL#WbqaLbK#K", +".zanbeb4be#aaY#aak.k#4bL#t.G.G#i#1#j#j.gaq#j#.bW.ZaT#tbRbObRbLb.#u.r.r.r.r.rbmbm#za5bv.la5a5a5a5.K.4#xbg#xbg.MaM#2.8bV#s.w#sbV#ubS#z.1#z#G#G.1#G.1.1.1.1.1.1bc.1.1.1.1#G.wazaz#Bb4#8bC#Hbebe#H#b", +"#D#G#G#u#0#zbSbSbVbVbAbAbV#z#z#s#JbK.R#s#saYaVaYb.#4.SbL.4.Z#t#t.L.LaS.Lba.O.n#mbQ#z.K#zbQ#0.e#2bQ.K.K.K#z#s#z#D.y#F#F#F#F#F.oaB.8.y.8.y#ubV#0#D#u.r#G.0#G#G#Gbc.1#G#G#G#G#Hbc.1#naz#b.w.1#0#0#P", +".z.zbcbCbcbC.0.0be#b#ba0#H.1.1.w#Dbdbdbn#H#8.z.z#BaL#b.w#sbV#z#s.K.K.K#z.K.K#z.K#R.C.j#RauaubYbt.6#6a6bL#zak#bak#D#D#D.y#u#u#0#0.w#sbV#u#F#Fbl#u.w#0#G#G.1#G.1#G.r#GbV#GbV.1bc#H.w.w.wa0#0bS#G#0", +".w.w.1#G.1#P#G#P.w.1#H.1.1#D#D.1by#0#0#G#P.w.w#b#Hbc#Gay#G.r.1.wbv#F.l#F.laJbvblbA.8.l.8a5#z#zbS.K#4bO.4#TaBaB#Fb4#baz#b#P#zbl.o#F#D#0#G#G#GaU#0.B#u#u#u#G#G#0.1.w.w.w.w#0#G.1.1b4anbraz#8.1#8az", +"b4.1bnbC.1b4.zaz#f#fbr#fb4#8.Van#f#8#8ananbe#G#u.1#G#DbC.1.1.w.1.w.1#G#G#GbS#ubSaiaB.SbXaB#2.4bKbvar.ebF.T#1#j.gah#O##bnbn#D#baY.1#D#DbS#u#D#7#7.o#u#0.wbya0a0#0.wbn#0bSbAbS#z#0#8#8an.z.1bd.1a0", +"#b.1.1bn.1bebran#W.man.manbran.m.m#Bbebe.1#D#D#bbCbCbC#GbC#G.1#G#u.8#ubSbVbS#z#z.w#s#D#ubV.1.w.w#Da7bd#Dbs.5.5#O.Q.Q.K#N.Jbgawax#O.y#z#s#z#z#b#B.zazaz.1#GbC.0bd#7#D#ubSbV#G.wbebr.Vbe#8#D#7#7#G", +"#b#b#b#b.w#b#bbeb4#H.cbebe#bbnbK.e#z#z#sbVbs#D#G#z#z#za5a5#za5a5#sbn#z#z#z.y.8bAbl#F.o.o#u#G#G.r.1bnbn#D#DbV#z.w#T#x.MbGbla5a5.eaB.S.SbT.6.a#2bK.1bn.1bn.1bean#lazazbe.1.R#F.5a#.S.e.ebUbU.W.Wap", +".ybAbAbKbK#DbV.waV#HbebebeaYbnbn#z#FaB#F.y#D#Dbnbe#H.1bn.1#Dbnbn#8#eao#e#8#8#8#8#0#0#0.w#G#G.ray#2.J#2#2.la5#z.w#b.1#u#Gbnbn#D#DbAbA.4.4.8bA#z#z.e.8#T.J#x.l.K#z#D#0.w.w#b.qbraLanbr.Vbr#8bd.b.b", +"#B#B#Bazbrbebebe#8brbrbrbe.zbrbr.mbrb4#H#b#sbVbV#NaW#T#T.J.JbkbkaAbp#Vbpbhbpbpbp.e#zbQ.w.w#s.1.w#H#b.1#G#D#7#7#FbS.8.l.l.8a5#sbybV#G#0.w#0#z#Fa#.4#NbOar#r#r#z#za8.ybS.8.4aB.SbK.cb4anan.mbeanan", +"brbrbebrazbr#f.Vbr#f.manb4bebean.V.V.m.maL.1bA.y.Rbnbnbnbnbn#Hb4#Y.w#saYbQbnbK.RbT.GaM#2.4bVbVbK.8#F#u#z.wbybyby#G#G#zbV#u#F#F.obb#uay#0#0.w.w.w#b#b#sbn#D.X.5.b#z#0#za5bAbA.K#s#TaAbObO#T#T#raN", +"bnbnbnbeanbq#l#Lan.maLbrbebebrbeaVb4b4aVbnbn.wbe#T.4.ybAbK.KbQbQ#D.R#D.1.1#H.1#H#Y#s#zbVbV#z#u.ya5a5ar.l#T.J#vawa7#Hb4be#b.1.0.0#G#ublbv#c#c#2#u#Dbd#D.1.w#Hbean#b.w.wbVbSbVbVbVbVbV#D.1bV.1#ban", +"#Bbebe#abebeaVbnbn#sbn#D#s#a#b.w.q#b.q#Y#Ybe#HbnaY#baY#baVbnaVaV#bbn.w#bbebeaV#H#D.1bebe.w#G.wa0.z.z#HaV#HaYbnaV.ebLa6a6a6bOa5b2.w#b.w#zbU#s#s#zbA.lbv#T#T.l.y#0#8.1#D.1.wazaza0.w#P.wbebe#H#baz", +"az.1bcbc.1.1bCa0#H#8b4b4#H#Hbebr#b#bbn.ybXbK#s.c.ia7bebe#zbV.8a5bnaY.caLaLbe#H#H.kbKbKbK#s#b#b#H#bbV#DbV.wbe.w.1bCbCbn#D#2bg#i#i.J.lbA#s#b#bbQbQ#JbVbVbS#G#u.R.R.SaB#2#2aB#Fbd#H.z.1.wa0#b#Ybe#Y", +"au.S.S#J.k.R.kaY#DbVbV#sbn#s#s#b#Y#Y#Y#Yak.q#Y.N#Y#Y#a.R.y.y.ybV#ebrbq#WaL#B#bbV.i.RbVbn.1#bb4b4#s#D.y#ubV.1#b#H.1.1#bbe#Y#b#s#z#z#z#D#7bs#u.y.lai.5#F#u#0.wbebe.qakbQbQ#baY#b#b.1.1.0#G#D#ubb#F", +".k#s.k.k.K.KbK.KbA.KbK.K#z#s#z.K.5aBbX.4bY#RaHbY.Z.4.e#s#sbnb4#H.q#Y#sai.dbs#8anbeanan#Ybe#H#H#8#b#H.wbV#G#G.0.1.wbV#u#F#7#D.1b4#bbebebeazb4.1bVbebe.w#z#u#FaBai.4#2.4.ebQbQ.w#Y.w#G#GbVay#u#z.w", +"bm#G#Gaybl#ublblbAbA.8bSbAa5bS#F#D.1#zbnbVbK.K.K.K.e.4aB.y#Dbnbea7#8brbq#Y.K.ebU#Hbe#Yanazbeazanazaz#n#n.w.1.1.1.w.w.1#Pa0#b.1.0bV#G.1.1az#b.w#s#sbVbV#ubVbV.1#s#z.yaB#2bG.M#xbgbG.8#z#Yb0#b#s#z", +"bS#GaybS#G.w#b#b#zbV#0bV.w.w#G#G#G#G.1#G#zbV#D#u.y#D#z#s#s.K.8aiar.4.4bV#sbn.cbr#s#u#2.M#x.y#D#b.1#b#b#b#na0a0a0a0.1.0.X#7#u.1a0#z#D#u#F#u#ubVbV#n#n#b#Pby#b#Y#n#bbn#D#DbV.KbV#z.K#1#i.6.6bDbL.Q", +"#Ebi#p.U.Y#Z#C#3bAbAbKbV#s#G#s#0#D#G.w.w#0bc#Gay.1#D#7#F.ya5#s.WaV.cbebn#sbQ#h.T.K.kbQb0aE#YbV.X.y.y.y.ybV.w#b.1#8.1azazaza0a0.wa0.w#0#GbV#z#z#0#F#F#F#F#F#u#ubVbe#b.1aY.wbV.ybAbRbR.Zaq.Z#E.U.U", +".n#Z.p.Las.faQ.fafaf.U.UaPbD.Z#t.4bK#za5#z#G#G#G#G#G.w#G#GbV#u.ybUbQ#z#zbV#JbKbYb.#R.Z#tbA.wbe#n.R#D.y.y.8#Dbn#D#Y.w.wbn.w.waza0.1.1#H#b#P.w#GbV.w#0bV#u#u#u#u#ubv.o#F.y#DbK#z.K#z#4.4.S.TbL#t#t", +"bLaZbD#R#taP.U#Z.hb6as.L#k.pba#ZbD.s.ZbTbG.8bS#Gay.B#G#0#G#D.0#D#s.y.ybVbV.4.ZbL.s.s#R#4#s.w#H.1aY.qbebQ#s#s#sbnar.l.l#u.1#HbC.FbC.1bC.1.1.1.1.1aybVbV.w#s.w#s#0by#za5#u.y.4.l#r.y.8#F.8.K.e.4#T", +"#4#4.S.4#taZ#T#2aZaTbNaQ#daQ.fasaS#QaT.s.4.8ararbl#ubVbV#ubl#F.XbT.G#t.S#tbkbT.T.uaH#OaB#D.1.zaz.z#f.z.zb4.za0.z#Jbn#JbK.ybAbK#s#z#baz.z.z.zaobc.0.1#G.0#G#u#G#G#ubS#0bVa5bS#uaBaB.y.y#u#F#FbA.K", +"#zbK.e.S.8.S.S.T.O#Z.LaQaQaQb5af#..Z#t.4#F.yblblbl#ubVbVbK.S#t.saI#tbwbZaI#t#t.S.n#1.TbF#zbQby.wbebranbraz#b.1.wan#nbe.w#z.y#FaB.8.ybn#Haobcbcbc.1.1.1.1#G#G#G#0#G#0#GbV#ubVbVbV.8bAblbAbSbS.K.K", +"#F.l.8.4bLbRbRbR#Z.L#kafafbN#..Zbg.Jbv.8#u#D.0#7#ubS.y#t.s.Obaas#3baaP.Z.sbD.Z.Z.y#JaY#a#Ybe#b.wb4#b#bbebebebe#bbm.0#u#G.w.w#0bVbGbAbVbV.1.1.w#P.1#Ha0bc.1#Day#D#0.1bS#u#ubV#zbVar.8.l.8a5a5.e#N", +"#T.4.4bObw#.bNad#k.pba#.bR.4bAa5ara5#zbVbV#u.y.4.K#t.gbi#pb5.p#k.ZaP.Z#t.S.y#Dbna7bCb4.zazb4ao.1#b.1.1bVaybV#G.wa0.w#G#z#0#z.K.y.8bV.w.1.1.1bc.1bcbc#Ha0.1.0#G#G#G#G#G#G#GbVbV#ubla8a8blbSa5.8.4", +".e.T#1bw#..paQa.#E#v.Z.8.ebSbSay#FblbA.y.S.T.TaIaDbN#paj.U#v.g#ta6#TbAbSbS#G.1bc#GaU#P.w#0#GbSbS#G#Gay.r#D#G.w#P#D.y.8.4.4.e.e.e#u.1#P.1bc.1.1.1.0#Ha0#Hbc.1.1.way#0.w#0bV#GbV.ybl#F#u#zbVbKbA.y", +".g#.bW.UaOa9#..O.4.8bAbSbS#u.lbv.K.K.S#x#Eb#.v...Yba#..Z#T.4#Fbvbl#ubS#G.0#GbCbc#Pbc#P#P#G.w.w#P#Gbc.w.w.w.w#P.wb0.qbQ.K#r.S.S.S#G.1b4#P#H.1bc.1.1bca0.1#P.w.w.w#G#z#GbVbVbSbSbS#DbV#s.K#4.S.4.4", +"#EaC#i.gbT.4.4bAbAbAbSbAbA.4.ZaPa3.6#6#E#x.4bLbL.4bAbKbAbSbS#ubS#0#P#P.w.w.1.w.1#H.1a7bCbn#H#H#Hbybyby#z#z.8.4.4aM#xaZ#2.8.y#GbV#Gbc.w.1#G.w.1.wbcbC#G#G.1#G#GaybSbSbS.8bla5bA.8#z#z.KbZbRaT.ZaP", +".4#r.K#z#z#G#ubb.8.y.y.y#R.O#Z.tbMbM#5.ebA.R#D#Day.rayaybV#G.wby.1#G.w#G.w.wbV#u.TbObO.Z.Za6bD#ia6bTbDbD#iaP.s#t.K#s.wbya0#P.1bm#G#0#0.BbSayb2#0.1#G#u#GbVay.8.8blbSa5bSa5#za5bAar.Z.gbaa9baba.O", +"b2bS.8#N#T.Ja6bk.M.M.lbS#z#G#z.w#ubV#GbV.1#G#D.ra7bnaV#H#Hbnbn#D.l.4#2.E.6.6bT.T.X.X#u#D.1.1b4be.1#G#G#G.0#Gbcbc.1.1.w.1.w.1#D#G#D.0.0#D#GbVaybS#G.1.1#Dbn#DbnbV.SbA.KbVbK.4aZbD#F#ubVbSaybV.wbn", +"#D.0#Dbn.1#sbQ#s#za5#z.w#zbS.y#ubV.kbVbVbVbVbVbnaW.l.l.4#Narar.8bCbn#HaVbnaVbebea0.w.w.1.1a7#u#7.1#s#H.1.w#Ha0#b#G.w.w.w.1.w#G#G.0#G.1#0.w#0#0.wbS.ebS.e.l.4.JbG.y#u#D.w.w.w#sbQbV#s#0ay#ubV#D#D", +".0bn#Gbn#D.R.R.RbV#G#z#0bV#u#u.y.SaBbYaB#t.4bA.ea5#zb2bSbSbVbV.w.0.0a7#Hb4#Hbn#7a5#z#z.w.wa0a0#bbeaz#b#b#bbn#D.y.1#G#G#G#G#u#G#u.1.1#b.1aybl#Fa8bG#T.8.eby.Wb0bP#G#Gbm#Gbm#G#G#G#sbn.w#z#G#G#zbn", +"#z.w.w#zar.4#T.Jbv#F.ybSbV#ubSbVaY#s#s.Ka5.K#z.Kbl#u#D#G#D.rbd.ra5#0bS.BbVa5#ua8.ybla8#u#0#G#G#G.0#D#G.wbe#B#Ybe#P.w.w.w.1#0#G#G#G.1#P.w.w#0#0.w#baY#s.wbn.0#D#7ay.rbm.r#G#G#G#GbV#0#z#0#G#z.1.w", +".8ara5.Ka5.ear.e.w.w.wa0#bby.w#b#0#0bV#u#F#FbGbv.8.8ay#z#0#0#0#0#z#0a5aya5ayb2#0bV#GbV#D#u#u#D#Ga0a0bc.1bc#G#D#u#Day#D#GbV#G.w#s.w.w.w.w.w#z.w.waBbs.y#D#DbC.1bCbV#G#0.1#0#G#0#zbKbSbSbS#u#ubVbV", +"#Hb4bebeazbeaz#Y#ubV#u#z#u.y.8#F.w.w.w.w#0.w#0#z#G#ubl#F#u#u#u#Fbd#u#D.0#7#7#7#D#u#D#GbV#G.w#bbebc.1#G#G.1.w#P.w#b.wby#s.w.w#s.w#z#z.KbA.4#F#T#2ar.e.ebA.ebAbAbSbQ.w#s.w#z#zbK.4.y.8bSbS#0bSbVbn", +"bn.1a7bnbn#D###u.1#0bn.w#G#z#D#0#0bV.w.w.w#bbe#bb4b4#HbCa7#Dbd.ybs.R#D#u#u#F#7bs#u#u#u.ybA.S.4bLap#b.WbQ#z#s#z#z.8.4.8#2#2bG.MbT.4.SbA.S.4.S.K.Kararar.ea5.ebS.e.8.8.ybS#z#z#s.KbAbla5#0#0.w#s.w", +"#s#z#s#z#z#z#za5#D#D#GbV.wbV#z#0.Ka5bKbAau.R.S.R.lbAa5.e#r#NaAaAa6.ZaW#N#N.e.e.e.BbSa5.earbOa6#Ebi#EbDbDa6#t.4.4.ebA.SbA.e.K.K#zbL.T.KbL#t#TbL.Kbn.1.1.1.w#Hbeb4bV#z#z#G.w#z#z.K#za5#zby#0bVbV#z", +"#u#D#DbV#u#ua8#ubXau.y.y.ybs#DbsbK.SbL#RaIaI.C#3bw#t#R#R.S.S.S.y#t.gaPaP.gaT.Z.ObabaaP.Z.Z.Z.4.l#F#2#2#O.S.ebA.8.S#2aB.y#zbKbS.y#u#D.1.w.1bnbVbn#zbK.y.SbK#4.S#tbSbV#u.8.8#u.8#ubV.y.y.y#ubA#ubV", +".##q#qat.tas.2.2#A#A#AbH.H#C.H#CaMbI#x.GaZ.9bD.G.9bD.GbT#2#2aBaBbK.ybAbKbK.S.S.S#t.Z.Z.4bAbK#zbV#sbV.K.K.K#s.KbV.K.y.SbA.KbK.y.S.4.ybAbK.K.K.K.K.K.K.e.K#4.K#4bLa2#5.D#5a2aIaIa2aIbBbZbwbw.s.OaP", +"ba.O.Obaba#.#.#..A.A#v.Abkbkbk.A.y.8.SbA.e.S.S.4.K.e.e.e.e#z#z#0bS#ubV#zbV.y.ybS#4.SbY.S.y.yaBaB.4#t#t#t#t.S.S.S.e.4.4.S.K.KbL.S#hbF.TbR.gaPbWaP#Z#ZbaaS.p#kb5b5bNa9#..O.O.Oaq.ObaaP.O.O#Zba.Y.Y", +"#D#u#u#uaybSbS#u#s#s#z.w#s#s.1bnbQbQbQbQbQ.Q.K.T#t.4.Z#2#T.4.4.4bAbA.SbA.S.S.K.KbQ.K.K.K#5bLbL.SbO#R.T#5b.#5.K.kb.#5bLbZbZbR.Z.gaP#.aPbNbNbN.O.Hbwbwbwbw#3.O.O.O#2.4.8.8.8.8.ybAbA.e#z#s#z#s#z#s", +"#5.TbLbL.TbLbLbL#m#gae.CaX.Caeae.Z.4#tbLbLbZbR#tbObR#tbR.4.4.4#t.saP.U#E.YaP.U#..UbWbibWbNbNa9#..gbW.Z.sbwaP.G.9aP#E.U#E#EaPaP.U.Y#3bBaIbw.Cb.#w.ybSa5bVbSbV#z.w#z#z#z.K.K.e.ea5bAa5.ea5.ea5a5.e", +".U.Y.YaTaT.Z.O.gbRbRbwbw#tbB.s.ZbTbT.Z#t.4.4.4a6#t.Z#t#t#t#ta6bDaIbZbB.n#m.n#3#3#X#.aq.HbH#..H#m.TbRaIa2.DaI.T#4bwbRbwbwbZb.bob.#4b.buaK#R.s.9#t#3.O.O.Obw.sbw.sbwbwbwbw#tbwbRbB.Z.gaP.gaP.gaP.g", +"aB#FbSbVbV#D#ubVaya8bl.8aybS#u#u#zbVbV#zbV#zbK#u#u#u.y.8.ybA.ybA.4bY.4.4#t#tbDaZ#tbR.4#t.4#t#tbL.K#tbwaI#5aIbLbFaIaIbwbD.U#E.Ubi#EbDbD.ZbT#xbT#xabaRaR#oabat.O#Z.s#t.SbLaI#4aKb.b.b..Kbu.7.Qbub.", +".w#b#b#Y.w#0.1#G#z#G#z#G#b#b#b#s.1#G#G#G.1bc#G#G#G#Day#G#G#G#G#G.w#G#GbV.1#z.w#b.kbnbKbn#s#DbVbV.K#t#iaP.ZbW.g.Z.s.s.gaPaP.Zbw.Za6.Z.Z.8#r#z#ra5#D.r.r.r#Gbcbmbm#G.1.w.wbc.w#G#G#G#G#G#Ga0#P.1.r" +}; + + + +/* XPM */ +static const char *button_xpm[] = { +/* width height num_colors chars_per_pixel */ +" 96 96 254 2", +/* colors */ +".. c #9c3218", +".# c #a4733e", +".a c #bc450a", +".b c #d4700c", +".c c #dc8c29", +".d c #bc5e00", +".e c #d46b37", +".f c #945431", +".g c #bc5a2c", +".h c #8c4e4b", +".i c #d47e16", +".j c #bc7422", +".k c #d47d3a", +".l c #d45e28", +".m c #ec9b3e", +".n c #bc6b43", +".o c #d45a13", +".p c #a45236", +".q c #dc8848", +".r c #e46b1b", +".s c #bc652f", +".t c #a46243", +".u c #bc6920", +".v c #a4391e", +".w c #e47b35", +".x c #9c6b30", +".y c #d46d24", +".z c #ec8a29", +".A c #bc452a", +".B c #e46833", +".C c #bc702e", +".D c #c47845", +".E c #b15314", +".F c #e47e10", +".G c #bc5a18", +".H c #bc6145", +".I c #a44d16", +".J c #cc5728", +".K c #d47439", +".L c #a45b39", +".M c #cc5815", +".N c #dc8f4c", +".O c #b46239", +".P c #bc5307", +".Q c #d4794f", +".R c #d47624", +".S c #cc6c2c", +".T c #cc6941", +".U c #ac5222", +".V c #e49328", +".W c #e4754d", +".X c #d4650b", +".Y c #ac592c", +".Z c #c05e2d", +".0 c #e4751a", +".1 c #e47d29", +".2 c #9c6143", +".3 c #e45f2b", +".4 c #cc632a", +".5 c #cc660d", +".6 c #b44b13", +".7 c #d48442", +".8 c #d66228", +".9 c #bc6221", +"#. c #b45736", +"## c #d47714", +"#a c #dc8936", +"#b c #e48237", +"#c c #cc530c", +"#d c #8c522b", +"#e c #dc8819", +"#f c #ec9129", +"#g c #bc7936", +"#h c #d46f50", +"#i c #bc521d", +"#j c #bc553b", +"#k c #9c523b", +"#l c #f49a45", +"#m c #bc7548", +"#n c #ec8643", +"#o c #a86d3a", +"#p c #a44d21", +"#q c #a4754b", +"#r c #d46547", +"#s c #dc7937", +"#t c #c4642d", +"#u c #dc6c21", +"#v c #bc4d2e", +"#w c #cc7e53", +"#x c #c45917", +"#y c #cc5c42", +"#z c #dc7036", +"#A c #ac5448", +"#B c #ec8f44", +"#C c #b45c4d", +"#D c #dc7622", +"#E c #b45222", +"#F c #d4651b", +"#G c #e47328", +"#H c #e58429", +"#I c #9c5f23", +"#J c #d47f2b", +"#K c #cc7116", +"#L c #eca24e", +"#M c #9c471c", +"#N c #d45b36", +"#O c #c46716", +"#P c #ec7836", +"#Q c #ac642d", +"#R c #c46f2e", +"#S c #c47551", +"#T c #cc5b2b", +"#U c #cc685f", +"#V c #bc4b3a", +"#W c #e49a4b", +"#X c #b44c35", +"#Y c #e48745", +"#Z c #ac613c", +"#0 c #e47234", +"#1 c #c46242", +"#2 c #cc5e1a", +"#3 c #b4683d", +"#4 c #cc7430", +"#5 c #cc7042", +"#6 c #bf4b0d", +"#7 c #dc6e13", +"#8 c #e48c21", +"#9 c #9c3445", +"a. c #8c432b", +"a# c #cc5e04", +"aa c #a43f33", +"ab c #b46d44", +"ac c #9c5e62", +"ad c #9c4833", +"ae c #b4742c", +"af c #a4522b", +"ag c #dc943c", +"ah c #b46000", +"ai c #c46309", +"aj c #a4441e", +"ak c #dc7f4c", +"al c #ac6e27", +"am c #ac4b4e", +"an c #ec9238", +"ao c #e48518", +"ap c #e47c4f", +"aq c #bc5c3e", +"ar c #d56238", +"as c #9c5840", +"at c #ab6946", +"au c #cc761f", +"av c #9c5024", +"aw c #bc4922", +"ax c #bc421d", +"ay c #e46927", +"az c #ec8836", +"aA c #cc513b", +"aB c #cc661d", +"aC c #b44a21", +"aD c #b4544c", +"aE c #ec8a55", +"aF c #9c5a20", +"aG c #94533f", +"aH c #c4701d", +"aI c #c46b42", +"aJ c #dc5a18", +"aK c #cc7b2f", +"aL c #e49046", +"aM c #c4520b", +"aN c #dc774c", +"aO c #ac4631", +"aP c #b45b28", +"aQ c #944e30", +"aR c #ac6e4d", +"aS c #a45f2a", +"aT c #b4612a", +"aU c #ec7032", +"aV c #dc872b", +"aW c #cc5939", +"aX c #b47844", +"aY c #dc843b", +"aZ c #c4601d", +"a0 c #ec7f36", +"a1 c #c47531", +"a2 c #c47344", +"a3 c #ac431d", +"a4 c #ac7439", +"a5 c #dc6735", +"a6 c #c4582a", +"a7 c #dc7c1b", +"a8 c #dc5d26", +"a9 c #ac5036", +"b. c #cc7742", +"b# c #ac4b13", +"ba c #ac5a37", +"bb c #dc5f0c", +"bc c #ec7a29", +"bd c #dc7813", +"be c #e48b37", +"bf c #f48e28", +"bg c #c44e1f", +"bh c #c44e3f", +"bi c #ac4b1e", +"bj c #dc6544", +"bk c #c44c2b", +"bl c #dc611a", +"bm c #ec7125", +"bn c #dc7d29", +"bo c #cc7752", +"bp c #c4473c", +"bq c #ec994b", +"br c #e49336", +"bs c #d46f16", +"bt c #bc600a", +"bu c #d47a46", +"bv c #d45b1e", +"bw c #bc653a", +"bx c #ac3c1d", +"by c #e47943", +"bz c #a46b2e", +"bA c #d46b2e", +"bB c #bc6c3a", +"bC c #e47f1b", +"bD c #bc5b22", +"bE c #bc6052", +"bF c #d47346", +"bG c #cc561f", +"bH c #b46044", +"bI c #bc5312", +"bJ c #d4775e", +"bK c #d4732e", +"bL c #cc6b37", +"bM c #cc644f", +"bN c #ac512d", +"bO c #cc6137", +"bP c #ec8552", +"bQ c #dc7944", +"bR c #c46339", +"bS c #dc6a2c", +"bT c #c45a21", +"bU c #dc6f44", +"bV c #dc732c", +"bW c #b4502c", +"bX c #cc6d1f", +"bY c #c46521", +"bZ c #c46939", +"b0 c #e48653", +"b1 c #ac6445", +"b2 c #e46e43", +"b3 c #c45851", +"b4 c #e48b2b", +"b5 c #9c5430", +"b6 c #944d49", +"b7 c #c46a51", +/* pixels */ +".waB.U#5#Dba.##u#sbn#H.8#z.0#Db2.4#E.g.e#T#F#z#4bL.n#EbSbm.kauaz#Bbnbr#B.y#b#bb4.w.z#D.z#haKaZbr#Ha6bLaubn.w#Yb4.z#0#ba7an#s#Yb4b4.8.wbnaVaOb3aBbS.l.K.4bL.S#i#5#0#u.w.w#u.w.1#D#zaP#AbK.y#.#a#u", +"#b#F.Y.T#u.O#q#D#z.1b4ar.wbn.0bS#raC#..T.4.lbK#4aZ#Zbi#G#G#s.S.1bebnbr#BbA#b.1.1.w.z#Gan#5aK#tbr.1a6#1aua7bS.w#HbCa5#0#DazbK.w#8#H.8#0aVbXbibRbsbA.l.K.e.e.4#x.T#0.8.wbVbVbn#sbVbSaT#AbVbS.gag#G", +"#bbS.YbL#u.O#q#D#sa7bea5.w#G#D.8.K#ibW#1.4.8.e.SbD.p#pay#G.k.Sbcbebnbe#BbA#b.1bn.1bc#Gbe#1aHaZb4#D.Zb.aLan#0#Dbda7bS.ybCbe.y.w#8be#ubSaY.G#X#1.ybA.8#z.K.ebL.ZbL#0#u.w#GbV.w.1bnbA.u#C#z.y#.aL#G", +"#YbVaTbL#ubaatbV#zbnbe.K#zbnbn#N#z.g.UbwbO.4.S.4#R.L.UbSay.k#Jbc#abebrazbK#bbnbC#GbC#ub4#X.u.Z#HaY.eaI#Wbr.w.1#H#HbV.8b4anbS#s#H#b#GbVbe.6bw.4.ya5.y.ebS.e.e#t#t#G#u#zbVbV.w#s.w.e.u#CbKbS#.br#P", +".wbVaT.Tayba.t#u#zbnaza5ar#D.1#T#zbTaO#.bwbL.8#t#tas.Y#Gbl.K.k.1beanazbrbK.w.1.1.1bc#0be#j.C.4b4.ybO.g#Wana0aya7az.w#2az#B#z.w#HaY.wbVaNa3.s.4bA.e.8#F.8#z.ebLbD#0#u.w#GbV#b.1#s#z.s#AbAbV#jag#G", +"#0#D.ZbLbS#.as#u#z#Dbe.e.4.R#s.J#G.4a9.p#.bR.SaZaP.f#Z.w#u.K.R.1bebqbrbe#D#bbeb4#PbC#z#aaO.CbL.1bV.T.Ibr#8a0.w#Han#Y#2anan#z#0bC#s#H#DaraC.s.4.lbAbA.lblbS.e.K#i#ubV.w#s#GbQbV.wa5.CaD.ybV#.#a#G", +".1#u.ObLbS#..2a8#z##azar#T.RbQa6#u.4#.aQbNbR.S#T.UaQ#C#bblbK.kbCaV#l#fbebV#bbr.z#G.0bSaYaa.sbO#D.S.Q.U#Laz#n.w.1b4#B#2anbebS#zbC.KaV#Dbpb3bYbX.l.8bAbvblbS.e.k.g#u#G.w#GbVbVbS#s.e.C#CbKbV#X#a#G", +"#GbV.gbL#u#..2#ua5#u#Y.e.J.R#sbkbbbA.Oa.adbR.T#2#Z.f#3#bbl.KaYa0bn#L.Vbe.wbeanaz#P.0bS#aaabw.e.0aBaNaP#W#8a0#G.0#8aE#2an#HbS#0.1.S.1.1.A#U.S.Rar.4a5#FbSblbAbQ.ZblbV.w#0#DbV.ybV.8.CbE#zbVbW#a.1", +"#zaybR#m#s.A#AbX#D.1#u.wbvbV#z.M.8bA.4#E#k#Z.OaZ.hafbA#zbAbA#D#Hbnanbr#8aVb4#W#f.wbebVak#M.ObL.R.Ya2.Gbe.1aza7a7#Y.1#F#B.y.k#Db4.y#saY.P.ybX.K.4.8bS#zbS#u.8bA.SbDby#G.1#s.4.KbAbV.SatbVbl#Z#D#G", +"#Ga8bR#g#s.A#Aau#D#0bV.w#F#Ga5.M.ybA.8#v.p.L#ZaTb6afbAbVbA.KbV#8#s.m#fbr#H#H.m#f.1#bbV.k#p.ObR.y.Oa2aZ#n#baz#H#H.w#0#uaL#O.k#D#b#F.w#b#2#zbK.KaB.ybS#GbS#DbSbVbAbT.wbV#G#s.4#zbS.KbAat#z#u#obV#G", +"#zblbwae#z#v#A.y#Gbn#u.w.y#z#z.l.ybSbA.Zba#k.LbNas.UbK#0.8bKbVb4bnaL.mbrbe.canbr#H#bbA#4af.O.S.y.OaI#tbea0#b#H#b.y.w#G#b#x.KbV.w.y#s.w#F#s#zbVaBbS#ubS#GbSbSbK#z.4bQ.r.1bn.y#sbSbV.SaR#0#u.Obn.1", +"#G.8bw.C.w.AbH.ybV.w#za0bS#0.wbS.ybAbS.8#.afaQaQ.L.UbVbVbS.K#sb4#Dbranbrbebe.m#f.1a0bAbL.Y.O.T#F#.aT.4.w#b#H.w.w.8bS.w#Y#x.SbV.1bS#0#z.y#0#z.y.8#zbS#ubV#GbS#ubA#4.w.0.1#bbKbVbV.y.4b1bS#u.O#G.1", +"#bay#taX#sbk.H.y.w#G#u#bbVbV#z#z#RbAbS.ebRafaQ#d#kaP#s.wbA#zbn#H#sbeb4bebebeanb4.1#HbV#tba.YbL.y#X.U.S.wbc.1#GbV#zay#0by.y.SbV#PbS#zbS#u#z.wbl.y#GbS#u#G#GbV.ybK#z#b.0.1.wbnbV#DbA.Sb1#0bS#3#0.1", +"#bbSbB.C#sbk#CbsbV#z.yby#u#ubS#G.O.4#ubS.4bNaQaQ.pbD#G.wa5#s#s#H#abebe.zaY#bbr#8#D.1#z.Gba.U.TaB.Ob#bK.wbe#G#G#s.w#u#G#bbKbAbV#G.RbV#F#s.w.w#F#F.w#0#G#0#0aybSbSbQ.w#G#G.wbVbA#GbKbAab#0ay.n.1.w", +"#b#u.sae.1bk.H#D#z#D.8.wbS#u.y#z#Z.Z.lbSbA#.b5.fba.Z#s#GbS#z#sbe#bbrbebrbnbnan.V#D.1#z.G.nba#4bvbB.6#s.1az.0#G.w#Gay#P#GbKbK#b#G#z.waB.w.w.w#F#u#0.w.w#G#G#0bVbS.ebV#G#G.1#z.8bS#z.8b1#0bS.n#0#G", +"#s#u.Zaebn.A#Cbs#0#0#F#bbV.y#u.w.taPbvaya5.Zafas#Z#t#0#G#F.K#bbr.wbeanbrbnbK.man.1.w#s#i#S.ObuaBaI.EbQa7a0.0#G#0#D#Gaz#u.Rbnan.0bebQaB#s#sa0#F.wbS#G#G#G#G#G#zbA.ebl#G.0bV#z#F#0bK.8.tayay.H#D.r", +".1#zbT.ZbQ.yaMbK.K#0.w#0aY.SbV#ubMa3.K#Farbg#.aSbD.4#D#G#D.5#Y#b.qaV.V.m#z.e.m#fby#D#J#1.H.uaK.ZbRbIbe.1a0.w#D#D#Gbdb4b0.J.wa7ak#H#n#xb4#H#z#zbnay#G#u#G.1.1#G#u#s#Tbd#0b2#GbA.1.8#r#Ia5#sala5#D", +"#GbVbT.4bQ.8bI.Sa5bV.w#0#saB.kbVbM.6.Kbla5.J.Z#Q.sbK#G#G.1aB#Y#b#bb4.Vbr#F#z#B#8#0bdbK#j#.aP.S.g.TaZ#B#H.w#P.w#D#0.Fb4aNbv.1#DbV#Ha0.Mb4#H#za5#D#0#G#G.0.1.1.w#D#s#Ta7#0b2#D.8#H.y#r.fbA#zal#z.1", +"#GbV.Z#tbQ.S#xbLbK.w.wbV#sbYbV#G#5#6.SbA#zbv#taT.Z#z.w.1#zbX#Ybn.qb4.mb4aB#zbe#8#0bd.R#j#.bt#R.g#1aZbe.1#G.wbV#D#PbCbe.ear#D.1bX.1by.l.1.1a5a5#Dbm#G#G.1.1a0.w#G#s.la7.wa5#Dar#HbVbF#I.4a5ala5.1", +"#G#z#tbLbQbA.G#RbA.w.w#u.KaBbVbV.e#E#x.ybV.8.4.sbTa5.w#Gbn.4#Y.y#YaV.m#H#F#sbean#Gbn#s.gaDaT#R.g#t.4#b.0#G#G#G#D#0bCb4#x.e#G.1aB#G#0.8.1.1bS.B#G#G#G#G.1.1.1#G#u#z.e#H.w#z#D.8#H#z#haS.4#zal.4.1", +".1bV.4bLbQ.eaZaIau.w#0#Fa5#tbV.1bA#x#E.SbV#u#F.4bG#z#0#zbVbYakbX#YbnaL#b.ybV.1an#P#H#saqaq.u#4#j#1.S.1#u.1#0.1#G#0#Hbn#ibjbV#b#2bca5a5.1.0.l#z.0#G.1.1bcbc#b#D#u.war#8by#z#u.e#b.y.Tbz.4#za4.J#D", +"bc#z.4bZ.Q.S.9aI.R#b.w#F.K.4bV#G.R.4b#.T#u#D.y.8.8#GbcbVbK#R.qbKbebn.1#s#Dbs#Dbe.w#8aY#jaq.s.SaO.Z.S#D#7bm#G.w#u#0.zbn#xa5#G.1#2#bbSby.1#G.l#0.0.0bca0az#Ha0#G#u#0.B#8.w.K#D#r.1#FbO.x#T#zaX.J#D", +"#GbK.4bR.K.SbD.C.Sbe#0bG#zbAbV#D#DbL.v.T.y.0blarbS#G#G#D.KaH#Y#s#H.wbAbV#D#D#D#G.w.zaV#.aq.sbwax.gbA#D#7#G#u#G#u#uan##aW#NbV#D.4#bbvap#H#H.8#sa7.1.1bc#Ha0#H#0#D#0a5#8bQ#z.y.ebn.y.T.##x.KaXbkbV", +"#G#ua6#t.T.4.G#3.R#b#zbv.K.ebn.r#DbL..aI.4#7blar#G#Gay#u.KbY.N.cbnbe.ybVbn#G#b#u#b.zaYbW.H#R#tbx.Z.k.w.r#0ay.1#GaJaz.5bO#T.w#DbAbnbg#b#Hb4bVby.F.0bC.1.1.1#b#GbVaU.8#HbnbA.R#N.1#s#h.#bgbAa4#vbV", +"#G#u#tbO#t.K.9bw.lb4#G.8bla5aWa7ay.4.YaD.K#ublblay#G.1.y.K.Z#Y.iaY#T.R#Nbe#zbC.1#H#Bb..ZaPb.#3aFaPak#G.0.1#D#D#G#D#b#xbAbv#G#ubA.w.Mbn#nbVbS.1bdbcbm#P#G#Gbc.1#G#D.w#u.w.w#2bK#4bK.K#vbw.Q#tbt.K", +"#D#u.ZbR.4.ebD#tbAb4#u.8#u#z.lbn.rbAbabN#tbS#u#u.B#G#D#D.e.4#Ya7#b.4bnaW#H#zbC#GbcaL#4aTbW#4aTaS.UbQ#D#u#z#D#D#G#u#baBa5bS#G#u.K#b#F.1bebVbV#GbC#H.1#P.1.1#H#GbVbS#G#u.w#saBbA.SbAbF.gaqb..u.G.K", +"ay.y#t#t.Z.e.G#Ra5#Hblay#Db2.laVaybK#.#p.g.ybVbV#G.w#7#z.4.e#abeaY.ybn#T.1#zbC#D#G#b.S#t#x#5.Z.Y.U.kbSbl#GbA#u#G#u#b.4.e#z#G#FbAby.ybeaz#ubS.1bc.z.1#P.w.1bc#DaybV#G#F#G.w#2.S#t.R.e.g.OaI.9#x.K", +"#G.8#tbR#2.ebT#R.ebC#F#z#GbS.4#HaybA.Zajbi#tbVbV#0#G#F#saB#s.Rbe#bbAbn#Tbna5#GbCay.wbLbR.ZbL.Z.O#E.Kbl#ubVbKbSbVbl.w.4.8#0#ua#bVbQ#ube#b#u#G.1.1bf.0.w#Pa0#H.1#GbV#G#u.w#s.M.S#tbn.e#1.gbZ#R.9.K", +"#G.y#t.4#T.e#2.S#ra7#u#0#DbS#N#HbVbS#T.U#p.sbK#u#G#G.y#s.y#s.y#zaVbKbn.J.1a5bC.1#G#s.4bO.4bLbD.sbWbF.8ay#z#zbA#u#D#z.4.4#0#u.o#s.4bSbe#H#u#G.1.1.z#D#G.w#ba0.1#0#D.w#D.wbV#x.S.S#s.SbR.ObZ#5bYbO", +"#GbA#t.4.4#z#2.S#N#D#u#0.rbVarbn#GbS.4#vb5.O.Sbl#DbVa5.K#Dbn.ybVbn.Kbn.J#D#z#G.1.rbV.ZbR.Z#T#i.s.g.ebl#G#0.K#u.8#0bA.e#2.1#u.y#b#xbAbebn#D#Gbm.0beblbV.w.1bc.1#G#D.1#Ga0#s.M.S.Tbn.S.T#jbBbu.4.Z", +"#G.ya6.4.4#zaB.SaAbd#u#0bdbVarbn.w#u#F.g.pba#t#F.0#u#s.8bnb4.y.8aVbQ#Hbkbna5.1.w.1#z#tbL.4.Z.E#t.gbA#uay#sbS.K.y.w#2#z.4#0bl#D#Ybg#zbebC.0.w#G.1.1bvar#z#u.1.1#G#D.1bV#b#z#2bLbL#b.S#5#..g.k#t.Z", +"#GbAbD#t.4#0aB.yaA.y#F#0.r.w.8#DbybSbv#t#kas.s.X#D.y.Waibe#HbVa5aVbQb4bkbna5#G.1.w#s#tb.bR.4#ia2.g.y#F#u#GbKbV#ub2#c.K.4bV#7#DaYa6.kaza7#D#P.1bc#z#Tar.8#F.0.1.r#G.1#u#P#s#2bL.S#b.S#haP.U#5bY#T", +".w.4aI.sbAbSbK#ta6bsbd#za5.0bC.l.1#0bla6.Z#3aIbT#sbUaVara7.q#ebn#b#D#YaA#8#s#u.wbv.K.L#u#R.4#Z#F#T.e.8#z.e.l#sbs.w.P.e.w#G.r.r.1#T.wa7.z.1bea0.F.K#D.RbK.e#zbV#D.w.1#G#u.w#zaB.K#Y#ubOaC.gbobwaP", +"#GbYbZaPbA#u.y.g.Z.R#u#0#0.0bn.4#G#P#u#TaPba#t.G.ybQ.c.4#8#YbraYbn.R.wbp#ebn.8.1#F.K.L.rbL#t#Zbl#T.eaB#z#z.4#G#7.1#6.S.w#u#G.rbV.l.w.0be.1.wa0#8bV.R#J.K.4.8bV#G#G#G#G#G#b#saB.K.w.ybOaCaPb7.s.G", +"#G.4bB.U.SbVbAaPaW#D#Da5bSa7#H#2.w#PbSbA.ZaPbw#t.y#zbe.4br#sbq.c.w#D#s#Vao#z#u#G.l.KaS.rb..4afa5.4bS#Fa5#zbv#u#G#0#6bAbQ#u#G.w.8#z.wbd.z.1#b#H#HbS.y#HbQ#T#T#zbn#G#G.w#G.w.waB.K#s.8.T#v#.aIaPaT", +"bV.4.n#EbA#zbKaP#N#u.0ay.B#HaV.E#G.w#GbS#t.ZbZ.SbV#zbnbVbqai#WaL#b.1aYbp#e#zbS#G#F#z.L.rb..4afbS.lbS#F#u#z.8#u.1#0.M.8#z.o#0#baZa5.w#u.1#D#b#H.1bAbVaYbQ.8.J.y.w.w.w.1#0.w#s#2.SbVbA.K.gaPaIaP.Z", +".1#t#m.Y.SbVbK.g#N#u#7a5bVb4bn.6.w.w.0bS.S.saI#tbVbV#s#s#Y.daLaLbe.1bQbh#8#zbV#G.l.Kba.r.k#tbNay.l#u#F#ua5#F#u.1.w#2bAbS#F#z#Y.GbVa0#u#D#7az#b.y.ybe.1bVby.laB#b#P.1.w#G#GbVaB.S.y.e.K.g#..n.U.O", +"#z#t.naP.S.y.SaT.e#F#7aya5#HaV.6.w.1#G#G.ybD#tbk.4#JbQbn.Kbs#Bbebe#Hbnbp#8.ybSbSaJ.K.O.r#4.4#Z#u.8.8#ubS.8.lbVbn#z.e.ebSbbay#bbY#Ga0bS#D#Dbr#bbG#D#n.1#u#b.eaM#b.w#G#G#GbV#s.SbK.4.4#5aPaPbwb#.O", +".wbD#3.U.K.y.S.Z.e#7#7b2#ubnbebTbV.wbC.1#D.Z#tbT.ZbK#h.c.e#8#b#HaV.1bKbp#8.8#z#ubv#z.nbm#R.y.na8bS#FbV#zbG.ebn#D.4.KbKbV#7ay#baB#G.wbS.w#Hb4#s.4#Daz.1#D#nbV.M#H.w#G.w#G.w.wbK.e.lbA.KaPaPbwaf.O", +"#baZ#3#..KbS.S.O.ebs#D#0a8#7be.T#u.1bcbcbn.Z.S.TbLbY.TbrbUanbV#H#H#H.Rbp#8bA#zbSbl.K#mbm.4.ea2bl.ebG.wa5bg.S#s.y.G.k.KbVbm.0.w.Sbc.w.B#Bb4#H.y.e.1an#H.1a0bV.5aY.w.wa0.w.w#sbA.SbA.ebu.Z.O#m.Y.H", +".k#t#X.UbQ#4#tba.B#u#ubV.ya5a0.X.T#H#P#Ga7.y.n.u.sb..K#s#Hbe.i.k#D#YbT.e#0bl.waibA#RbQ#z#RbK.3.y#F#r.y#DaA#u.z#x#v#K#z.w#F#Y.g.R.w#HbCazbCbea#bnbean#H#0a0#G.y.1#G#PbV#b.X.1bV#t.y.KbL#R.9#5.s.9", +"bnbR#.bW.K.S.ZbabS#u#D#Gbl#z.w.XbO.1bcaUbC#J#1aH.s#R.k#ubean.RbK.1#s.G#z#0#F#saB.8.C#za5aHbAay.y.8#rbS#ubvbAb4bXbhaBbV#z#7.wbkaV#b.w#D.zbcbe.X#sbean#b#G#b#G.ybVbm.w#Daz#D.wbV.4.y#z.4#RaPaI.saP", +"bK.4aqbi.KbY.ZaPa5#u#GbVa8#z.w#ubOa7#P#Pb4aY.T#O#R.ZbQ#2#YanbVbKbe#zaMbQ#0.o#D.S.l.j.Kbv.ubV.B.R#F#rbS#u#TbAb4bAbR.X.y#z#ua5bg#a#b#H.0#H.1be.y#sbebe.1#G.w#G.ybVbm#G#D#Ya0.wbV#t.ybQ.4#t.ga2.Z.Z", +"bn#t.HbW.K.S.4.Z.e.ybV#D#u.w.1#D.ZbC#P.w.z#abFaB#4#tb0.Man#YbnbKbebV#2.w.w.o#ubX.8#R#z.l.u.K.BbK.l.e#u.8.l.R#sbAbObs#ubS#DbS#Tbe.wbV#D.w.w.1.y#b#Haz.1#G.w.w#u.ybm.1bVaza0#b#s#tbA#s#t#t.s#5.saP", +"#s.4bHbN#5.ybA.ZarbA#G#u#0.w.1.1.Zbn#G#0az#Y#z#D#sbAaE#xazbe.1#s.wbV.4.w#G#ubVaBa5aubQa5.ubAay#J.8#F.8.8#FbKbObY#rbnbV.J#D#zarbnbV#D#G#P#b#ubVaYbe#bbc#G.w.wbV#uay.w.w.1#G.w.wbD#T.K.4#t.O#5aPaP", +"#D#t#.bNbL.ybK.ZbO.S.w#u#Ga0a7.1a6#H.w#Gb4bebQ.1.w.w#Y.ybe#H#b#b#G#zbV#s#G#G.1#2#zau#0a5.jbA.B.Kar.y.8.8#D.K.gbtar.1bVbGbnbS#z.1#D#u.w.w#b#Fbn#saz#b.1#G.w.w.w.y#u#P#b.0.1.1#YaP.M.K.Z.Z.ZaI#EaP", +"bV#t.Ha9bLaB#z.4a6.4#b#D#Ga0#ub4bD#H.wbSao#bby.z#HbebV#Daz#Hb4#b.w#ubV.1.r#G.w.4#zbY.ea5a1bA.8bKarbsa5.8a7.K#V.Z#N.1bVbG#b.8a5#8.1#G.w.w#n.5.waYazbc#P.1#P.w#P#F#G.waz#Dbc#Gbeb#bGbU#t.saPb7.gbZ", +"bVbL#m#..SaBbV.l#EbLbe#G#G#b#7be#i#H#PbS.1.w.waz.1#n.X#ban#8b4#Ha0.ybK.way.r.wbKbSbt#2a5aK.Ka8bKarbd#z#ra7#s#X#R.l#7bV.lbe.Ma5azbe.1.1.w#n.X#baVaz#H.1#P#0#P.w#F.w#0.w.0az#GbQb#.4bQbL.Z.Z#5bwbo", +".K.K.T.gbO.4#s#Fbiapbca0.0be.1.1a6by#G#G#bb4be.zaY.R.y.1az#b#s#b.za5.8#H#2.1#Dbv.K.6bQ.K#F.Kbn.SblbV.k.4bQ.4.MbX#4#Har#D#s.4###bby.1anbebe#Fbe#baz.w.w.1bV.w.wbvaz#D#G#G#G#s.K.UbO.y.e#O#C.D.U.i", +"#t#tbRbW#R#tbV#2#E#b.1a0#Daz#s#GbTbybc#G.1#bbr#f.q#D.y#baz#H#DbV.za5#F#b.Jbna7ar#4#6.K.4.SbV.y#FbS#z.KbYbybAaBbKbLbn.8#G#s.Z##.w.w.1azbe.1.ybe.waza0#b.1bV#b.w.o#b#D#G#G#G#zbA#EbO.R#r#OaDbB.U.k", +"#ibwaI.Z.T#t.K#2bD.W#Gbc#G#b#H#GbDby.way.1#ban.zbe.y.y#b#n.w.y#D#Har#u.1#2bnbd.ebOa6.K#x.4bA.4.ya5bV.KaZbQa5.y#s.Sa7arbV#s#x.5.wbV#bb4an#u#saY#sbe.1#bbe.1#n#b.M.wbV#G#GbSbV.e.9.4.y.K.5#AbB.U#J", +"aPaIa2.s#5#t.K#ObDbQ#G.1.w#b.1#GbD#z.w.rbVbebr.zbQ.y.y#b#nbV#ubVaV.l#z#G#2#D#DbF.4bL.Kbg.Ka5.4.8#0.ybK.G#z#zaB.k.4#Da8.1bnbk.b#bbV.wbebr.y#Y#s#JbV#sazaz.1#b.1#2.w.w#G#G#GbV.K.S.S.y.KaHam#3aO.k", +".Z#5.Dbwb.#t.K.Sa6#z.1bcbe#b.w.0#i#z.w#Daybeazb4#s.8bV#n.w#GbV.w#H#T.w#D.l#Dbs.T#T#z#z#x#z#z.4.8bSaB.K.G.e#zaB.R.4#Dar.w.wa6.R#b#z.1bebeaB.NbA.S.SbVbebe#G.1.1#2#G.w#0bVbVbVbV.ebLaB.e#KambwbW#J", +"bWaIaIaP#5.S#s.e#t#s.w#G#Bbn#H#GaP.8.w#GbVbe#b.z#s#D.wa0.1#G.1beaY.Jby#7a5bV.5#1aBak#sbgbQ#z.8bA.BaBbQaZ#z#z#2.S.4#Da8.1#z#Ta7a0#s.1bebnbXaNbRaZ.4.S.w.1#G.1.w#2a5#0.Bbl#ubS.ybVbO#O.ebYambwbWbK", +".gbL.T.G.K.S.KbA.4#z#P#D#Y#Da0bc.s.4#P.w#Gbe.1a0#sbn#ba0.1.0#b.wbn#vby#7#z#z.5#jaB#b#z.M#z#z.8#FbS#2aYaZ.e#zaZ.R.4#Da5#GbVbO.1by.w#Dbr.R.S.QbZbD#1.S#z#G#u.w.waBbl#0bS.8bVbVblbSaq#x.T.Sam.CbWbn", +".ZbF#4.9.k.SbV.8.4#z.w#ube.y#bbc#t.4.w#P.w#b.w.zbn#D.1a0.1.1#H.1aVawby#F.w.w#O.g#Fak#DaMbV.ybA.l#u#2akaZbA#z#2bAbL.0ar#GbVbObn.w#Y#D#BbX.k.Qa2.sbM#tbA#u#G#nbybG#u#0a5bl#0bV.y#G#.bT#r#4#X.OaPbn", +".saIbwaPb..e.K.S.e.8#b#D#P.1#G.1.KaMb0#Da0bman#Jar#Y#8a0.w.w.1bC.ea7#GbS#b#T.Qahb4#D.y#2bS#zbl.ybV#Mbu#tbl#w.yblay#0.R#Hbk#D#H.1#bbV.V.4b4.TaubRbZ#t#t#z.1.1#b.9ar.w#ubv#zbdbs.K.O#t.KbD#3#ob##b", +".saIbR#E#5.4.y#2bA.4.way.w#G.w.1#s#x.q.y.w.0#nbn.l.w.1.1.wbV.1bCbL#H#G.8.1#x.Q#O#b#D#F.8bS#z.y.y#uav.K.Sbl#m.y#F#D#zbV#8bp.RaV#Hbeak.cbQ.c.T.S#tbR.s#tbK#G.1.w#OaW#b#ua8#0#ubs.K.Y.4#z.G#Zabb##s", +".gbwbw.UbL.4.SaB.S.8by#D.w#G.w.w.waZbQ.8#G#ube#J.l.waz.0.1#u#bbna6b4#z.l#u.M.K##az#D#FbVbSbS.y.8#uaS.SbLay#3.R.o#ubV#z#8bpbn#HazaYaL#Db0b4bu.R.S.Z.Z.Z.K#G.1#baB#i#b#D.8#0bdbs#rafbL.K#x.Oab.EbV", +"aPbDbw#EbZ.SbA.ybA#2#s#G.w#G.w.1by#2.K.4#z#G.wbK#ubnaz.X#P#Fbe#Da6bebV.l#GbG#Nbn#b.y#F#s.y.8bK.8bl#Z.4bF.0ba.K.oaybVbV#8bp#s#Hbe#JaL#OaLaY.w#s#z.Z.s.Z.4#u#G.w.y#iaV.1.Ba5.r#D.l#pbL#zaZaP.n#tbV", +"aP.UbZ#EbZ.K.K#z.e#2.wbV.1#G.1.wa0.8#r.4#0.w#z.y.1.waz#7a0#7#Y#2a6#b#u.8bnbl.Jbn#P#u#F.wbSaBbS.4#u.O.4b.ay.pbQ#F.1#ubAaobh#bbnbe#saLai#BbA#s#z#u.Zbw.ZbObS#G#b#D#iaV.1#z#0#D#u#y#pbL#saZaPaI.K#G", +".Z#Eb.aPbR.KbKbK.KbG.w#G#0#u.w.1#P.y.S.e#z.w.ybA#H.wa0#u#b#D#bbgbO.1#Fa5bna5bg#D#z#u#F#s#D#2.e.4bl.O.4#5.r.p.Kbv#H#F.ya7bhbe#D.1#Ybq.SaY#Tbn.ybs#taI.g.Z.8#D.w.1a6bnbn.B#0#D#D#T.I.4bV#2aP.C.K#G", +"bw.UboaP.ZbL.ybS.K.M#s.w#G#G#G#D.1#G.S.e.K#0#FbKbCaza0.1.1.1#s#ia5.0#F#s#Da5aw#bbl#0.obVbV.M.e.4bl.O.SbOaJ.LbQ.ya0#F#D#8bhbe#D#sbe#B#sa7.4.1.e#F#taI#.#j.l#u.1.1.4.1.0a5b2#D#u.Z.UbLbS.SaP#t#z.r", +".Zbib..U.g.S.S.y#zbT.w#s#G#u#G#GbmbV.S.e.ybVaB#s.Fa0.wa0.0b4#z#ib2.0.oby#D.eaxaY.o#0aB#ubV#2.8.4blaP.e.Z.o.Lbubl.wbl#s#8bhbe.y#b.1.V.W.b#rbe#z.RbYaI#.#v#Tbl.1.1.e#G#7#0#0#D.R.Z.U.S#zbV.s#R#s.r", +"a6#E#4.YaP#h.4#ubL.4#z.w#G.1.0#D#G#G#G#u.8bG.8#zbC.1a0#zbV#b#z.J.w#GbbbVbAaB#O.1#F.w.8bSay.o#FaP#5a6.4#tbR.Z#zbV.1bdbS#DaAbVbQ#e#BaBaEbA.4#sbs#Dbl#tb1#A.Zbl#u.wbV.y#zay.0.1.y#2aT.4bVbVaZ.9#say", +".ZbDb.#3#.bF.y#D.T.S#z.w.1.1#G.0#0bc.1.1bVbA.y#b.1.1.w#D#Gbe#z.l#b#u#u#GbA.S.y#D#D#s.y#zay#F.KbtbZ#i.8.Z.saZbA#u.wbCa5#DaA.RbQbn#B.X#Y.4.KbV#u#D.o#tba#k.g#2#u#sbn.y#0#G.rbC#DaB.Z.S#u#sbY#t#s.r", +".ZbDbubBaP.TbA.1.KbA.K.w#P#b.1.0#0.wb4#P.wbVbnazbC#H#0#u.1be#DbA.wblay#0.4.S#z#D#0bV.8.1ay#u#saP.g#i.4.Z#tbDbK#7.1bCa5bnaW.R#zbn#BaB#Y#x.KbVbn.0#u.4#.a9#i.4#u.1bQ#FbS#G.0.1#D.S.O.4#u.w#tbYbQ.0", +".8.ZaKaIbNbRbK.wbL.SbA.w.w.1#0#D.B.1#P.1.1bV#H.z.1#b#G#F.1be#7#s#zbv#0.w.4bT#sbS#G#u.y#zblbl#saPaP.Z.e#tbR#t#s#G.w.1bV.1aW.y.Kbnbr.y#YaM#s.y.1#GbSbA.Z.YbW.4bV.w#b#FbS#z.0.1bV.y.O#TbVbV#t#t#s#G", +"#rbT#RbwbN.g.K.1#t.4.4.w.way.w#GbS#G#Hbc.1.1ao.z.1#PbV#uazazbs#bbU#c#0#0.8.6#z#u#G#F#u#Gbb#F.k#E#.bRbF.Z#t#R#b.1#GbC#zbn#N.R.eaV#sbKaYaZ#s.y.1#G#G.l.ZbW.U.gbA#G.w#2bS#G#u.1bVbSaq.Zbl#z#tbY#s.0", +"#z#x.s.CbNaP.Kbn#T.S#F#z#0bl#0bVay.w.1.1.1.1bc.z.1.w#z#u#bb4#u#b#s#c.w#zbA.a#z#D#G#FbV#Gbl#u.K.YbaaI.K#i.s.Sbe.z#s#GbSbC#r#D.KaV.RbQ.k.y#s.y.1#Gaybl.l.ZbN.ZbK#G.w.oa5#z#u.1#s#u.Oa6#FbSbY.Zbn#G", +"#rbT.9b..ObW.KbVbL.K#T.w#0#F#0ayb2.1bc.1bc.wbcao.1#G#zbV.w.1.ybQ#s#2.w#F#z#2#b#7aUbl#0.1#u#GbLaPbN.Hb.aC.saK#Y.z#0.1bV.1#r#D.eaYbAaLaBbK#Dbn#G#G#0#ubSbLa9#Z#z#G#Gbv#z#z#F#D#0.8.H.Z.8bA#tbY#s.1", +"a5#x#t#w.HaP.Kbn.K.K#2.w.wa8.wbS#0.w.1.1.1#Pbcbc.1bV#0bV#sbV.lbQ#z#u.wa##zbK#B#7#0#u#D#G#G.wbObN.p.n#h.E#taKbe.z.w.1bSbCbFbV.ebn.KaL#x.k.y#b#D.0#ubl#u.4#pbN.S.rbV#F#z#z.o.1.w#F.H.J.la5bY.s#sbc", +"#Dab#3.ybw#Z.K#zbnararaB#bbGbS#G.1bc.1.0bc.1.1.0ay.w#F#n#sbeai#JbA#D#b.4.e.1.z.o.B.w#u.1#DbQbLaPb#.Z.g.ZbDaka0.w#GbV#G#bbsbea7bnbK.q#4bA#G#G.0#Dar.3.y.R.U#9.Tbd#uay#r#z.MbVbe#Kb1bD#2.e#t#tbn.r", +".raR.ObSbw#Z.KbK.1ar.ebsaY#T.e.1#GbCbc#Hbc#H.1.1bV#0#F#nbVbe.5bV.lbd#b#N.8bnaz#u#u#0.r.1#ubK#t.Z#EaIbR#1aZapbe.1.1#u#D.w.ybebnb4bn.q.S.4ay#G#D.Rbla5#u.RaP#9.Tbd.r#z.ebU.M#Gbeaub1.g.4.K#t#t#s.0", +".raR.Oa5bwba.e.y.1ar.e.y#s.8bS.1#u#Ga0a0#Ha0.1#GbVbV#F#bbV.w#FbVbv#D#sbO#T.1az#0#u#G#G.1#ubK.Z.s#EaI#t.ga6#Y#b#G.1#DbV#DbK#BaVbeaVaY.S.4bV#G#D.y.la5#u.i.9aabOa7.r#G.e#z.M#0#b.y#Z.Z.8bQbL#t.w.0", +".r#o.ObVbwaS.K.S.1.ebA#D.w.e.e#D#G#G.1#Ha0bc.1.0.w#u#F#P#u#z#ubS#T.1bnar.Jbn.1.w#u#G.0.1#Dbn.9bw#E.Taq.gbT#bbn#uan#G#b#Dbnbqa7be.w#a.4#F.w#G.RaBaB.ebSbn.S#X.Zbd#GbV.4#z#F#0#b.S#Z.gbAbQbZ#R#sbc", +"#GabbwbS#3.p#4bK.wa5.e#Dbnby.lbnbV.1#Pbc.1.1#G#G#s#u#FbybV#u#0#G#T.w#D#r#x.1#Gby#G.1#G.1.1bQ.Gbw.Z#5.Za6.Zak.w#D#B#H#b.y#baLbn#a#b#baB.8.w#0bAbD#t.4bS#D.y.g#vbn#GbV.4#z#u#GbQ.y.L.ZbAbU.S.s.w.0", +"bcat.sbV.O#k.K#4#H.ebAbC.0.W.4#Day#G.w.1.0#D#G#u.w#u#u#bbV#F.w#u.l#H.X#r.lbebCa0#G#G#G.1.1#Y.G.C.gaIbW#i.g#s#D.0azbe.1.5#YbeaYbe.w.wbX.y.wbn.4bD.ubh#N#ubV.Zbgbn#G#z#2bQbV.w.w.y#Z.g.l#sbRbY#s.0", +"bm.Obw#z.Ob5#4.SbebSbA.1#Db0.Jbn.8#G.w.1#Gay#G#G#s#u#u#Y.1aBbe.R.ybe.5#z.Kan.0a0#0.1#Gbc#baLbI.C.gbR#EbWbT#z.y#Gb4anbnbsaLbn#a#a#H#b.ybA.w#zbOaPaT#V.l#FbVbOa3#s#0.e#2by#G.1bn.Rat.Z.4#z#t.s#s.0", +"bm#Z.s.w.Ob5bL#tb4.ebSbC#7bPbGbV.8ay.w.w#G#D#0#G#0#ubV#n#saibe.R#0an.b#z#z#lbd#0.1#Gbc.1#H#Y.EbZaIb..gbR.Sak#G#nb4.m#b.ybq.RaLbea0#b.y.y.wbS.4.g.O#XaA#F#DaraxbQa5.ebTbQ.1a0#G.y#3.Zbv.K#t#tbn.r", +"#G.sbw#z#2bNa2bSbV.8bQbVay#G.y.SblbS#Gay#G#0#G#ubybvbe#b#z.4.q.S#8#b#za8#Daz#7.w.w.r.1.1#H#s.GbBaBb.aP.CbAbn.1b4ananan###Bbn.mbnb4#b.ybv#GbnaP#ZadbN#jbSay.MbD.n.1#z.4#z#bbCbV#zbwaPa6#5bZbD.y.1", +".1#tbw#z.4a9#5bV#z.8.w#G.r#G#ubAbSbS#z#0#G.1#0bS#z.o#bbn.y#2akaB.1.w#0.y#0az#Dbn.w#G#G.1#baY.9.C#2bL.Y.s.S#DbC#Hazbeana7brbn#Wbnan#b.K#u.w#bbDb1#k#k.g.Saybv#xbw.w#z.4bK#P#G#G#z.s.g.g.KbR.ZbV.1", +".w.Sbw#z.8#..D#u#z.y#s#0bmbm#D.Ka5bS#G.w#GbS#G#0a5#F.1#DaB.4bQ#2#D.w#zbS.wbe#u#0.wbV#G.1#b.KaP.Z.ZaIbN#..S#u.1.1b4anbe#Hbebebrbnbe.w#z#u.wbn#E.LaG#ka9.4#zblaZ.sbV#z.4#z.w.0#D#s.H#i#x#5bZ.Z#s.1", +".wbLbw.K.8.O#5.8#GbS.w.1.r#G.wbVbS.8bV#0#G#ubVbV#u.yaY#D#2.ebQ#2.1bVa5.8.w.1bSbS.w#G#G#G#GbA.g#.bLbRba.O.K#D.1.1b4anb4brbebrbrbn#Hbn.KbS.w#Db#.fb6aG#kaq#za5.8.Z#zbV.S#s.way#GbnbBaP.g.TbR#t#s.1", +"bcaI#t.K.8.Oa2.8.w#z#z#0#Gbm.wbKa5blbVbV#G#u#ua5.y#D.wbVbGbQ#baB.wbSbA.4#b.RbVbA#0bV#G.wbVbY.Z.O.TbR#.aPbQ.ya0#b.z#Bb4anbe#B#Y.ibe#sbV#s#b.Rafb6#k#kadaP.e#zbA.4bS#s.R#s.wbS#D.1b7#i#x#4bR.9bV#G", +".w#4bw.e.8.OaI#u#z#z#z#G#G#G.w.4#za5bS#GbVbVbVbS.4bKbV.K.MbQaY#FazbVbAaB.q#F#GbS#G.1#Haz#saBbZ.H.e.gbabN.q#7#b.zan.manbebrbrbrbn.1#D#zbV.1.R.I.ha9.L#kbN.4#zbA.8ar#s.Rbn#0.B#GbnaI#E#i#5.s.Z#s#D", +"#GaKbR.e.yaqaI.8#z#sbK#0#G#G#saZa5bAbSbVbV#zbV#u.l#z.ybV#x.w#bbdazbV.K.Sbr.5.w#z.1bcbcaz#baBbZ.O.ebWbabi.qbs.zb4ananan.1#Bbe#Wbn.1.y.y#DbnaB#M.h.g.Oa9bibTbAbA.8.J#sbn.Raya5bVa7aI#E#i.KbR#t#s.0", +"#Gb.bBa5bA.Oa2#u.K.K.4#z#G#GbQbDbA.8bS.y#ubVbVaB#r.KbA#zbg#Y#b#Ha0bV#sbKaLa#be#0.1#H.1#B.1bY#taP.KaPaP.U#Y#7.z.zananan.ibqaV.mbn#b#DbV#z.1bXafac.ZaI#..I#i.lbA.8.J#s.i.ya5a5#DbdaIaC#ib.bR.4bQ#D", +"#Gb..ZbAbAbaaIbV#zbA.ybKbV#sbV#Far#z#Dblblar.8aB.y#zbR.KbG.w.1.z.wbV#T.can.Sbr#8b4.w#nb4#L#.bJ#R#z.g#3a9bq#F.z#H#f.mbe#sbe#D#L##bC#s.ybl#P#3.2.I#tbL.g#..paP.e.obTbQ#s#2.ybV.y#FbA.O.L.4.4bB#a.0", +"#Gb..ga5.eaPbB.ya5bl.8bS#0bn#s#u.Z#zbV#Fa8.8bA.y.8#4bR#1.8#G.1.1#PbVaAb4br.e.V#8an.waz#8#WbiaIbX.k#v.uajaL#Fbc.1#fbeanbnaLa7#La7#8#sbK.r.w.O.x.Y#t.e.gbWadbN#4bl#xbQ.K#2#ubVbV#D.lba.LbZaBbwak.0", +"#G.KaP.e#z.ObZ.y#za5bSbS#z.w#0bV.g.K#s#ua8.lbl.y#F.4.Z#i#z#G.0.w.w#DbOan.V.ebeanbr.w#bbCaLbi#..Sby.g.saObe#u#H.1#8be#B#Dbebr#L#8bc#sbKay.w.Y.LaT.4.K#taP#pbibA#u#2#s#zaB.ybV#sbV.4bababLaB.s.7.0", +"#Gbu.ga5#s.Obw.yby#0bSbS#0#zaybSbabZ.K#zbl.8bA#u.8.Saq.6#YbV#Ga0be.1bOanbrbU#8.zaza0.w#H#WaP#EbK#b.Z#R#XaV#0.z.1#b.1#B.R#Yan.m#8#H#JbK#G#0af.L.u.4.ebO.gbN.U#t#z.ybQbV.8.y.wbVbVaBba#Z.T.4.s.kbc", +"a0.7aP.e#z#Zbw#u#0#0#0#u#G#G#uaya9bR#4bVbSa5bS#F.K.T.Z.6b0ay#D#bbebV#T.m#8bU#D.1#8#0.1bebqaIbW#J#b#x#R#v#D#0bC#H#HbV#Bbs#B.mbe#ea0bK.K#G#0.I#Z#t#tbA.ebO#..Ua6bV#F.w#sbVbV#z#sbVbA.O#Z.ebYaT.7bc", +"#P.Q.ga5#sba.sbAbV.wbS#u#z#GbVbVbaaT.SbKa5a5bS#F.ebL#EbD#b#u#u#Y#H.1#Tbebd.W#7bd.1bS#0beaL.T#Ebn#Y.g.S#y#u#0aobe.w.1azbs#Bbrb4a7a0au.K#Pay.I.O.Z.4.y.ebLbR#..P#z.8bV#0bVbn.w#s#sbAbH#ZbL.4.9.kbc", +".1buaPa5#z.Y.O#ubV#sbVbV.1#z#D.wba.Z.4bA.8.e.KbA.4#t.UbL#s#zbbbe#b#b#ran.b.W#7.1#8#G#0#HbKb7.gaV#BbT.K#r#Dby#H.m.1.1be#u#B.1.wbe#P.S#z.wbSbi.n.ZbK.4.e.8aI.Z.6.K#u#GbV#0bV#s.w.w.e#Z#Z.K.4aT.k.1", +".rb..g.e#s.YaPbV#z.wbnbV.wbn#Dbn.OaP.4.y.4#N.K.K#T#t.U.Q#z.w#F#YazanaNan.bap#Ga0az#0#P#b#KbR.Z#aaz#ibK#h#u.wbC#B#b.1bebs#B#D#baLbcbA.k#P#G#E#S#2.K.8bAbL.Tbw.6.K#G#0.wbVbVbV#s#s.e.Oba.K.4aT.k.0" +}; + +static void drawroundrect( QPainter *p, QCOORD x, QCOORD y, + QCOORD w, QCOORD h, QCOORD d ); + +static inline int buttonthickness( int d ); + +static QRegion roundRectRegion( const QRect& g, int r ); + +static void get_combo_parameters( const QRect &r, + int &ew, int &awh, int &ax, + int &ay, int &sh, int &dh, + int &sy ); + +static int get_combo_extra_width( int h, int *return_awh = 0 ); + +enum { PointUp, PointDown, PointLeft, PointRight }; + + +NorwegianWoodStyle::NorwegianWoodStyle() : QWindowsStyle() +{ +} + +/*! + Reimplementation from QStyle + */ +void NorwegianWoodStyle::polish( QApplication *app) +{ + + oldPalette = app->palette(); + + // we simply create a nice QColorGroup with a couple of fancy wood + // pixmaps here and apply to it all widgets + + QImage img(button_xpm); + QImage orig = img; + orig.detach(); + QPixmap button; + button.convertFromImage(img); + + + int i; + for (i=0; iconvertFromImage(img); + + + img = bgimage; + img.detach(); + for (i=0; iconvertFromImage(img); + + + + QPalette op(QColor(212,140,95)); + // QPalette op(white); + QColorGroup active (op.active().foreground(), + QBrush(op.active().button(),button), + QBrush(op.active().light(), light), + QBrush(op.active().dark(), dark), + QBrush(op.active().mid(), mid), + op.active().text(), + Qt::white, + QColor(236,182,120), + QBrush(op.active().background(), background) + ); + QColorGroup disabled (op.disabled().foreground(), + QBrush(op.disabled().button(),button), + QBrush(op.disabled().light(), light), + op.disabled().dark(), + QBrush(op.disabled().mid(), mid), + op.disabled().text(), + Qt::white, + QColor(236,182,120), + QBrush(op.disabled().background(), background) + ); + + app->setPalette(QPalette(active, disabled, active), TRUE ); + +} + +void NorwegianWoodStyle::unPolish( QApplication *app) +{ + app->setPalette(oldPalette, TRUE); +} + +/*! + Reimplementation from QStyle + */ +void NorwegianWoodStyle::polish( QWidget* w) +{ + + // the polish function sets some widgets to transparent mode and + // some to translate background mode in order to get the full + // benefit from the nice pixmaps in the color group. + + if ( !w->isTopLevel() ) { + if ( w->inherits("QPushButton") + || w->inherits("QToolButton") + || w->inherits("QComboBox") ) { + w->setAutoMask( TRUE ); + return; + } + if ( w->backgroundPixmap() ) + w->setBackgroundOrigin( QWidget::WindowOrigin ); + } +} + +void NorwegianWoodStyle::unPolish( QWidget* w) +{ + // the polish function sets some widgets to transparent mode and + // some to translate background mode in order to get the full + // benefit from the nice pixmaps in the color group. + if ( !w->isTopLevel() ) { + if ( w->inherits("QPushButton") + || w->inherits("QToolButton") + || w->inherits("QComboBox") ) { + w->setAutoMask( FALSE ); + return; + } + if ( w->backgroundPixmap() ) + w->setBackgroundOrigin( QWidget::WidgetOrigin ); + } +} + +void NorwegianWoodStyle::drawPrimitive( PrimitiveElement pe, + QPainter *p, + const QRect &r, + const QColorGroup &cg, + SFlags flags, const QStyleOption& opt ) const +{ + int x, y, w, h; + r.rect( &x, &y, &w, &h ); + switch ( pe ) { + case PE_ButtonCommand: + { + int d = QMIN( w, h ) / 2; + int b = buttonthickness( d ); + + QRegion internR = roundRectRegion( QRect(x + b, y + b, + w - 2 * b, + h - 2 * b), d - b ); + QPen oldPen = p->pen(); + + QBrush brush( flags & Style_Sunken ? cg.brush(QColorGroup::Mid) : + cg.brush(QColorGroup::Button) ); + p->setClipRegion( internR ); + p->fillRect( r, brush ); + + int e = QMIN( w, h ) / 2; + QPoint p2( x + w - 1 - e, y + e ); + QPoint p3( x + e, y + h - 1 - e ); + + QPointArray a; + a.setPoints( 5, x,y, x+w-1, y, p2.x(), p2.y(), p3.x(), p3.y(), + x, y + h - 1 ); + p->setClipRegion( QRegion(a) - internR ); + + p->fillRect( r, (flags & Style_Sunken ? QBrush( cg.dark(), *sunkenDark) + : cg.brush(QColorGroup::Light)) ); + + // A little inversion is needed the buttons + // ( but not flat) + if ( flags & Style_Raised || flags & Style_Sunken ) { + a.setPoint( 0, x + w - 1, y + w - 1 ); + p->setClipRegion( QRegion( a ) - internR ); + + p->fillRect( r, (flags & Style_Sunken ? QBrush( cg.light(), *sunkenLight) : cg.brush( QColorGroup::Dark ) ) ); + } + p->setClipRegion( internR ); + p->setClipping( FALSE ); + p->setPen( cg.foreground() ); + drawroundrect( p, x, y, w, h, d ); + p->setPen( oldPen ); + break; + } + case PE_ScrollBarAddLine: + if ( flags & Style_Horizontal ) + drawSemicircleButton( p, r, PointRight, flags & Style_Down, cg ); + else + drawSemicircleButton( p, r, PointDown, flags & Style_Down, cg ); + break; + case PE_ScrollBarSubLine: + if ( flags & Style_Horizontal ) + drawSemicircleButton( p, r, PointLeft, flags & Style_Down, cg ); + else + drawSemicircleButton( p, r, PointUp, flags & Style_Down, cg ); + break; + default: + QWindowsStyle::drawPrimitive( pe, p, r, cg, flags, opt ); + break; + } +} + +void NorwegianWoodStyle::drawControl( ControlElement element, + QPainter *p, + const QWidget *widget, + const QRect &r, + const QColorGroup &cg, + SFlags how, const QStyleOption& opt ) const +{ + switch( element ) { + case CE_PushButton: + { + const QPushButton *btn; + btn = ( const QPushButton * )widget; + QColorGroup myCg( cg ); + SFlags flags = Style_Default; + if ( btn->isOn() ) + flags |= Style_On; + if ( btn->isDown() ) + flags |= Style_Down; + if ( btn->isOn() || btn->isDown() ) + flags |= Style_Sunken; + if ( btn->isDefault() ) + flags |= Style_Default; + if ( ! btn->isFlat() && !(flags & Style_Down) ) + flags |= Style_Raised; + + int x1, y1, x2, y2; + r.coords( &x1, &y1, &x2, &y2 ); + + p->setPen( cg.foreground() ); + p->setBrush( QBrush( cg.button(), NoBrush ) ); + + QBrush fill; + if ( btn->isDown() ) + fill = cg.brush( QColorGroup::Mid ); + else if ( btn->isOn() ) + fill = QBrush( cg.mid(), Dense4Pattern ); + else + fill = cg.brush( QColorGroup::Button ); + myCg.setBrush( QColorGroup::Mid, fill ); + + if ( btn->isDefault() ) { + x1 += 2; + y1 += 2; + x2 -= 2; + y2 -= 2; + } + + drawPrimitive( PE_ButtonCommand, p, + QRect( x1, y1, x2 - x1 + 1, y2 - y1 + 1), + myCg, flags, opt ); + + if ( btn->isDefault() ) { + QPen pen( Qt::black, 4 ); + pen.setCapStyle( Qt::RoundCap ); + pen.setJoinStyle( Qt::RoundJoin ); + p->setPen( pen ); + drawroundrect( p, x1 - 1, y1 - 1, x2 - x1 + 3, y2 - y1 + 3, 8 ); + } + + if ( btn->isMenuButton() ) { + int dx = ( y1 - y2 - 4 ) / 3; + + // reset the flags + flags = Style_Default; + if ( btn->isEnabled() ) + flags |= Style_Enabled; + drawPrimitive( PE_ArrowDown, p, + QRect( x2 - dx, dx, y1, y2 - y1), + myCg, flags, opt ); + } + + if ( p->brush().style() != NoBrush ) + p->setBrush( NoBrush ); + break; + } + case CE_PushButtonLabel: + { + const QPushButton *btn; + btn = (const QPushButton*)widget; + int x, y, w, h; + r.rect( &x, &y, &w, &h ); + + int x1, y1, x2, y2; + r.coords( &x1, &y1, &x2, &y2 ); + int dx = 0; + int dy = 0; + if ( btn->isMenuButton() ) + dx = ( y2 - y1 ) / 3; + if ( dx || dy ) + p->translate( dx, dy ); + + x += 2; + y += 2; + w -= 4; + h -= 4; + drawItem( p, QRect( x, y, w, h ), + AlignCenter | ShowPrefix, + cg, btn->isEnabled(), + btn->pixmap(), btn->text(), -1, + (btn->isDown() || btn->isOn()) ? &cg.brightText() + : &cg.buttonText() ); + if ( dx || dy ) + p->translate( -dx, -dy ); + break; + } + default: + QWindowsStyle::drawControl( element, p, widget, r, cg, how, opt ); + break; + } +} + +void NorwegianWoodStyle::drawControlMask( ControlElement element, + QPainter *p, + const QWidget *widget, + const QRect &r, + const QStyleOption& opt ) const +{ + switch( element ) { + case CE_PushButton: + { + int d = QMIN( r.width(), r.height() ) / 2; + p->setPen( color1 ); + p->setBrush( color1 ); + drawroundrect( p, r.x(), r.y(), r.width(), r.height(), d ); + break; + } + default: + QWindowsStyle::drawControlMask( element, p, widget, r, opt ); + break; + } +} + +void NorwegianWoodStyle::drawComplexControl( ComplexControl cc, + QPainter *p, + const QWidget *widget, + const QRect &r, + const QColorGroup &cg, + SFlags how, + SCFlags sub, + SCFlags subActive, + const QStyleOption& opt ) const +{ + switch( cc ) { + case CC_ComboBox: + { + const QComboBox *cmb; + cmb = (const QComboBox*)widget; + + int awh, ax, ay, sh, sy, dh, ew; + get_combo_parameters( subRect(SR_PushButtonContents, widget), + ew, awh, ax, ay, sh, dh, sy ); + drawPrimitive( PE_ButtonCommand, p, r, cg, Style_Raised, opt ); + QStyle *mstyle = QStyleFactory::create( "Motif" ); + if ( mstyle ) + mstyle->drawPrimitive( PE_ArrowDown, p, + QRect(ax, ay, awh, awh), cg, how, opt ); + else + drawPrimitive( PE_ArrowDown, p, + QRect(ax, ay, awh, awh), cg, how, opt ); + + QPen oldPen = p->pen(); + p->setPen( cg.light() ); + p->drawLine( ax, sy, ax + awh - 1, sy ); + p->drawLine( ax, sy, ax, sy + sh - 1 ); + p->setPen( cg.dark() ); + p->drawLine( ax + 1, sy + sh - 1, ax + awh - 1, sy + sh - 1 ); + p->drawLine( ax + awh - 1, sy + 1, ax + awh - 1, sy + sh - 1 ); + p->setPen( oldPen ); + + if ( cmb->editable() ) { + QRect r( querySubControlMetrics(CC_ComboBox, widget, + SC_ComboBoxEditField, opt) ); + qDrawShadePanel( p, r, cg, TRUE, 1, + &cg.brush(QColorGroup::Button) ); + } + + break; + } + default: + QWindowsStyle::drawComplexControl( cc, p, widget, r, cg, how, + sub, subActive, opt ); + break; + } +} + +void NorwegianWoodStyle::drawComplexControlMask( ComplexControl control, + QPainter *p, + const QWidget *widget, + const QRect &r, + const QStyleOption& opt ) const +{ + switch ( control ) { + case CC_ComboBox: + { + int d = QMIN( r.width(), r.height() ) / 2; + p->setPen( color1 ); + p->setBrush( color1 ); + drawroundrect( p, r.x(), r.y(), r.width(), r.height(), d ); + break; + } + default: + QWindowsStyle::drawComplexControlMask( control, p, widget, r, opt ); + break; + } +} + +QRect NorwegianWoodStyle::querySubControlMetrics( ComplexControl control, + const QWidget *widget, + SubControl sc, + const QStyleOption& opt ) const +{ + QRect rect; + switch ( control ) { + case CC_ComboBox: + { + switch( sc ) { + case SC_ComboBoxEditField: + { + rect = subRect( SR_PushButtonContents, widget ); + int ew = get_combo_extra_width( rect.height(), 0 ); + rect.setRect( rect.x() + 1, rect.y() + 1, + rect.width() - 2 - ew, rect.height() - 2 ); + break; + } + default: + rect = QWindowsStyle::querySubControlMetrics( control, widget, + sc, opt ); + break; + } + break; + } + case CC_ScrollBar: + { + const QScrollBar* sb; + sb = (const QScrollBar*)widget; + bool horz = sb->orientation() == QScrollBar::Horizontal; + int b = 2; + int w = horz ? sb->height() : sb->width(); + + switch ( sc ) { + case SC_ScrollBarAddLine: + rect.setRect( b, b, w - 2 * b, w - 2 * b ); + if ( horz ) + rect.moveBy( sb->width() - w, 0 ); + else + rect.moveBy( 0, sb->height() - w ); + break; + case SC_ScrollBarSubLine: + rect.setRect( b, b, w - 2 * b, w - 2 * b ); + break; + default: + rect = QWindowsStyle::querySubControlMetrics( control, widget, + sc, opt ); + break; + } + break; + } + default: + rect = QWindowsStyle::querySubControlMetrics( control, widget, + sc, opt ); + break; + } + return rect; +} + +QRect NorwegianWoodStyle::subRect( SubRect sr, const QWidget * widget ) const +{ + QRect r; + switch ( sr ) { + case SR_PushButtonContents: + { + const QPushButton *btn; + btn = (const QPushButton*)widget; + r = btn->rect(); + int d = QMIN( r.width(), r.height() ) / 2; + int b = buttonthickness( d ); + + d -= b; + b++; + + if ( r.width() < r.height() ) + r.setRect( r.x() + b, r.y() + d, + r.width() - 2 * b, r.height() - 2 * d ); + else + r.setRect( r.x() + d, r.y() + b, + r.width() - 2 * d, r.height() - 2 * b ); + break; + } + case SR_ComboBoxFocusRect: + { + r = subRect( SR_PushButtonContents, widget ); + int ew = get_combo_extra_width( r.height() ); + r.setRect( r.x() + 1, r.y() + 1, r.width() - 2 - ew, + r.height() - 2 ); + break; + } + default: + r = QWindowsStyle::subRect( sr, widget ); + break; + } + return r; +} + +static void drawroundrect( QPainter *p, QCOORD x, QCOORD y, + QCOORD w, QCOORD h, QCOORD d ) +{ + int rx = (200*d)/w; + int ry = (200*d)/h; + p->drawRoundRect( x, y, w, h, rx, ry ); +} + +static QRegion roundRectRegion( const QRect& g, int r ) +{ + QPointArray a; + a.setPoints( 8, g.x()+r, g.y(), g.right()-r, g.y(), + g.right(), g.y()+r, g.right(), g.bottom()-r, + g.right()-r, g.bottom(), g.x()+r, g.bottom(), + g.x(), g.bottom()-r, g.x(), g.y()+r ); + QRegion reg( a ); + int d = r*2-1; + reg += QRegion( g.x(),g.y(),r*2,r*2, QRegion::Ellipse ); + reg += QRegion( g.right()-d,g.y(),r*2,r*2, QRegion::Ellipse ); + reg += QRegion( g.x(),g.bottom()-d,r*2,r*2, QRegion::Ellipse ); + reg += QRegion( g.right()-d,g.bottom()-d,r*2,r*2, QRegion::Ellipse ); + return reg; +} + + + + +static int get_combo_extra_width( int h, int *return_awh ) +{ + int awh; + if ( h < 8 ) { + awh = 6; + } else if ( h < 14 ) { + awh = h - 2; + } else { + awh = h/2; + } + if ( return_awh ) + *return_awh = awh; + return awh*3/2; +} + + +static void get_combo_parameters( const QRect &r, + int &ew, int &awh, int &ax, + int &ay, int &sh, int &dh, + int &sy ) +{ + ew = get_combo_extra_width( r.height(), &awh ); + + sh = (awh+3)/4; + if ( sh < 3 ) + sh = 3; + dh = sh/2 + 1; + + ay = r.y() + (r.height()-awh-sh-dh)/2; + if ( ay < 0 ) { + //panic mode + ay = 0; + sy = r.height(); + } else { + sy = ay+awh+dh; + } + ax = r.x() + r.width() - ew +(ew-awh)/2; +} + +static inline int buttonthickness( int d ) +{ return d > 20 ? 5 : ( d < 10 ? 2: 3 ); } + +void NorwegianWoodStyle::drawSemicircleButton( QPainter *p, const QRect &r, + int dir, bool sunken, + const QColorGroup &g ) const +{ + int b = pixelMetric( PM_ScrollBarExtent ) > 20 ? 3 : 2; + + QRegion extrn( r.x(), r.y(), r.width(), r.height(), QRegion::Ellipse ); + QRegion intern( r.x()+b, r.y()+b, r.width()-2*b, r.height()-2*b, QRegion::Ellipse ); + int w2 = r.width()/2; + int h2 = r.height()/2; + + int bug = 1; //off-by-one somewhere!!!??? + + switch( dir ) { + case PointRight: + extrn += QRegion( r.x(), r.y(), w2, r.height() ); + intern += QRegion( r.x()+b,r.y()+b, w2-2*b, r.height()-2*b ); + break; + case PointLeft: + extrn += QRegion( r.x()+w2, r.y(), w2, r.height() ); + intern += QRegion( r.x()+w2+b,r.y()+b, w2-2*b, r.height()-2*b ); + break; + case PointUp: + extrn += QRegion( r.x(), r.y()+h2, r.width(), h2 ); + intern += QRegion( r.x()+b,r.y()+h2+b, r.width()-2*b-bug, h2-2*b-bug ); + break; + case PointDown: + extrn += QRegion( r.x(), r.y(), r.width(), h2 ); + intern += QRegion( r.x()+b,r.y()+b, r.width()-2*b-bug, h2-2*b-bug ); + break; + } + + extrn = extrn - intern; + QPointArray a; + a.setPoints( 3, r.x(), r.y(), r.x(), r.bottom(), r.right(), r.top() ); + + QRegion oldClip = p->clipRegion(); + bool bReallyClip = p->hasClipping(); // clip only if we really want. + p->setClipRegion( intern ); + p->fillRect( r, g.brush( QColorGroup::Button ) ); + + p->setClipRegion( QRegion(a)&extrn ); + p->fillRect( r, sunken ? g.dark() : g.light() ); + + a.setPoints( 3, r.right(), r.bottom(), r.x(), r.bottom(), + r.right(), r.top() ); + p->setClipRegion( QRegion(a) & extrn ); + p->fillRect( r, sunken ? g.light() : g.dark() ); + + p->setClipRegion( oldClip ); + p->setClipping( bReallyClip ); +} + +// ************************** +// --- Plugin - interface --- +// ************************** + +class WoodStylePlugin : public QStylePlugin +{ +public: + WoodStylePlugin(); + + QStringList keys() const; + QStyle *create( const QString& ); +}; + +WoodStylePlugin::WoodStylePlugin() +: QStylePlugin() +{ +} + +QStringList WoodStylePlugin::keys() const +{ + QStringList list; + list << "Wood"; + return list; +} + +QStyle* WoodStylePlugin::create( const QString& s ) +{ + if ( s.lower() == "wood" ) + return new NorwegianWoodStyle(); + + return 0; +} + +Q_EXPORT_PLUGIN( WoodStylePlugin ) + +#endif diff --git a/plugins/styles/wood/wood.h b/plugins/styles/wood/wood.h new file mode 100644 index 0000000..1e428ac --- /dev/null +++ b/plugins/styles/wood/wood.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** $Id: wood.h,v 1.1.1.8 2006/05/07 17:31:30 chehrlic Exp $ +** +** Definition of something or other +** +** Created : 979899 +** +** Copyright (C) 1997 by Trolltech AS. All rights reserved. +** +** This file is part of an example program for Qt. This example +** program may be used, distributed and modified without limitation. +** +*****************************************************************************/ + +#ifndef WOOD_H +#define WOOD_H + + +#include + +#ifndef QT_NO_STYLE_WINDOWS + +#include + + +class NorwegianWoodStyle : public QWindowsStyle +{ +public: + NorwegianWoodStyle(); + void polish( QApplication*); + void polish( QWidget* ); + void unPolish( QWidget* ); + void unPolish( QApplication*); + + void drawPrimitive( PrimitiveElement pe, + QPainter *p, + const QRect &r, + const QColorGroup &cg, + SFlags flags = Style_Default, + const QStyleOption& = QStyleOption::Default ) const; + + void drawControl( ControlElement element, + QPainter *p, + const QWidget *widget, + const QRect &r, + const QColorGroup &cg, + SFlags how = Style_Default, + const QStyleOption& = QStyleOption::Default ) const; + + void drawControlMask( ControlElement element, + QPainter *p, + const QWidget *widget, + const QRect &r, + const QStyleOption& = QStyleOption::Default ) const; + + void drawComplexControl( ComplexControl cc, + QPainter *p, + const QWidget *widget, + const QRect &r, + const QColorGroup &cg, + SFlags how = Style_Default, + SCFlags sub = SC_All, + SCFlags subActive = SC_None, + const QStyleOption& = QStyleOption::Default ) const; + + void drawComplexControlMask( ComplexControl control, + QPainter *p, + const QWidget *widget, + const QRect &r, + const QStyleOption& = QStyleOption::Default ) const; + + QRect querySubControlMetrics( ComplexControl control, + const QWidget *widget, + SubControl sc, + const QStyleOption& = QStyleOption::Default ) const; + + QRect subRect( SubRect r, const QWidget *widget ) const; + + +private: + void drawSemicircleButton(QPainter *p, const QRect &r, int dir, + bool sunken, const QColorGroup &g ) const; + QPalette oldPalette; + QPixmap *sunkenDark; + QPixmap *sunkenLight; + +}; + +#endif + +#endif diff --git a/plugins/styles/wood/wood.rc b/plugins/styles/wood/wood.rc new file mode 100644 index 0000000..55c3468 --- /dev/null +++ b/plugins/styles/wood/wood.rc @@ -0,0 +1,97 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,0,0,0 + PRODUCTVERSION 0,0,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Vladimir Shutoff\0" + VALUE "FileDescription", "wood\0" + VALUE "FileVersion", "0, 9, 5, 0\0" + VALUE "InternalName", "wood\0" + VALUE "LegalCopyright", "Copyright © 2002-2003\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "wood.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "SIM\0" + VALUE "ProductVersion", "0, 9, 5, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/styles/wood/wood.vcproj b/plugins/styles/wood/wood.vcproj new file mode 100644 index 0000000..2ebbb6d --- /dev/null +++ b/plugins/styles/wood/wood.vcproj @@ -0,0 +1,266 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/transparent/CMakeLists.txt b/plugins/transparent/CMakeLists.txt new file mode 100644 index 0000000..2a4bbe8 --- /dev/null +++ b/plugins/transparent/CMakeLists.txt @@ -0,0 +1,27 @@ +####################### +# transparent library # +####################### +IF(BUILD_DROPPED) +SET(transparent_SRCS + transparent.cpp + transparentcfg.cpp +) + +SET(transparent_HDRS + transparent.h + transparentcfg.h +) + +SET(transparent_UICS + transparentcfgbase.ui +) + +SET(transparent_LIBS + floaty +) + +REMOVE_DEFINITIONS(-DQT3_SUPPORT) +REMOVE_DEFINITIONS(-DQT_3SUPPORT_LIB) +REMOVE_DEFINITIONS(-DQT3_SUPPORT_WARNINGS) +SIM_ADD_PLUGIN(transparent) +ENDIF(BUILD_DROPPED) diff --git a/plugins/transparent/configure.in.in b/plugins/transparent/configure.in.in new file mode 100644 index 0000000..2c51f7a --- /dev/null +++ b/plugins/transparent/configure.in.in @@ -0,0 +1,10 @@ +compile_plugin="no" +if test "$use_kde" = "yes"; then + compile_plugin="yes" + TRANSPARENT_OBJ=transtop.lo + AC_SUBST([TRANSPARENT_OBJ]) +fi +if test "$kde_use_qt_win" = "yes"; then + compile_plugin="yes" +fi +AM_CONDITIONAL(ENABLE_TRANSPARENT, test "x$compile_plugin" = "xyes") diff --git a/plugins/transparent/transparent.cpp b/plugins/transparent/transparent.cpp new file mode 100644 index 0000000..5853316 --- /dev/null +++ b/plugins/transparent/transparent.cpp @@ -0,0 +1,278 @@ +/*************************************************************************** + transparent.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include + +#include "log.h" +#include "misc.h" +#include "core.h" + +#include "transparent.h" +#include "mainwin.h" +#include "transparentcfg.h" +#include "../floaty/floatywnd.h" //Handle Floatings +#include "profile.h" +#include "profilemanager.h" + + +#define SHOW_TIMEOUT 300 +#define HIDE_TIMEOUT 1000 + +using namespace SIM; + +Plugin *createTransparentPlugin(unsigned base, bool, Buffer *config) +{ + return new TransparentPlugin(base, config); +} + +static PluginInfo info = + { + I18N_NOOP("Transparent"), +#ifdef WIN32 + I18N_NOOP("Plugin provides windows transparency\n" + "This plugin works only on Windows 2000 or Windows XP") +#else + I18N_NOOP("Plugin provides windows transparency") +#endif + , + VERSION, + createTransparentPlugin, +#ifdef WIN32 + PLUGIN_DEFAULT +#else + PLUGIN_NOLOAD_DEFAULT +#endif + }; + +EXPORT_PROC PluginInfo* GetPluginInfo() +{ + return &info; +} + +TransparentPlugin::TransparentPlugin(unsigned base, Buffer *config) + : QObject(), Plugin(base) + , timer (NULL) //Fixme? look below + , m_bHaveMouse (false) + , m_bActive (false) +{ + m_propertyHub = SIM::PropertyHub::create("transparent"); + if (value("Transparency").toUInt() >100) + setValue("Transparency", 100); + + QTimer *timer = new QTimer(this); //Fixme? look above + connect(timer, SIGNAL(timeout()), this, SLOT(tickMouse())); + timer->start(1000); + setState(); +} + +TransparentPlugin::~TransparentPlugin() +{ + delete timer; + + // reset opacity for all toplevel widgets + QWidgetList list = QApplication::topLevelWidgets(); + foreach(QWidget *w,list) + { + w->setWindowOpacity(1.0); + } +} + +QByteArray TransparentPlugin::getConfig() +{ + return QByteArray(); +} + +QWidget *TransparentPlugin::getMainWindow() +{ + CorePlugin *core = GET_CorePlugin(); + return core->getMainWindow(); +} + +QWidget *TransparentPlugin::createConfigWindow(QWidget *parent) +{ + return new TransparentCfg(parent, this); +} + +void TransparentPlugin::tickMouse() +{ + QPoint p = QCursor::pos(); + bool bMouse = false; + QWidget *main = getMainWindow(); + if (main && main->isVisible()){ + if (main->frameGeometry().contains(p)) + bMouse = true; + } + + //Handle Floatings// + QWidgetList list = QApplication::topLevelWidgets(); + foreach (QWidget *w,list) { + if (bMouse) + break; + if (FloatyWnd *flt = dynamic_cast(w)) + bMouse = flt->frameGeometry().contains(p); + } + //Handle Floatings// + + if (bMouse != m_bHaveMouse){ + m_bHaveMouse = bMouse; + setState(); + } +} + +bool TransparentPlugin::eventFilter(QObject *o, QEvent *e) +{ + if (value("IfInactive").toBool()){ + switch (e->type()){ + case QEvent::WindowActivate: + m_bActive = true; + setState(); + break; + case QEvent::WindowDeactivate: + m_bActive = false; + setState(); + break; + case QEvent::Show:{ + QWidget *main = getMainWindow(); + if (main){ + setState(); + } + break; + } + default: + break; + } + } + return QObject::eventFilter(o, e); +} + +void TransparentPlugin::setState() +{ + QWidget *main = getMainWindow(); + QWidgetList list = QApplication::topLevelWidgets(); + + if (main == NULL) + return; + if (timer == NULL) { + timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(tick())); + main->installEventFilter(this); + main->setMouseTracking(true); + m_bActive = main->isActiveWindow(); + m_bState = !m_bActive; + } + bool bNewState = m_bActive || m_bHaveMouse; + if (bNewState == m_bState){ + qreal transparency = (100 - value("Transparency").toUInt()) / 100.; + if(value("IfMainWindow").toBool()) + main->setWindowOpacity(transparency); + else + main->setWindowOpacity(1.0); + + QWidgetList list = QApplication::topLevelWidgets(); + foreach (QWidget *w,list) { + if (FloatyWnd *refwnd = dynamic_cast(w)){ + refwnd->installEventFilter(this); + if (value("IfFloatings").toBool()) + refwnd->setWindowOpacity(transparency); + else + refwnd->setWindowOpacity(1.0); + } + } + return; + } + m_bState = bNewState; + startTime = QTime::currentTime(); + timer->start(10); +} + +void TransparentPlugin::tick() +{ + QWidget *main = getMainWindow(); + if (main == NULL){ + timer->stop(); + return; + } + qreal timeout = m_bActive ? SHOW_TIMEOUT : HIDE_TIMEOUT; + qreal difftime = startTime.msecsTo( QTime::currentTime() ); + if (difftime >= timeout){ + difftime = timeout; + timer->stop(); + } + if (m_bState) + difftime = timeout - difftime; + + qreal transparency = (100 - value("Transparency").toUInt()) / 100.; + qreal diff_to_opaque = 1. - transparency; + transparency = transparency + diff_to_opaque * (1 - difftime / timeout); + + //log(L_DEBUG, "transparency: %f, diff_to_opaque %f, time %d, timeout %d", + // transparency, diff_to_opaque, time, timeout); + if (value("IfMainWindow").toBool()) + main->setWindowOpacity(transparency); + else + main->setWindowOpacity(1.0); + + //Handle Floatings + QWidgetList list = QApplication::topLevelWidgets(); + foreach (QWidget *w,list) { + if (FloatyWnd *refwnd = qobject_cast(w)){ + refwnd->installEventFilter(this); + if (value("IfFloatings").toBool()) + refwnd->setWindowOpacity(transparency); + else + refwnd->setWindowOpacity(1.0); + } + } + //Handle Floatings// +} + +bool TransparentPlugin::processEvent(Event *e) +{ + if (e->type() == eEventInit) { + setState(); + } + else if(e->type() == eEventPluginLoadConfig) + { + PropertyHubPtr hub = ProfileManager::instance()->getPropertyHub("trnsparent"); + if(!hub.isNull()) + setPropertyHub(hub); + } + return false; +} + + +void TransparentPlugin::setPropertyHub(SIM::PropertyHubPtr hub) +{ + m_propertyHub = hub; +} + +SIM::PropertyHubPtr TransparentPlugin::propertyHub() +{ + return m_propertyHub; +} + +QVariant TransparentPlugin::value(const QString& key) +{ + return m_propertyHub->value(key); +} + +void TransparentPlugin::setValue(const QString& key, const QVariant& v) +{ + m_propertyHub->setValue(key, v); +} diff --git a/plugins/transparent/transparent.h b/plugins/transparent/transparent.h new file mode 100644 index 0000000..8e7aa95 --- /dev/null +++ b/plugins/transparent/transparent.h @@ -0,0 +1,63 @@ +/*************************************************************************** + transparent.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _TRANSPARENT_H +#define _TRANSPARENT_H + +#include +#include + +#include "cfg.h" +#include "event.h" +#include "plugins.h" +#include "propertyhub.h" + +class QWidget; +class QTimer; + +class TransparentPlugin : public QObject, public SIM::Plugin, public SIM::EventReceiver +{ + Q_OBJECT +public: + TransparentPlugin(unsigned, Buffer*); + virtual ~TransparentPlugin(); + void setState(); + void setPropertyHub(SIM::PropertyHubPtr hub); + SIM::PropertyHubPtr propertyHub(); + QVariant value(const QString& key); + void setValue(const QString& key, const QVariant& v); +public Q_SLOTS: + void tick(); + void tickMouse(); +protected: + virtual QByteArray getConfig(); + virtual QWidget *createConfigWindow(QWidget *parent); + virtual bool eventFilter(QObject*, QEvent*); + QWidget *getMainWindow(); + bool m_bState; + virtual bool processEvent(SIM::Event *e); + + QTime startTime; + QTimer *timer; + bool m_bHaveMouse; + bool m_bActive; +private: + SIM::PropertyHubPtr m_propertyHub; +}; + +#endif + diff --git a/plugins/transparent/transparent.rc b/plugins/transparent/transparent.rc new file mode 100644 index 0000000..9eabb74 --- /dev/null +++ b/plugins/transparent/transparent.rc @@ -0,0 +1,97 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,9,6,0 + PRODUCTVERSION 0,9,6,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Vladimir Shutoff\0" + VALUE "FileDescription", "Transparent plugin\0" + VALUE "FileVersion", "0, 9, 6, 0\0" + VALUE "InternalName", "transparent\0" + VALUE "LegalCopyright", "Copyright © 2002-2003\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "transparent.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "SIM\0" + VALUE "ProductVersion", "0, 9, 6, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/transparent/transparent.vcproj b/plugins/transparent/transparent.vcproj new file mode 100644 index 0000000..d2ca40b --- /dev/null +++ b/plugins/transparent/transparent.vcproj @@ -0,0 +1,398 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/transparent/transparentcfg.cpp b/plugins/transparent/transparentcfg.cpp new file mode 100644 index 0000000..e7f57df --- /dev/null +++ b/plugins/transparent/transparentcfg.cpp @@ -0,0 +1,44 @@ +/*************************************************************************** + transparentcfg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "transparentcfg.h" +#include "transparent.h" + +#include +#include + +TransparentCfg::TransparentCfg(QWidget *parent, TransparentPlugin *plugin) + : QWidget(parent) + , m_plugin(plugin) +{ + setupUi(this); + sldTransparency->setValue(m_plugin->value("Transparency").toUInt()); + chkInactive->setChecked(m_plugin->value("IfInactive").toBool()); + chkMainWindow->setChecked(m_plugin->value("IfMainWindow").toBool()); + chkFloatings->setChecked (m_plugin->value("IfFloatings").toBool()); +} + +void TransparentCfg::apply() +{ + m_plugin->setValue("Transparency", sldTransparency->value()); + m_plugin->setValue("IfInactive", chkInactive->isChecked()); + m_plugin->setValue("IfMainWindow", chkMainWindow->isChecked()); + m_plugin->setValue("IfFloatings", chkFloatings->isChecked()); + m_plugin->setState(); +} + + diff --git a/plugins/transparent/transparentcfg.h b/plugins/transparent/transparentcfg.h new file mode 100644 index 0000000..c769b75 --- /dev/null +++ b/plugins/transparent/transparentcfg.h @@ -0,0 +1,37 @@ +/*************************************************************************** + transparentcfg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _TRANSPARENTCFG_H +#define _TRANSPARENTCFG_H + +#include "ui_transparentcfgbase.h" + +class TransparentPlugin; + +class TransparentCfg : public QWidget, public Ui::TransparentCfgBase +{ + Q_OBJECT +public: + TransparentCfg(QWidget *parent, TransparentPlugin *plugin); +public slots: + void apply(); +protected: + TransparentPlugin *m_plugin; +}; + +#endif + diff --git a/plugins/transparent/transparentcfgbase.ui b/plugins/transparent/transparentcfgbase.ui new file mode 100644 index 0000000..3272dbf --- /dev/null +++ b/plugins/transparent/transparentcfgbase.ui @@ -0,0 +1,114 @@ + + + TransparentCfgBase + + + + 0 + 0 + 530 + 391 + + + + Form1 + + + + + + + 0 + 0 + + + + Transparency of main window: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + false + + + + + + + + + opaque + + + + + + + 100 + + + 5 + + + 20 + + + Qt::Horizontal + + + 0 + + + + + + + transparent + + + + + + + + + Transparent only if inactive + + + + + + + Mainwindow + + + + + + + Floaties + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + diff --git a/plugins/transparent/transtop.cpp b/plugins/transparent/transtop.cpp new file mode 100644 index 0000000..182ce1d --- /dev/null +++ b/plugins/transparent/transtop.cpp @@ -0,0 +1,64 @@ +/*************************************************************************** + transtop.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "transtop.h" + +#include +#include +#include + +#include "event.h" + +TransparentTop::TransparentTop(QWidget *parent, unsigned transparent) + : QObject(parent) +{ + m_transparent = transparent * 0.01; + rootpixmap = new KRootPixmap(parent); + rootpixmap->setCustomPainting(true); + connect(rootpixmap, SIGNAL(backgroundUpdated(const QPixmap&)), this, SLOT(backgroundUpdated(const QPixmap&))); + transparentChanged(); +} + +TransparentTop::~TransparentTop() +{} + +void TransparentTop::transparentChanged() +{ + rootpixmap->start(); +} + +void TransparentTop::setTransparent(unsigned transparent) +{ + m_transparent = transparent * 0.01; + transparentChanged(); +} + +QPixmap TransparentTop::background(const QColor &c) +{ + if (bg.isNull()) + return QPixmap(); + KPixmap pix = KPixmap(bg); + return KPixmapEffect::fade(pix, m_transparent, c); +} + +void TransparentTop::backgroundUpdated( const QPixmap &pm ) +{ + bg = pm; + SIM::EventRepaintView e; + e.process(); +} + diff --git a/plugins/transparent/transtop.h b/plugins/transparent/transtop.h new file mode 100644 index 0000000..dc0331c --- /dev/null +++ b/plugins/transparent/transtop.h @@ -0,0 +1,48 @@ +/*************************************************************************** + transtop.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _TRANSTOP_H +#define _TRANSTOP_H + + +#include +#include + +class KRootPixmap; + +class TransparentTop : public QObject +{ + Q_OBJECT +public: + TransparentTop(QWidget *parent, unsigned transparent); + ~TransparentTop(); + static void setTransparent(QWidget*, bool isTransparent, unsigned long transparency); + static bool bCanTransparent; + static TransparentTop *getTransparent(QWidget*); + QPixmap background(const QColor &c); + KRootPixmap *rootpixmap; + void setTransparent(unsigned transparent); + void transparentChanged(); +protected slots: + void backgroundUpdated( const QPixmap &pm ); +protected: + QPixmap bg; + double m_transparent; +}; + +#endif + diff --git a/plugins/update/CMakeLists.txt b/plugins/update/CMakeLists.txt new file mode 100644 index 0000000..51921e1 --- /dev/null +++ b/plugins/update/CMakeLists.txt @@ -0,0 +1,18 @@ +################## +# update library # +################## +IF(BUILD_DROPPED) +IF(FALSE) + +SET(update_SRCS + update.cpp +) + +SET(update_HDRS + update.h +) + +SIM_ADD_PLUGIN(update) + +ENDIF(FALSE) +ENDIF(BUILD_DROPPED) diff --git a/plugins/update/update.cpp b/plugins/update/update.cpp new file mode 100644 index 0000000..2826c88 --- /dev/null +++ b/plugins/update/update.cpp @@ -0,0 +1,466 @@ +/*************************************************************************** + update.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "update.h" +#include "socket/socketfactory.h" +#include "core.h" + +#include "simgui/ballonmsg.h" +#include "aboutdata.h" +#include "log.h" +#include "mainwin.h" + +#include +#include +#ifdef WIN32 +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace SIM; + + + +QWidget *UpdatePlugin::getMainWindow() //obsolete +{ + CorePlugin *core = GET_CorePlugin(); + return core->getMainWindow(); +} + + +Plugin *createUpdatePlugin(unsigned base, bool, Buffer *config) +{ + Plugin *plugin = new UpdatePlugin(base, config); + return plugin; +} + +static PluginInfo info = + { + I18N_NOOP("Update"), + I18N_NOOP("Plugin provides notifications about update SIM software"), + VERSION, + createUpdatePlugin, + PLUGIN_NOLOAD_DEFAULT + }; + +static QWidget *pMain = NULL; + +EXPORT_PROC PluginInfo* GetPluginInfo() +{ + return &info; +} + +static DataDef updateData[] = + { + { "Time", DATA_ULONG, 1, 0 }, + { NULL, DATA_UNKNOWN, 0, 0 } + }; + +UpdatePlugin::UpdatePlugin(unsigned base, Buffer *config) + : Plugin(base) +{ + load_data(updateData, &data, config); + CmdGo = registerType(); + this->timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(timeout())); + this->show=false; + this->upToDate=false; + this->ignore=false; + this->isInstalling=false; + this->CHECK_INTERVAL = 60; //seconds for the first time wait + setTime(time(NULL)); //this was missing ;) + this->msgret=-1; + this->bupdateMsgMissing=true; + this->timer->start(15000); + +} + +UpdatePlugin::~UpdatePlugin() +{ + free_data(updateData, &data); +} + +QByteArray UpdatePlugin::getConfig() +{ + return save_data(updateData, &data); +} + +void UpdatePlugin::timeout() +{ + testForUpdate(); +} + +void UpdatePlugin::testForUpdate(){ + if (ignore) return; + if (!getSocketFactory()->isActive() || !isDone()) + return; + if (((unsigned)time(NULL)) >= getTime() + CHECK_INTERVAL){ + versionurl=QString(""); + this->CHECK_INTERVAL=60*60*12; //checking every half day for an update, after first time + //url = "http://sim-im.org/index.php?v=" + VERSION; +#ifdef WIN32 + versionurl = "http://www.sim-icq.de/update.php?"; + versionurl += "os=1"; +#else +#ifdef QT_MACOSX_VERSION + versionurl += "&os=2"; + location="??"; +#endif +#endif +#ifdef CVS_BUILD + //url += "&svn="; + QString date(__DATE__); + versionurl += date; + versionurl.replace(' ',"%20"); + #ifdef WIN32 + location="http://www.sim-icq.de"; + #endif +#else + versionurl += "&release"; +#endif + /*versionurl += "&l="; + QString s = i18n("Message", "%n messages", 1); + s = s.remove("1 "); + for (int i = 0; i < (int)(s.length()); i++){ + unsigned short c = s[i].unicode(); + if ((c == ' ') || (c == '%') || (c == '=') || (c == '&')){ + char b[5]; + sprintf(b, "%02X", c); + versionurl += b; + }else if (c > 0x77){ + char b[10]; + sprintf(b, "#%04X", c); + versionurl += b; + }else{ + versionurl += (char)c; + } + }*/ + QUrl um( "http://www.sim-icq.de/updatemsg.php" ); + httpmsg = new QHttp(this); + connect(httpmsg, SIGNAL(requestFinished(int, bool)),this, SLOT(UpdateMsgDownloadFinished(int, bool))); + QBuffer *buffer_um = new QBuffer(&bytes_um); + buffer_um->open(QIODevice::ReadWrite); + httpmsg->setHost(um.host()); + Request_um=httpmsg->get(um.path(),buffer_um); + } +} + +void UpdatePlugin::UpdateMsgDownloadFinished(int requestId, bool error){ + if (error || msgret==QMessageBox::Yes + || msgret==QMessageBox::No + || msgret==QMessageBox::Ok + || upToDate) return; //Don't show the dialog more than once SIM starts. + if (Request_um==requestId) { + QString updateMsg(bytes_um); + this->m_updateMsg=updateMsg; + this->bupdateMsgMissing=false; + disconnect(httpmsg, SIGNAL(requestFinished(int, bool)),this, SLOT(UpdateMsgDownloadFinished(int, bool))); + QUrl u=QUrl(versionurl); + http = new QHttp(this); + connect(http, SIGNAL(requestFinished(int, bool)),this, SLOT(Finished(int, bool))); + QBuffer *buffer = new QBuffer(&bytes); + buffer->open(QIODevice::ReadWrite); + http->setHost(u.host()); + Request=http->get(u.path(),buffer); + } +} + +void UpdatePlugin::Finished(int requestId, bool error){ + if (error || msgret==QMessageBox::Yes + || msgret==QMessageBox::No + || msgret==QMessageBox::Ok + || upToDate + || bupdateMsgMissing) return; //Don't show the dialog more than once SIM starts. + + + if (Request==requestId) { + QString remoteVersion(bytes); + QDate date=QDate::fromString(remoteVersion,Qt::LocalDate); + QString currentVersion = SIM::getAboutData()->version(); + QString majorVersion = currentVersion.section(' ',0,2,QString::SectionDefault); + if (!isUpdateNeeded(currentVersion, remoteVersion)) + { //If no Update is needed don't go further. + if(remoteVersion.right(4).compare("HTML")==0) + { + upToDate=false; + return; + } + upToDate=true; + log(L_DEBUG, "Update::You have the latest online Version."); + return; + } + + if (!show) { + show=!show; + disconnect(timer, SIGNAL(timeout()), this, SLOT(timeout())); + msgret = QMessageBox::question( 0, i18n("Sim-IM Update"), + i18n("A new update ist available.\n\nYou have Version %1:\n%2\n\n").arg(majorVersion).arg(dlocal.toString()) + + i18n("New Version is:\n%1\n\n").arg(dremote.toString()) + + i18n("Changes are:\n%1\n\n").arg(this->m_updateMsg) + +#ifdef WIN32 + i18n("I can now DOWNLOAD the Update\navailable at: %1\nIN BACKROUND and install the update\nfor Sim-IM, automatically after finishing.\n\nWould like you to ALLOW to carry out THE UPDATE?").arg(location), + QMessageBox::Yes,QMessageBox::No); + + address=QString("http://www.sim-icq.de/setup.exe"); + + if (msgret == QMessageBox::Yes) + download_and_install(); + else { + msgret = QMessageBox::question( 0, i18n("Sim-IM Update Remember?"), + i18n("Should I remember you to update in some minutes again?"), + QMessageBox::Yes,QMessageBox::No); + + if (msgret == QMessageBox::No) + this->timer->stop(); + else { + connect(timer, SIGNAL(timeout()), this, SLOT(timeout())); + disconnect(http, SIGNAL(requestFinished(int, bool)),this, SLOT(fileRequestFinished(int, bool))); + connect(http, SIGNAL(requestFinished(int, bool)),this, SLOT(Finished(int, bool))); + show=!show; + msgret=0; + setTime(time(NULL)); + this->CHECK_INTERVAL=60*20; + } + return; + } +#else + i18n("Please go to %1\nand download the new version from:\n\n%2").arg(location).arg(datestr), + QMessageBox::Ok); + address=QString::null; +#endif + } + } +} + +bool UpdatePlugin::isUpdateNeeded(QString& local, QString& remote){ + + /* + The remote-String in win32 is generated in following format: + echo %SIMVERSION% %SIMTAG% %SVNTAG% %DATE% %TIME% >update.php + */ + //Cut the Time away + remote = remote.trimmed(); + remote = remote.left(remote.length()-11); + remote = remote.trimmed(); + + remote = remote.replace(" "," "); //No double whitespaces, because scanning is wrong then + local = local.replace(" "," "); + + local = local.section (' ',2,5,QString::SectionDefault); + remote = remote.section(' ',4,4,QString::SectionDefault); + + QString month("Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec"); + QStringList ml = month.split(',', QString::SkipEmptyParts); + int i=0; + for ( QStringList::Iterator it = ml.begin() ; it != ml.end(); ++it, ++i ) + { + QString search(*it); + if (search.compare(local.section(' ',0,0, QString::SectionDefault))==0) + break; + } + + this->dlocal = QDate(local.right(4).toInt(), i+1 , local.section(' ',1,1, QString::SectionDefault).toInt()); + this->dremote = QDate(remote.right(4).toInt(), remote.mid(3,2).toInt(), remote.left(2).toInt()); + + if (dremote.isNull()) + { + QMessageBox::critical( 0, i18n("Update Plugin: Error fetching the date of the current Update Setup."), + i18n("Please contact and notify me via noragen@gmx.net about this issue. \n//\\//oRaGen.")); + log(L_DEBUG, "Update::Error in parsing Version-String. Perhaps you forgot to set SVNTAG and SIMTAG - Environment-Vars"); + } + + //local=dlocal->toString(); + //remote=dremote->toString(); + if (dlocal.daysTo(dremote)>0) + { + log(L_DEBUG, "Update::There is a new Version on www.sim-icq.de"); + return true; + } + else + { + log(L_DEBUG, "Update::Your SIM-Version is up to date."); + return false; + } +} + +void UpdatePlugin::download_and_install(){ + disconnect(http, SIGNAL(requestFinished(int, bool)),this, SLOT(Finished(int, bool))); + connect(http, SIGNAL(requestFinished(int, bool)),this, SLOT(fileRequestFinished(int, bool))); + ignore=true; + downloadFile(); +} + +void UpdatePlugin::installFile(){ +#ifdef WIN32 + if (isInstalling) return; + + qint64 pid; + if ( !QProcess::startDetached("setup.exe", QStringList(), ".", &pid) ) { + QMessageBox::critical( 0, i18n("Error launching the Update-Setup"), + i18n("Make sure the Sim-IM Dirctory\n") + + i18n("is writable and you have rights to install.\n")); + ignore=false; + disconnect(http, SIGNAL(requestFinished(int, bool)),this, SLOT(fileRequestFinished(int, bool))); + return; + } + + //Shutdown SIM here, because we are now ready to install: + isInstalling=true; + QCloseEvent *e = new QCloseEvent(); + //pMain=getMainWindow(); //obsolete + + pMain=GET_CorePlugin()->getMainWindow(); + + (static_cast(pMain))->closeEvent(e); + +#endif +} + +void UpdatePlugin::downloadFile() + { + QUrl url(address); + QFileInfo fileInfo(url.path()); + QString fileName = fileInfo.fileName(); + + if (QFile::exists(fileName)){ + QFile::remove(fileName); + download_and_install(); + return; + } + + file = new QFile(fileName); + if (!file->open(QIODevice::WriteOnly)) { + QMessageBox::critical( 0, i18n("HTTP"), + i18n("Unable to save the file %1: %2.") + .arg(fileName).arg(file->errorString())); + delete file; + file = 0; + return; + } + httpRequestAborted = false; + Request = http->get(url.path(), file); + } + +void UpdatePlugin::fileRequestFinished(int requestId, bool error) + { + if (httpRequestAborted) { + if (file) { + file->close(); + file->remove(); + delete file; + file = 0; + } + + //progressDialog->hide(); + return; + } + + if (requestId != Request) + return; + + //progressDialog->hide(); + file->close(); + + if (error) { + file->remove(); + download_and_install(); + return; + } + installFile(); + //downloadButton->setEnabled(true); + } + + + +#if 0 +I18N_NOOP("Show details") +I18N_NOOP("Remind later") +#endif + +bool UpdatePlugin::done(unsigned, Buffer&, const QString &headers) +{ + QString h = getHeader("Location", headers); + if (!h.isEmpty()){ + Command cmd; + cmd->id = CmdStatusBar; + EventCommandWidget eWidget(cmd); + eWidget.process(); + QWidget *statusWidget = eWidget.widget(); + if (statusWidget == NULL) + return false; + m_url = h; + EventNotification::ClientNotificationData d; + d.client = NULL; + d.text = I18N_NOOP("New version SIM is released"); + d.code = 0; + d.args = QString::null; + d.flags = EventNotification::ClientNotificationData::E_INFO; + d.options = "Show details\x00Remind later\x00\x00"; + d.id = CmdGo; + EventShowNotification e(d); + e.process(); + } + setTime(time(NULL)); + EventSaveState e; + e.process(); + return false; +} + +bool UpdatePlugin::processEvent(Event *e) +{ + if (e->type() == eEventCommandExec){ + EventCommandExec *ece = static_cast(e); + CommandDef *cmd = ece->cmd(); + if (cmd->id == CmdGo){ + EventGoURL(m_url).process(); + setTime(time(NULL)); + m_url = QString::null; + EventSaveState().process(); + return true; + } + } + return false; +} + +QString UpdatePlugin::getHeader(const QString &name, const QString &headers) +{ + int idx = headers.indexOf(name + ':'); + if(idx != -1) { + int end = headers.indexOf('\n', idx); + QString res; + if(end == -1) + res = headers.mid(idx); + else + res = headers.mid(idx, end - idx + 1); + return res.trimmed(); + } + return QString::null; +} +/* +#ifndef NO_MOC_INCLUDES +#include "update.moc" +#endif +*/ \ No newline at end of file diff --git a/plugins/update/update.h b/plugins/update/update.h new file mode 100644 index 0000000..6d7145c --- /dev/null +++ b/plugins/update/update.h @@ -0,0 +1,92 @@ +/*************************************************************************** + update.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _UPDATE_H +#define _UPDATE_H + + + +#include "cfg.h" +#include "event.h" +#include "fetch.h" +#include "plugins.h" +#include "mainwin.h" + +#include +#include +#include +#include +#include + +struct UpdateData +{ + SIM::Data Time; +}; + +class UpdatePlugin : public QObject, public SIM::Plugin, public FetchClient, public SIM::EventReceiver +{ + Q_OBJECT +public: + UpdatePlugin(unsigned, Buffer*); + virtual ~UpdatePlugin(); + void testForUpdate(); +protected slots: + void timeout(); + void Finished(int requestId, bool error); + void UpdateMsgDownloadFinished(int requestId, bool error); + void fileRequestFinished(int requestId, bool error); +protected: + unsigned CmdGo; + bool done(unsigned code, Buffer &data, const QString &headers); + virtual QByteArray getConfig(); + virtual bool processEvent(SIM::Event *e); + QString getHeader(const QString &name, const QString &headers); + bool isUpdateNeeded(QString&, QString&); + QWidget* getMainWindow(); + void download_and_install(); + void downloadFile(); + void installFile(); + QString versionurl; + QString m_url; + QString location; + QString address; + QString m_updateMsg; + PROP_ULONG(Time); + UpdateData data; + QByteArray bytes; + QByteArray bytes_um; + QHttp *http; + QHttp *httpmsg; + QFile *file; + bool httpRequestAborted; + int Request; + int Request_um; + QBuffer *buffer; + int msgret; + bool show; + bool bupdateMsgMissing; + bool upToDate; + bool ignore; + bool isInstalling; + QDate dlocal; + QDate dremote; + QTimer *timer; + unsigned CHECK_INTERVAL; +}; + +#endif + diff --git a/plugins/update/update.rc b/plugins/update/update.rc new file mode 100644 index 0000000..12d13b4 --- /dev/null +++ b/plugins/update/update.rc @@ -0,0 +1,97 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,9,6,0 + PRODUCTVERSION 0,9,6,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Vladimir Shutoff\0" + VALUE "FileDescription", "Update check plugin\0" + VALUE "FileVersion", "0, 9, 6, 0\0" + VALUE "InternalName", "update\0" + VALUE "LegalCopyright", "Copyright © 2002-2003\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "update.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "SIM\0" + VALUE "ProductVersion", "0, 9, 6, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/update/update.vcproj b/plugins/update/update.vcproj new file mode 100644 index 0000000..2e0c494 --- /dev/null +++ b/plugins/update/update.vcproj @@ -0,0 +1,310 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/weather/CMakeLists.txt b/plugins/weather/CMakeLists.txt new file mode 100644 index 0000000..ca3c3e9 --- /dev/null +++ b/plugins/weather/CMakeLists.txt @@ -0,0 +1,28 @@ +################### +# weather library # +################### +IF(BUILD_DROPPED) +SET(weather_SRCS + weather.cpp + weathercfg.cpp + wifacecfg.cpp +) + +SET(weather_HDRS + weather.h + weathercfg.h + wifacecfg.h +) + +SET(weather_UICS + weathercfgbase.ui + wifacecfgbase.ui +) + +ADD_JISP_ARCHIVE(jisp weather.jisp weather_SRCS) + +REMOVE_DEFINITIONS(-DQT3_SUPPORT) +REMOVE_DEFINITIONS(-DQT_3SUPPORT_LIB) +REMOVE_DEFINITIONS(-DQT3_SUPPORT_WARNINGS) +SIM_ADD_PLUGIN(weather) +ENDIF(BUILD_DROPPED) diff --git a/plugins/weather/jisp/0.png b/plugins/weather/jisp/0.png new file mode 100644 index 0000000..b85eeb4 Binary files /dev/null and b/plugins/weather/jisp/0.png differ diff --git a/plugins/weather/jisp/1.png b/plugins/weather/jisp/1.png new file mode 100644 index 0000000..b85eeb4 Binary files /dev/null and b/plugins/weather/jisp/1.png differ diff --git a/plugins/weather/jisp/10.png b/plugins/weather/jisp/10.png new file mode 100644 index 0000000..175fbef Binary files /dev/null and b/plugins/weather/jisp/10.png differ diff --git a/plugins/weather/jisp/11.png b/plugins/weather/jisp/11.png new file mode 100644 index 0000000..fdc25cf Binary files /dev/null and b/plugins/weather/jisp/11.png differ diff --git a/plugins/weather/jisp/12.png b/plugins/weather/jisp/12.png new file mode 100644 index 0000000..af608d0 Binary files /dev/null and b/plugins/weather/jisp/12.png differ diff --git a/plugins/weather/jisp/13.png b/plugins/weather/jisp/13.png new file mode 100644 index 0000000..0d695f7 Binary files /dev/null and b/plugins/weather/jisp/13.png differ diff --git a/plugins/weather/jisp/14.png b/plugins/weather/jisp/14.png new file mode 100644 index 0000000..eb1e101 Binary files /dev/null and b/plugins/weather/jisp/14.png differ diff --git a/plugins/weather/jisp/15.png b/plugins/weather/jisp/15.png new file mode 100644 index 0000000..8087938 Binary files /dev/null and b/plugins/weather/jisp/15.png differ diff --git a/plugins/weather/jisp/16.png b/plugins/weather/jisp/16.png new file mode 100644 index 0000000..861c888 Binary files /dev/null and b/plugins/weather/jisp/16.png differ diff --git a/plugins/weather/jisp/17.png b/plugins/weather/jisp/17.png new file mode 100644 index 0000000..9f56e8f Binary files /dev/null and b/plugins/weather/jisp/17.png differ diff --git a/plugins/weather/jisp/18.png b/plugins/weather/jisp/18.png new file mode 100644 index 0000000..732eb92 Binary files /dev/null and b/plugins/weather/jisp/18.png differ diff --git a/plugins/weather/jisp/19.png b/plugins/weather/jisp/19.png new file mode 100644 index 0000000..dcd4013 Binary files /dev/null and b/plugins/weather/jisp/19.png differ diff --git a/plugins/weather/jisp/2.png b/plugins/weather/jisp/2.png new file mode 100644 index 0000000..b85eeb4 Binary files /dev/null and b/plugins/weather/jisp/2.png differ diff --git a/plugins/weather/jisp/20.png b/plugins/weather/jisp/20.png new file mode 100644 index 0000000..4281bf1 Binary files /dev/null and b/plugins/weather/jisp/20.png differ diff --git a/plugins/weather/jisp/21.png b/plugins/weather/jisp/21.png new file mode 100644 index 0000000..d2e6b65 Binary files /dev/null and b/plugins/weather/jisp/21.png differ diff --git a/plugins/weather/jisp/22.png b/plugins/weather/jisp/22.png new file mode 100644 index 0000000..dcd4013 Binary files /dev/null and b/plugins/weather/jisp/22.png differ diff --git a/plugins/weather/jisp/23.png b/plugins/weather/jisp/23.png new file mode 100644 index 0000000..e3d4eaf Binary files /dev/null and b/plugins/weather/jisp/23.png differ diff --git a/plugins/weather/jisp/24.png b/plugins/weather/jisp/24.png new file mode 100644 index 0000000..e3d4eaf Binary files /dev/null and b/plugins/weather/jisp/24.png differ diff --git a/plugins/weather/jisp/25.png b/plugins/weather/jisp/25.png new file mode 100644 index 0000000..1c2ad7d Binary files /dev/null and b/plugins/weather/jisp/25.png differ diff --git a/plugins/weather/jisp/26.png b/plugins/weather/jisp/26.png new file mode 100644 index 0000000..a3820c2 Binary files /dev/null and b/plugins/weather/jisp/26.png differ diff --git a/plugins/weather/jisp/27.png b/plugins/weather/jisp/27.png new file mode 100644 index 0000000..5a6f0d0 Binary files /dev/null and b/plugins/weather/jisp/27.png differ diff --git a/plugins/weather/jisp/28.png b/plugins/weather/jisp/28.png new file mode 100644 index 0000000..73ad130 Binary files /dev/null and b/plugins/weather/jisp/28.png differ diff --git a/plugins/weather/jisp/29.png b/plugins/weather/jisp/29.png new file mode 100644 index 0000000..8058cdc Binary files /dev/null and b/plugins/weather/jisp/29.png differ diff --git a/plugins/weather/jisp/3.png b/plugins/weather/jisp/3.png new file mode 100644 index 0000000..b85eeb4 Binary files /dev/null and b/plugins/weather/jisp/3.png differ diff --git a/plugins/weather/jisp/30.png b/plugins/weather/jisp/30.png new file mode 100644 index 0000000..12f2569 Binary files /dev/null and b/plugins/weather/jisp/30.png differ diff --git a/plugins/weather/jisp/31.png b/plugins/weather/jisp/31.png new file mode 100644 index 0000000..c4e919a Binary files /dev/null and b/plugins/weather/jisp/31.png differ diff --git a/plugins/weather/jisp/32.png b/plugins/weather/jisp/32.png new file mode 100644 index 0000000..64a7461 Binary files /dev/null and b/plugins/weather/jisp/32.png differ diff --git a/plugins/weather/jisp/33.png b/plugins/weather/jisp/33.png new file mode 100644 index 0000000..1917aa7 Binary files /dev/null and b/plugins/weather/jisp/33.png differ diff --git a/plugins/weather/jisp/34.png b/plugins/weather/jisp/34.png new file mode 100644 index 0000000..d515b43 Binary files /dev/null and b/plugins/weather/jisp/34.png differ diff --git a/plugins/weather/jisp/35.png b/plugins/weather/jisp/35.png new file mode 100644 index 0000000..b85eeb4 Binary files /dev/null and b/plugins/weather/jisp/35.png differ diff --git a/plugins/weather/jisp/36.png b/plugins/weather/jisp/36.png new file mode 100644 index 0000000..398c468 Binary files /dev/null and b/plugins/weather/jisp/36.png differ diff --git a/plugins/weather/jisp/37.png b/plugins/weather/jisp/37.png new file mode 100644 index 0000000..a8b8bf8 Binary files /dev/null and b/plugins/weather/jisp/37.png differ diff --git a/plugins/weather/jisp/38.png b/plugins/weather/jisp/38.png new file mode 100644 index 0000000..5f46c6c Binary files /dev/null and b/plugins/weather/jisp/38.png differ diff --git a/plugins/weather/jisp/39.png b/plugins/weather/jisp/39.png new file mode 100644 index 0000000..514c2cc Binary files /dev/null and b/plugins/weather/jisp/39.png differ diff --git a/plugins/weather/jisp/4.png b/plugins/weather/jisp/4.png new file mode 100644 index 0000000..9f56e8f Binary files /dev/null and b/plugins/weather/jisp/4.png differ diff --git a/plugins/weather/jisp/40.png b/plugins/weather/jisp/40.png new file mode 100644 index 0000000..bb0199a Binary files /dev/null and b/plugins/weather/jisp/40.png differ diff --git a/plugins/weather/jisp/41.png b/plugins/weather/jisp/41.png new file mode 100644 index 0000000..5022861 Binary files /dev/null and b/plugins/weather/jisp/41.png differ diff --git a/plugins/weather/jisp/42.png b/plugins/weather/jisp/42.png new file mode 100644 index 0000000..23b45c1 Binary files /dev/null and b/plugins/weather/jisp/42.png differ diff --git a/plugins/weather/jisp/43.png b/plugins/weather/jisp/43.png new file mode 100644 index 0000000..2eb81bb Binary files /dev/null and b/plugins/weather/jisp/43.png differ diff --git a/plugins/weather/jisp/44.png b/plugins/weather/jisp/44.png new file mode 100644 index 0000000..1c2ad7d Binary files /dev/null and b/plugins/weather/jisp/44.png differ diff --git a/plugins/weather/jisp/45.png b/plugins/weather/jisp/45.png new file mode 100644 index 0000000..4292c5d Binary files /dev/null and b/plugins/weather/jisp/45.png differ diff --git a/plugins/weather/jisp/46.png b/plugins/weather/jisp/46.png new file mode 100644 index 0000000..daa249b Binary files /dev/null and b/plugins/weather/jisp/46.png differ diff --git a/plugins/weather/jisp/47.png b/plugins/weather/jisp/47.png new file mode 100644 index 0000000..b7ba0e6 Binary files /dev/null and b/plugins/weather/jisp/47.png differ diff --git a/plugins/weather/jisp/5.png b/plugins/weather/jisp/5.png new file mode 100644 index 0000000..21da1be Binary files /dev/null and b/plugins/weather/jisp/5.png differ diff --git a/plugins/weather/jisp/6.png b/plugins/weather/jisp/6.png new file mode 100644 index 0000000..9467f31 Binary files /dev/null and b/plugins/weather/jisp/6.png differ diff --git a/plugins/weather/jisp/7.png b/plugins/weather/jisp/7.png new file mode 100644 index 0000000..ac0ba5e Binary files /dev/null and b/plugins/weather/jisp/7.png differ diff --git a/plugins/weather/jisp/8.png b/plugins/weather/jisp/8.png new file mode 100644 index 0000000..b11cfa9 Binary files /dev/null and b/plugins/weather/jisp/8.png differ diff --git a/plugins/weather/jisp/9.png b/plugins/weather/jisp/9.png new file mode 100644 index 0000000..6798ea2 Binary files /dev/null and b/plugins/weather/jisp/9.png differ diff --git a/plugins/weather/jisp/icondef.xml b/plugins/weather/jisp/icondef.xml new file mode 100644 index 0000000..8e92dea --- /dev/null +++ b/plugins/weather/jisp/icondef.xml @@ -0,0 +1,248 @@ + + + + SIM weather icons + 0.9.6 + SIM weather icons. + Vladimir Shutoff + 2004-06-11 + http://sim-im.org/ + + + 0.png + + + 1.png + + + 2.png + + + 3.png + + + 4.png + + + 5.png + + + 6.png + + + 7.png + + + 8.png + + + 9.png + + + 10.png + + + 11.png + + + 12.png + + + 13.png + + + 14.png + + + 15.png + + + 16.png + + + 17.png + + + 18.png + + + 19.png + + + 20.png + + + 21.png + + + 22.png + + + 23.png + + + 24.png + + + 25.png + + + 26.png + + + 27.png + + + 28.png + + + 29.png + + + 30.png + + + 31.png + + + 32.png + + + 33.png + + + 34.png + + + 35.png + + + 36.png + + + 37.png + + + 38.png + + + 39.png + + + 40.png + + + 41.png + + + 42.png + + + 43.png + + + 44.png + + + 45.png + + + 46.png + + + 47.png + + + na.png + + + m0.png + + + m1.png + + + m2.png + + + m3.png + + + m4.png + + + m5.png + + + m6.png + + + m7.png + + + m8.png + + + m9.png + + + m10.png + + + m11.png + + + m12.png + + + m13.png + + + m14.png + + + m15.png + + + m16.png + + + m17.png + + + m18.png + + + m19.png + + + m20.png + + + m21.png + + + m22.png + + + m23.png + + + m24.png + + + m25.png + + + m26.png + + + m27.png + + + m28.png + + + m29.png + + diff --git a/plugins/weather/jisp/license b/plugins/weather/jisp/license new file mode 100644 index 0000000..72c3cae --- /dev/null +++ b/plugins/weather/jisp/license @@ -0,0 +1 @@ +Unknown-proprietary diff --git a/plugins/weather/jisp/m0.png b/plugins/weather/jisp/m0.png new file mode 100644 index 0000000..73418ee Binary files /dev/null and b/plugins/weather/jisp/m0.png differ diff --git a/plugins/weather/jisp/m1.png b/plugins/weather/jisp/m1.png new file mode 100644 index 0000000..2878123 Binary files /dev/null and b/plugins/weather/jisp/m1.png differ diff --git a/plugins/weather/jisp/m10.png b/plugins/weather/jisp/m10.png new file mode 100644 index 0000000..e0f1778 Binary files /dev/null and b/plugins/weather/jisp/m10.png differ diff --git a/plugins/weather/jisp/m11.png b/plugins/weather/jisp/m11.png new file mode 100644 index 0000000..61a5593 Binary files /dev/null and b/plugins/weather/jisp/m11.png differ diff --git a/plugins/weather/jisp/m12.png b/plugins/weather/jisp/m12.png new file mode 100644 index 0000000..2d4d21f Binary files /dev/null and b/plugins/weather/jisp/m12.png differ diff --git a/plugins/weather/jisp/m13.png b/plugins/weather/jisp/m13.png new file mode 100644 index 0000000..2d4d21f Binary files /dev/null and b/plugins/weather/jisp/m13.png differ diff --git a/plugins/weather/jisp/m14.png b/plugins/weather/jisp/m14.png new file mode 100644 index 0000000..5c5efd2 Binary files /dev/null and b/plugins/weather/jisp/m14.png differ diff --git a/plugins/weather/jisp/m15.png b/plugins/weather/jisp/m15.png new file mode 100644 index 0000000..4018803 Binary files /dev/null and b/plugins/weather/jisp/m15.png differ diff --git a/plugins/weather/jisp/m16.png b/plugins/weather/jisp/m16.png new file mode 100644 index 0000000..b1cf9e7 Binary files /dev/null and b/plugins/weather/jisp/m16.png differ diff --git a/plugins/weather/jisp/m17.png b/plugins/weather/jisp/m17.png new file mode 100644 index 0000000..6927c3c Binary files /dev/null and b/plugins/weather/jisp/m17.png differ diff --git a/plugins/weather/jisp/m18.png b/plugins/weather/jisp/m18.png new file mode 100644 index 0000000..eb64caf Binary files /dev/null and b/plugins/weather/jisp/m18.png differ diff --git a/plugins/weather/jisp/m19.png b/plugins/weather/jisp/m19.png new file mode 100644 index 0000000..eb64caf Binary files /dev/null and b/plugins/weather/jisp/m19.png differ diff --git a/plugins/weather/jisp/m2.png b/plugins/weather/jisp/m2.png new file mode 100644 index 0000000..54c76e4 Binary files /dev/null and b/plugins/weather/jisp/m2.png differ diff --git a/plugins/weather/jisp/m20.png b/plugins/weather/jisp/m20.png new file mode 100644 index 0000000..c770fad Binary files /dev/null and b/plugins/weather/jisp/m20.png differ diff --git a/plugins/weather/jisp/m21.png b/plugins/weather/jisp/m21.png new file mode 100644 index 0000000..c770fad Binary files /dev/null and b/plugins/weather/jisp/m21.png differ diff --git a/plugins/weather/jisp/m22.png b/plugins/weather/jisp/m22.png new file mode 100644 index 0000000..3f20807 Binary files /dev/null and b/plugins/weather/jisp/m22.png differ diff --git a/plugins/weather/jisp/m23.png b/plugins/weather/jisp/m23.png new file mode 100644 index 0000000..feaf3c6 Binary files /dev/null and b/plugins/weather/jisp/m23.png differ diff --git a/plugins/weather/jisp/m24.png b/plugins/weather/jisp/m24.png new file mode 100644 index 0000000..308942d Binary files /dev/null and b/plugins/weather/jisp/m24.png differ diff --git a/plugins/weather/jisp/m25.png b/plugins/weather/jisp/m25.png new file mode 100644 index 0000000..f332944 Binary files /dev/null and b/plugins/weather/jisp/m25.png differ diff --git a/plugins/weather/jisp/m26.png b/plugins/weather/jisp/m26.png new file mode 100644 index 0000000..24eb23b Binary files /dev/null and b/plugins/weather/jisp/m26.png differ diff --git a/plugins/weather/jisp/m27.png b/plugins/weather/jisp/m27.png new file mode 100644 index 0000000..79c2de5 Binary files /dev/null and b/plugins/weather/jisp/m27.png differ diff --git a/plugins/weather/jisp/m28.png b/plugins/weather/jisp/m28.png new file mode 100644 index 0000000..79c2de5 Binary files /dev/null and b/plugins/weather/jisp/m28.png differ diff --git a/plugins/weather/jisp/m29.png b/plugins/weather/jisp/m29.png new file mode 100644 index 0000000..73418ee Binary files /dev/null and b/plugins/weather/jisp/m29.png differ diff --git a/plugins/weather/jisp/m3.png b/plugins/weather/jisp/m3.png new file mode 100644 index 0000000..7091916 Binary files /dev/null and b/plugins/weather/jisp/m3.png differ diff --git a/plugins/weather/jisp/m4.png b/plugins/weather/jisp/m4.png new file mode 100644 index 0000000..a23508c Binary files /dev/null and b/plugins/weather/jisp/m4.png differ diff --git a/plugins/weather/jisp/m5.png b/plugins/weather/jisp/m5.png new file mode 100644 index 0000000..ca652a9 Binary files /dev/null and b/plugins/weather/jisp/m5.png differ diff --git a/plugins/weather/jisp/m6.png b/plugins/weather/jisp/m6.png new file mode 100644 index 0000000..ca652a9 Binary files /dev/null and b/plugins/weather/jisp/m6.png differ diff --git a/plugins/weather/jisp/m7.png b/plugins/weather/jisp/m7.png new file mode 100644 index 0000000..d03cdfe Binary files /dev/null and b/plugins/weather/jisp/m7.png differ diff --git a/plugins/weather/jisp/m8.png b/plugins/weather/jisp/m8.png new file mode 100644 index 0000000..cab0934 Binary files /dev/null and b/plugins/weather/jisp/m8.png differ diff --git a/plugins/weather/jisp/m9.png b/plugins/weather/jisp/m9.png new file mode 100644 index 0000000..3a91c60 Binary files /dev/null and b/plugins/weather/jisp/m9.png differ diff --git a/plugins/weather/jisp/na.png b/plugins/weather/jisp/na.png new file mode 100644 index 0000000..68e74a3 Binary files /dev/null and b/plugins/weather/jisp/na.png differ diff --git a/plugins/weather/weather.cpp b/plugins/weather/weather.cpp new file mode 100644 index 0000000..6236d95 --- /dev/null +++ b/plugins/weather/weather.cpp @@ -0,0 +1,719 @@ +/*************************************************************************** + weather.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "weather.h" +#include "weathercfg.h" + +#include "log.h" +#include "misc.h" +#include "icons.h" +#include "mainwin.h" +#include "unquot.h" +#include "core.h" + +#include "socket/socket.h" +#include "socket/socketfactory.h" +#include "simgui/toolbtn.h" + +#include "profile.h" +#include "profilemanager.h" + +#include +#include + +using namespace SIM; + +const unsigned CHECK1_INTERVAL = 30 * 60; +const unsigned CHECK2_INTERVAL = 120 * 60; + +Plugin *createWeatherPlugin(unsigned base, bool bInit, Buffer *config) +{ + return new WeatherPlugin(base, bInit, config); +} + +static PluginInfo info = + { + I18N_NOOP("Weather"), + I18N_NOOP("Plugin provides show weather"), + VERSION, + createWeatherPlugin, + PLUGIN_NOLOAD_DEFAULT + }; + +EXPORT_PROC PluginInfo* GetPluginInfo() +{ + return &info; +} + +WeatherPlugin::WeatherPlugin(unsigned base, bool bInit, Buffer *config) + : Plugin (base) + , m_bar ( NULL) +{ + m_propertyHub = SIM::PropertyHub::create("weather"); + BarWeather = registerType(); + CmdWeather = registerType(); + EventWeather = (SIM::SIMEvent)registerType(); + m_icons = getIcons()->addIconSet("icons/weather.jisp", true); + EventToolbar(BarWeather, EventToolbar::eAdd).process(); + + Command cmd; + cmd->id = CmdWeather; + cmd->text = I18N_NOOP("Not connected"); + cmd->icon = "weather"; + cmd->bar_id = BarWeather; + cmd->bar_grp = 0x1000; + cmd->flags = BTN_PICT | BTN_DIV; + EventCommandCreate(cmd).process(); + +} + +WeatherPlugin::~WeatherPlugin() +{ + delete m_bar; + EventCommandRemove(CmdWeather).process(); + EventToolbar(BarWeather, EventToolbar::eRemove).process(); + getIcons()->removeIconSet(m_icons); +} + +QByteArray WeatherPlugin::getConfig() +{ + return QByteArray(); +} + +void WeatherPlugin::timeout() +{ + if (!getSocketFactory()->isActive() || !isDone() || value("ID").toString().isEmpty()) + return; + QDateTime now = QDateTime::currentDateTime(); + if ( now < QDateTime::fromTime_t(value("Time").toUInt()).addSecs(CHECK1_INTERVAL) ) + return; + m_bForecast = false; + if ( now >= QDateTime::fromTime_t(value("ForecastTime").toUInt()).addSecs(CHECK2_INTERVAL) ) + m_bForecast = true; + QString url = "http://xoap.weather.com/weather/local/"; + url += value("ID").toString(); + url += "?cc=*&link=xoap&prod=xoap&par=1004517364&key=a29796f587f206b2&unit="; + url += value("Units").toBool() ? "s" : "m"; + if (m_bForecast && value("Forecast").toUInt()){ + url += "&dayf="; + url += QString::number(value("Forecast").toUInt()); + } + fetch(url); +} + +bool WeatherPlugin::processEvent(Event *e) +{ + if (e->type() == eEventLanguageChanged) + updateButton(); + if (e->type() == eEventInit) + showBar(); + if (e->type() == eEventCommandExec) + { + EventCommandExec *ece = static_cast(e); + CommandDef *cmd = ece->cmd(); + if ((cmd->id == CmdWeather) && !value("ID").toString().isEmpty()){ + QString url = "http://www.weather.com/outlook/travel/local/"; + url += value("ID").toString(); + EventGoURL(url).process(); + return true; + } + } + if(e->type() == eEventPluginLoadConfig) + { + PropertyHubPtr hub = ProfileManager::instance()->getPropertyHub("weather"); + if(!hub.isNull()) + setPropertyHub(hub); + showBar(); + if (m_bar) + { + m_bar->setIconSize( QSize( 30, 30 ) ); + m_bar->show(); + } + } + return false; +} + +bool WeatherPlugin::done(unsigned code, Buffer &data, const QString&) +{ + if (code != 200) + return false; + QDomDocument document; + QString errorMsg; + int errorLine; + int errorColumn; + if (!document.setContent(data,false,&errorMsg,&errorLine,&errorColumn)){ + log(L_WARN, "Weather XML parse error '" + errorMsg + "' at line: " + QString::number(errorLine) + ", column:" + QString::number(errorColumn) + ")"); + return false; + } + if( !parse( document ) ) { + return false; + } + unsigned int now = QDateTime::currentDateTime().toTime_t(); + setValue("Time", now); + if (m_bForecast) + setValue("ForecastTime", now); + updateButton(); + Event eUpdate(EventWeather); + eUpdate.process(); + return false; +} + +void WeatherPlugin::barDestroyed() +{ + m_bar = NULL; +} + +void WeatherPlugin::hideBar() +{ + if (m_bar){ + delete m_bar; + m_bar = NULL; + } +} + +bool WeatherPlugin::parseTime(const QString &str, int &h, int &m) +{ + QString s = str; + h = getToken(s, ':').toLong(); + m = getToken(s, ' ').toLong(); + if ((getToken(s, ' ') == "PM") && (h < 12)) + h += 12; + if (h == 24) + h = 0; + return true; +} + +bool WeatherPlugin::parseDateTime(const QString &str, QDateTime &dt) +{ + int h, m, D, M, Y; + QString daytime; + + QString s = str; + /* MM/DD/YY/ hh:mm */ + M = getToken(s, '/').toLong(); + D = getToken(s, '/').toLong(); + Y = getToken(s, ' ').toLong(); + h = getToken(s, ':').toLong(); + m = getToken(s, ' ').toLong(); + + if (getToken(s, ' ') == "PM" && (h < 12)) + h += 12; + /* 12:20 PM is 00:20 and 12:30 AM is 12:20 + but what date is 12:20 pm 4/7/04? */ + if (h == 24) + h = 0; + if (Y < 70) + Y += 2000; + dt.setDate(QDate(Y,M,D)); + dt.setTime(QTime(h,m,0,0)); + return true; +} + +bool WeatherPlugin::isDay() +{ + int raise_h = 0, raise_m = 0; + int set_h = 0, set_m = 0; + if (!parseTime(value("Sun_raise").toString(), raise_h, raise_m) || !parseTime(value("Sun_set").toString(), set_h, set_m)) + return false; + QDateTime now = QDateTime::currentDateTime().toLocalTime(); + if ((now.time().hour() > raise_h) && (now.time().hour() < set_h)) + return true; + if ((now.time().hour() == raise_h) && (now.time().minute() >= raise_m)) + return true; + if ((now.time().hour() == set_h) && (now.time().minute() <= set_m)) + return true; + return false; +} + +void WeatherPlugin::showBar() +{ + if (m_bar || value("ID").toString().isEmpty()) + return; + + CorePlugin *core = GET_CorePlugin(); + MainWindow *main= core->getMainWindow(); + if (main == NULL) + return; + + EventToolbar e(BarWeather, main); + e.process(); + m_bar = e.toolBar(); + m_bar->setObjectName("WeatherToolbar"); + main->addToolBar(Qt::BottomToolBarArea, m_bar); + connect(m_bar, SIGNAL(destroyed()), this, SLOT(barDestroyed())); + QTimer *timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(timeout())); + QTimer::singleShot(0, this, SLOT(timeout())); + timer->start( min( CHECK1_INTERVAL, CHECK2_INTERVAL ) * 1000 ); + updateButton(); +} + +void WeatherPlugin::updateButton() +{ + if ((value("Time").toUInt() == 0) || (m_bar == NULL)) + return; + Command cmd; + cmd->id = CmdWeather; + cmd->text = I18N_NOOP("Not connected"); + cmd->icon = "weather" + QString::number(value("Icon").toUInt()); + cmd->bar_id = BarWeather; + cmd->bar_grp = 0x1000; + cmd->flags = BTN_PICT | BTN_DIV; + EventCommandChange(cmd).process(); + + QString text = unquoteText(getButtonText()); + QString tip = "

%l

\n"; + QString ftip = getForecastText(); + text = replace(text); + tip = replace(tip); + if (value("Forecast").toUInt()) + tip = tip + ""; + tip += "
" + getTipText() + "

" + i18n("weather","Forecast") + ":

"; + unsigned n = (value("Forecast").toUInt() + 1) / 2; + if (n < 3) + n = value("Forecast").toUInt(); + for (unsigned int iDay = 1; iDay <= value("Forecast").toUInt(); iDay++){ + tip += forecastReplace(ftip,iDay); + if (--n == 0){ + tip += ""; + n = (value("Forecast").toUInt() + 1) / 2; + } + } + if (value("Forecast").toUInt()) + tip += "

\n"; + tip += "

"+i18n("weather", "Weather data provided by weather.com®") + "

"; + Command cmdw; + cmdw->id = CmdWeather; + cmdw->param = m_bar; + EventCommandWidget eWidget(cmdw); + eWidget.process(); + CToolButton *btn = qobject_cast(eWidget.widget()); + if (btn == NULL) + return; + btn->setText(text); + btn->repaint(); + btn->setToolTip(tip); +} + +#if 0 +i18n("Monday") +i18n("Tuesday") +i18n("Wednesday") +i18n("Thursday") +i18n("Friday") +i18n("Saturday") +i18n("Sunday") + +i18n("weather", "Squalls") +i18n("weather", "Overcast") +i18n("weather", "Fog") +i18n("weather", "Foggy") +i18n("weather", "Mist") +i18n("weather", "Haze") +i18n("weather", "Storm") +i18n("weather", "T-Storm") +i18n("weather", "T-Storms") +i18n("weather", "Scattered T-Storms") +i18n("weather", "Thunder") +i18n("weather", "Light Rain with Thunder") +i18n("weather", "Thunder in the Vicinity") +i18n("weather", "Rain") +i18n("weather", "Light Rain") +i18n("weather", "Heavy Rain") +i18n("weather", "Freezing Rain") +i18n("weather", "Rain to Snow") +i18n("weather", "Snow") +i18n("weather", "Light Snow") +i18n("weather", "Few Snow") +i18n("weather", "Scattered Snow") +i18n("weather", "Ice Crystals") +i18n("weather", "Sleet") +i18n("weather", "Clear") +i18n("weather", "Clearing") +i18n("weather", "Showers") +i18n("weather", "Showers in the Vicinity") +i18n("weather", "Mostly Clear") +i18n("weather", "Sunny") +i18n("weather", "Fair") +i18n("weather", "Cloudy") +i18n("weather", "Clouds") +i18n("weather", "Mostly Cloudy") +i18n("weather", "Partly Cloudy") +i18n("weather", "Wind") +i18n("weather", "Windy") +i18n("weather", "Drizzle") +i18n("weather", "Heavy Drizzle") +i18n("weather", "Freezing Drizzle") +i18n("weather", "Freezing Rain") +i18n("weather", "Light Drizzle") +i18n("weather", "Drifting Snow") +i18n("weather", "Snow Grains") +i18n("weather", "Light Snow Grains") +i18n("weather", "Scattered") +i18n("weather", "Smoke") +i18n("weather", "steady") +i18n("weather", "rising") +i18n("weather", "falling") +i18n("weather", "Unlimited") + +i18n("weather", "N") +i18n("weather", "NNW") +i18n("weather", "NW") +i18n("weather", "WNW") +i18n("weather", "W") +i18n("weather", "WSW") +i18n("weather", "SW") +i18n("weather", "SSW") +i18n("weather", "S") +i18n("weather", "SSE") +i18n("weather", "SE") +i18n("weather", "ESE") +i18n("weather", "E") +i18n("weather", "ENE") +i18n("weather", "NE") +i18n("weather", "NNE") +i18n("weather", "VAR") +i18n("weather", "CALM") + +i18n("weather", "km") +i18n("weather", "mi") +i18n("weather", "km/h") +i18n("weather", "mph") +i18n("weather", "mmHg"); +i18n("weather", "inHg"); + +i18n("weather", "Low") +i18n("weather", "Moderate") +i18n("weather", "High") + +i18n("moonphase", "New") +i18n("moonphase", "Waxing Crescent") +i18n("moonphase", "First Quarter") +i18n("moonphase", "Waxing Gibbous") +i18n("moonphase", "Full") +i18n("moonphase", "Waning Gibbous") +i18n("moonphase", "Last Quarter") +i18n("moonphase", "Waning Crescent") +#endif + +static QString i18n_conditions(const QString &str) +{ + if (str.isEmpty()) + return QString(); + int n = str.indexOf(" / "); + if (n >= 0) + return i18n_conditions(str.left(n)) + " / " + i18n_conditions(str.mid(n + 3)); + n = str.indexOf(" and "); + if (n >= 0) + return i18n_conditions(str.left(n)) + " " + i18n("and") + " " + i18n_conditions(str.mid(n + 5)); + n = str.indexOf(" Early"); + if (n >= 0) + return i18n_conditions(str.left(n)) + " " + i18n("weather", "Early"); + n = str.indexOf(" Late"); + if (n >= 0) + return i18n_conditions(str.left(n)) + " " + i18n("weather", "Late"); + QString s = str; + s = s.remove(" Showers"); + s = s.remove(" Shower"); + return i18n("weather", s); +} + +QString WeatherPlugin::replace(const QString &text) +{ + QString res = text; + QString sun_set, sun_raise, updated; + QTime tmp_time; + QDateTime dt; + int h,m; + + parseTime(value("Sun_set").toString(),h,m); + tmp_time.setHMS(h,m,0,0); + sun_set = tmp_time.toString(Qt::LocalDate); + sun_set = sun_set.left(sun_set.length() - 3); + + parseTime(value("Sun_raise").toString(),h,m); + tmp_time.setHMS(h,m,0,0); + sun_raise = tmp_time.toString(Qt::LocalDate); + sun_raise = sun_raise.left(sun_raise.length() - 3); + + parseDateTime(value("Updated").toString(),dt); + updated = dt.toString(Qt::LocalDate); + updated = updated.left(updated.length() - 3); + /* double Expressions *before* single or better RegExp ! */ + res = res.replace(QRegExp("\\%mp"), i18n("moonphase", value("MoonPhase").toString())); + res = res.replace(QRegExp("\\%mi"), QString::number(value("MoonIcon").toInt())); + res = res.replace(QRegExp("\\%pp"), QString::number(value("Precipitation").toInt())); + res = res.replace(QRegExp("\\%ut"), i18n("weather", value("UV_Description").toString())); + res = res.replace(QRegExp("\\%ui"), QString::number(value("UV_Intensity").toUInt())); + res = res.replace(QRegExp("\\%t"), QString::number((int)value("Temperature").toInt()) + QChar((unsigned short)176) + value("UT").toString()); + res = res.replace(QRegExp("\\%f"), QString::number((int)value("FeelsLike").toInt()) + QChar((unsigned short)176) + value("UT").toString()); + res = res.replace(QRegExp("\\%d"), QString::number((int)value("DewPoint").toInt()) + QChar((unsigned short)176) + value("UT").toString()); + res = res.replace(QRegExp("\\%h"), QString::number(value("Humidity").toInt()) + "%"); + res = res.replace(QRegExp("\\%w"), QString::number(value("Wind_speed").toInt()) + " " + i18n("weather",value("US").toString())); + res = res.replace(QRegExp("\\%x"), QString::number(value("Wind_speed").toInt() * 10 / 36) + " " + i18n("m/s")); + res = res.replace(QRegExp("\\%g"), value("WindGust").toInt() ? QString("(") + i18n("gust") + QString(" ") + QString::number(value("WindGust").toUInt()) + i18n("weather",value("US").toString()) + QString(")") : QString("")); + res = res.replace(QRegExp("\\%y"), value("WindGust").toInt() ? QString("(") + i18n("gust") + QString(" ") + QString::number(value("WindGust").toInt() * 10 / 36) + QString(" ") + i18n("m/s") + QString(")") : QString("")); + res = res.replace(QRegExp("\\%p"), QString::number(value("Pressure").toInt()) + " " + i18n("weather", value("UP").toString())); + res = res.replace(QRegExp("\\%a"), QString::number(value("Pressure").toInt() * 75 / 100)); // deprecated! + res = res.replace(QRegExp("\\%q"), i18n("weather", value("PressureD").toString())); + res = res.replace(QRegExp("\\%l"), value("Location").toString()); + res = res.replace(QRegExp("\\%b"), i18n("weather", value("Wind").toString())); + res = res.replace(QRegExp("\\%u"), updated); + res = res.replace(QRegExp("\\%r"), sun_raise); + res = res.replace(QRegExp("\\%s"), sun_set); + res = res.replace(QRegExp("\\%c"), i18n_conditions(value("Conditions").toString())); + res = res.replace(QRegExp("\\%v"), i18n("weather", value("Visibility").toString()) + (value("Visibility").toUInt() ? ' ' + i18n("weather",value("UD").toString()) : QString())); + res = res.replace(QRegExp("\\%i"), QString::number(value("Icon").toUInt())); + res = res.replace(QRegExp("\\%o"), value("Obst").toString()); + return res; +} + +QString WeatherPlugin::forecastReplace(const QString &text, int iDay) +{ + QString sDay = QString::number(iDay); + if (value("Day").toMap().value(sDay).toString().isEmpty()) + return QString(); + QString res = text; + QString temp; + int minT = value("MinT").toMap().value(sDay).toInt(); + int maxT = value("MaxT").toMap().value(sDay).toInt(); + temp += QString::number(minT); + temp += QChar((unsigned short)176); + temp += value("UT").toString(); + if ((value("MaxT").toMap().value(sDay).toString() != QLatin1String("N/A")) && (maxT != -255)) { + temp += '/'; + temp += QString::number(maxT); + temp += QChar((unsigned short)176); + temp += value("UT").toString(); + } + QString dd = value("Day").toMap().value(sDay).toString(); + QString mon = getToken(dd, ' '); + QString day = dd; + day += ". "; + day += i18n(mon); + res = res.replace(QRegExp("\\%n"), value("DayIcon").toMap().value(sDay).toString()); + res = res.replace(QRegExp("\\%t"), temp); + res = res.replace(QRegExp("\\%c"), i18n_conditions(value("DayConditions").toMap().value(sDay).toString())); + res = res.replace(QRegExp("\\%w"), i18n(value("WDay").toMap().value(sDay).toString())); + res = res.replace(QRegExp("\\%d"), day); + return res; +} + +QString WeatherPlugin::getButtonText() +{ + QString str = value("Text").toString(); + if (str.isEmpty()) + str = i18n("%t | %c"); + return str; +} + +#define WIATHER_ICON_SIZE (93) + +QString WeatherPlugin::getTipText() +{ + QString str = value("Tip").toString(); + if (str.isEmpty()) + str = + "

"+i18n("weather","Current Weather")+":

\n" + "


%c
\n"+ + i18n("weather","Temperature")+": %t ("+i18n("weather","feels like")+": %f)
\n"+ + i18n("weather","Humidity")+": %h
\n"+ + i18n("weather","Chance of Precipitation")+": %pp%
\n"+ + i18n("weather","Pressure")+": %p (%q)
\n"+ + i18n("weather","Wind")+": %b %w %g
\n"+ + i18n("weather","Visibility")+": %v
\n"+ + i18n("weather","Dew Point")+": %d
\n"+ + i18n("weather","Sunrise")+": %r
\n"+ + i18n("weather","Sunset")+": %s
\n"+ + i18n("weather","UV-Intensity is %ut with value %ui (of 11)")+"
\n" + ""+i18n("weather","Moonphase")+": %mp
\n" + "
\n" + "
\n"+ + i18n("weather","Updated")+": %u
\n"; + return str; +} + +QString WeatherPlugin::getForecastText() +{ + QString str = value("ForecastTip").toString(); + if (str.isEmpty()) + str = i18n("

%d %w


\n" + "
%c
\n" + "Temperature: %t
\n"); + + return str; +} + +QWidget *WeatherPlugin::createConfigWindow(QWidget *parent) +{ + return new WeatherCfg(parent, this); +} + +QString WeatherPlugin::GetSubElementText( + QDomElement element, + QString sSubElement, + QString sDefault /*= QString()*/ +) { + QString sResult = sDefault; + + do { + if( element.isNull() ) + break; + + QDomNodeList list = element.elementsByTagName(sSubElement); + if( list.count() <= 0 ) + break; + + //QDomNode::NodeType t = list.item(0).nodeType(); //unused + QDomElement subElement = list.item(0).toElement(); + sResult = subElement.firstChild().toCharacterData().data(); + } while( false ); + + return sResult; +} + +bool WeatherPlugin::parse(QDomDocument document) +{ + QDomElement weatherElement = document.documentElement(); + +// Parsing head element + QDomElement headElement = weatherElement.elementsByTagName("head").item(0).toElement(); + setValue("UT", GetSubElementText( headElement, "ut", "### Failed ###" ) ); + QString sUp = GetSubElementText( headElement, "up", "### Failed ###" ); + if( sUp == "in" ) { + setValue("UP", "inHg"); + } + else { + setValue("UP", sUp); + } + setValue("US", GetSubElementText( headElement, "us", "### Failed ###" ) ); + setValue("UD", GetSubElementText( headElement, "ud", "### Failed ###" ) ); + +// Parsing loc element + QDomElement locElement = weatherElement.elementsByTagName("loc").item(0).toElement(); + setValue("Location", GetSubElementText( locElement, "dnam", "### Failed ###" ) ); + setValue("Sun_raise", GetSubElementText( locElement, "sunr", "### Failed ###" ) ); + setValue("Sun_set", GetSubElementText( locElement, "suns", "### Failed ###" ) ); + +// Parsing cc element + QDomElement ccElement = weatherElement.elementsByTagName("cc").item(0).toElement(); + setValue("Obst", GetSubElementText( ccElement, "obst", "### Failed ###" ) ); + setValue("Updated", GetSubElementText( ccElement, "lsup", "### Failed ###" ) ); + setValue("Temperature", (int)GetSubElementText( ccElement, "tmp", "-10000" ).toLong() ); + setValue("FeelsLike", (int)GetSubElementText( ccElement, "flik", "-10000" ).toLong() ); + setValue("Visibility", GetSubElementText( ccElement, "vis", "### Failed ###" ) ); + setValue("DewPoint", (int)GetSubElementText( ccElement, "dewp", "-10000" ).toLong() ); + setValue("Humidity", (int)GetSubElementText( ccElement, "hmid", "-10000" ).toLong() ); + setValue("Conditions", GetSubElementText( ccElement, "t", "### Failed ###" ) ); + setValue("Icon", (unsigned int)GetSubElementText( ccElement, "icon", "0" ).toLong() ); + // Parsing cc/moon element + { + QDomElement subElement = ccElement.elementsByTagName("moon").item(0).toElement(); + setValue("MoonPhase", GetSubElementText( subElement, "t", "### Failed ###" ) ); + setValue("MoonIcon", (int)GetSubElementText( subElement, "icon", "0" ).toLong() ); + } + // Parsing cc/bar element + { + QDomElement subElement = ccElement.elementsByTagName("bar").item(0).toElement(); + float v = GetSubElementText( subElement, "r", "-10000" ).toFloat(); + if ( QString(value("UP").toString()) == "mb" ){ + v=v * 75 / 100; + setValue("Pressure", v); + setValue("UP", "mmHg"); + } else{ + setValue("Pressure", v); + } + setValue("PressureD", GetSubElementText( subElement, "d", "### Failed ###" ) ); + } + // Parsing cc/wind element + { + QDomElement subElement = ccElement.elementsByTagName("wind").item(0).toElement(); + setValue("Wind", GetSubElementText( subElement, "t", "### Failed ###" ) ); + setValue("WindGust", (int)GetSubElementText( subElement, "gust", "-10000" ).toLong() ); + setValue("Wind_speed", (int)GetSubElementText( subElement, "s", "-10000" ).toLong() ); + // wind/d dropped for now ! + } + // Parsing cc/uv element + { + QDomElement subElement = ccElement.elementsByTagName("uv").item(0).toElement(); + setValue("UV_Description", GetSubElementText( subElement, "t", "### Failed ###" ) ); + setValue("UV_Intensity", (int)GetSubElementText( subElement, "i", "-10000" ).toLong() ); + } + +// Parsing dayf element + QDomElement dayfElement = weatherElement.elementsByTagName("dayf").item(0).toElement(); + QDomNodeList list = dayfElement.elementsByTagName("day"); + for( int iDay = 0 ; iDay < list.count() ; iDay++ ) { + QDomElement dayElement = list.item(iDay).toElement(); +// dayElement.attribute("d").toLong(); + QVariantMap day = value("Day").toMap(); + day.insert(QString::number(iDay), dayElement.attribute("dt")); + setValue("Day", day); + + QVariantMap wday = value("WDay").toMap(); + wday.insert(QString::number(iDay), dayElement.attribute("t")); + setValue("WDay", wday); + + QVariantMap mint = value("MinT").toMap(); + mint.insert(QString::number(iDay), GetSubElementText(dayElement, "low", "### Failed ###")); + setValue("MinT", mint); + + QVariantMap maxt = value("MaxT").toMap(); + maxt.insert(QString::number(iDay), GetSubElementText(dayElement, "hi", "### Failed ###")); + setValue("MaxT", maxt); + + QDomNodeList listParts = dayElement.elementsByTagName("part"); + for( int iPart = 0 ; iPart < listParts.count() ; iPart++ ) { + QDomElement partElement = listParts.item(iPart).toElement(); + if( partElement.attribute("p") == "d" ) { + QVariantMap dayc = value("DayConditions").toMap(); + dayc.insert(QString::number(iDay), GetSubElementText( partElement, "t", "### Failed ###" )); + setValue("DayConditions", dayc); + + QVariantMap dayi = value("DayIcon").toMap(); + dayi.insert(QString::number(iDay), GetSubElementText(partElement, "icon", "na")); + setValue("DayIcon", dayi); + } + } + } + + return true; +} + +void WeatherPlugin::setPropertyHub(SIM::PropertyHubPtr hub) +{ + m_propertyHub = hub; +} + +SIM::PropertyHubPtr WeatherPlugin::propertyHub() +{ + return m_propertyHub; +} + +QVariant WeatherPlugin::value(const QString& key) +{ + return m_propertyHub->value(key); +} + +void WeatherPlugin::setValue(const QString& key, const QVariant& v) +{ + m_propertyHub->setValue(key, v); +} diff --git a/plugins/weather/weather.h b/plugins/weather/weather.h new file mode 100644 index 0000000..869fff6 --- /dev/null +++ b/plugins/weather/weather.h @@ -0,0 +1,83 @@ +/*************************************************************************** + weather.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _WEATHER_H +#define _WEATHER_H + +#include "propertyhub.h" +#include "plugins.h" +#include "fetch.h" +#include "event.h" + +class QToolBar; +class QDomDocument; +class QDomElement; + +namespace SIM +{ +class IconSet; +} + +class WeatherPlugin : public QObject, public SIM::Plugin, public SIM::EventReceiver, public FetchClient +{ + Q_OBJECT +public: + WeatherPlugin(unsigned, bool, Buffer*); + virtual ~WeatherPlugin(); + QString getButtonText(); + QString getTipText(); + QString getForecastText(); + void updateButton(); + void showBar(); + void hideBar(); + SIM::SIMEvent EventWeather; + QToolBar *m_bar; + + void setPropertyHub(SIM::PropertyHubPtr hub); + SIM::PropertyHubPtr propertyHub(); + QVariant value(const QString& key); + void setValue(const QString& key, const QVariant& v); +protected slots: + void timeout(); + void barDestroyed(); +protected: + QString replace(const QString&); + QString forecastReplace(const QString&, int iDay); + unsigned long BarWeather; + unsigned long CmdWeather; + char m_bForecast; + virtual QByteArray getConfig(); + bool isDay(); + bool parseTime(const QString &str, int &h, int &m); + bool parseDateTime(const QString &str, QDateTime &dt); + virtual QWidget *createConfigWindow(QWidget *parent); + virtual bool done(unsigned code, Buffer &data, const QString &headers); + virtual bool processEvent(SIM::Event *e); + SIM::IconSet *m_icons; + + bool parse(QDomDocument document); + QString GetSubElementText( + QDomElement element, + QString sSubElement, + QString sDefault = QString() + ); +private: + SIM::PropertyHubPtr m_propertyHub; +}; + +#endif + diff --git a/plugins/weather/weather.rc b/plugins/weather/weather.rc new file mode 100644 index 0000000..3142c0a --- /dev/null +++ b/plugins/weather/weather.rc @@ -0,0 +1,97 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,9,6,0 + PRODUCTVERSION 0,9,6,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Vladimir Shutoff\0" + VALUE "FileDescription", "Weather plugin\0" + VALUE "FileVersion", "0, 9, 6, 0\0" + VALUE "InternalName", "weather\0" + VALUE "LegalCopyright", "Copyright © 2002-2003\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "weather.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "SIM\0" + VALUE "ProductVersion", "0, 9, 6, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/weather/weather.vcproj b/plugins/weather/weather.vcproj new file mode 100644 index 0000000..43af3dd --- /dev/null +++ b/plugins/weather/weather.vcproj @@ -0,0 +1,848 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/weather/weathercfg.cpp b/plugins/weather/weathercfg.cpp new file mode 100644 index 0000000..fb2b397 --- /dev/null +++ b/plugins/weather/weathercfg.cpp @@ -0,0 +1,158 @@ +/*************************************************************************** + weathercfg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "weathercfg.h" + +#include "wifacecfg.h" +#include "weather.h" + +#include "log.h" +#include "misc.h" + +#include "simgui/ballonmsg.h" + +#include +#include +#include + +using namespace SIM; + +WeatherCfg::WeatherCfg(QWidget *parent, WeatherPlugin *plugin) + : QWidget(parent), m_iface(0) +{ + setupUi(this); + m_plugin = plugin; + lblLnk->setUrl("http://www.weather.com/?prod=xoap&par=1004517364"); + lblLnk->setText(QString("Weather data provided by weather.com") + QChar((unsigned short)174)); + connect(btnSearch, SIGNAL(clicked()), this, SLOT(search())); + connect(cmbLocation->lineEdit(), SIGNAL(textChanged(const QString&)), this, SLOT(textChanged(const QString&))); + connect(cmbLocation, SIGNAL(activated(int)), this, SLOT(activated(int))); + textChanged(QString()); + fill(); + for (QObject *p = parent; p != NULL; p = p->parent()){ + QTabWidget *tab = qobject_cast(p); + if(!tab) + continue; + m_iface = new WIfaceCfg(tab, plugin); + tab->addTab(m_iface, i18n("Interface")); + tab->adjustSize(); + break; + } +} + +WeatherCfg::~WeatherCfg() +{ +// do not delete - it gets deleted when QTabWidget (=parent) goes away +// delete m_iface; +} + +void WeatherCfg::textChanged(const QString &text) +{ + btnSearch->setEnabled(!text.isEmpty() && isDone()); +} + +void WeatherCfg::search() +{ + if (!isDone()){ + stop(); + btnSearch->setText(i18n("&Search")); + textChanged(cmbLocation->lineEdit()->text()); + return; + } + if (cmbLocation->lineEdit()->text().isEmpty()) + return; + btnSearch->setText(i18n("&Cancel")); + QString url = "http://xoap.weather.com/search/search?where="; + url += toTranslit(cmbLocation->lineEdit()->text()); + fetch(url); +} + +bool WeatherCfg::done(unsigned, Buffer &data, const QString&) +{ + m_ids.clear(); + m_names.clear(); + QDomDocument doc; + if( !doc.setContent(data) ) { + log(L_WARN, "XML parse error"); + } + QDomElement el = doc.firstChildElement( "search" ); + if( !el.isNull() ) { + el = el.firstChildElement( "loc" ); + while( !el.isNull() ) { + QString sId = el.attribute( "id" ); + QString sLocation = el.text(); + m_ids.append(sId); + m_names.append(sLocation); + el = el.nextSiblingElement( "loc" ); + } + } + btnSearch->setText(i18n("&Search")); + QString oldText = cmbLocation->lineEdit()->text(); + cmbLocation->clear(); + if (m_ids.empty()){ + cmbLocation->lineEdit()->setText(oldText); + BalloonMsg::message(i18n("Location %1 not found") .arg(oldText), btnSearch, false); + }else{ + cmbLocation->addItems(m_names); + cmbLocation->setCurrentIndex(0); + activated(0); + } + textChanged(cmbLocation->lineEdit()->text()); + return false; +} + +bool WeatherCfg::processEvent(Event *e) +{ + if (e->type() == m_plugin->EventWeather) + fill(); + return false; +} + +void WeatherCfg::fill() +{ + edtID->setText(m_plugin->value("ID").toString()); + cmbUnits->setCurrentIndex(m_plugin->value("Units").toBool() ? 1 : 0); + cmbLocation->lineEdit()->setText(m_plugin->value("Location").toString()); + edtDays->setValue(m_plugin->value("Forecast").toUInt()); +} + +void WeatherCfg::activated(int n) +{ + if (n >= m_ids.size()) + return; + edtID->setText(m_ids[n]); +} + +void WeatherCfg::apply() +{ + m_plugin->setValue("Units", cmbUnits->currentIndex() != 0); + m_plugin->setValue("Forecast", (unsigned int)edtDays->text().toULong()); + m_plugin->setValue("ID", edtID->text()); + m_plugin->setValue("Location", cmbLocation->lineEdit()->text()); + m_iface->apply(); + if (!m_plugin->value("ID").toString().isEmpty()){ + m_plugin->showBar(); + m_plugin->updateButton(); + if (m_plugin->m_bar) + m_plugin->m_bar->show(); + m_plugin->setValue("Time", 0); + m_plugin->setValue("ForecastTime", 0); + QTimer::singleShot(0, m_plugin, SLOT(timeout())); + }else{ + m_plugin->hideBar(); + } +} diff --git a/plugins/weather/weathercfg.h b/plugins/weather/weathercfg.h new file mode 100644 index 0000000..a7310c2 --- /dev/null +++ b/plugins/weather/weathercfg.h @@ -0,0 +1,51 @@ +/*************************************************************************** + weathercfg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _WEATHERCFG_H +#define _WEATHERCFG_H + +#include "event.h" +#include "fetch.h" + +#include "ui_weathercfgbase.h" + +class WeatherPlugin; +class WIfaceCfg; + +class WeatherCfg : public QWidget, public Ui::WeatherCfgBase, public SIM::EventReceiver, public FetchClient +{ + Q_OBJECT +public: + WeatherCfg(QWidget *parent, WeatherPlugin*); + ~WeatherCfg(); +public slots: + void apply(); + void search(); + void activated(int index); + void textChanged(const QString&); +protected: + bool done(unsigned code, Buffer &data, const QString &headers); + virtual bool processEvent(SIM::Event *e); + void fill(); + WeatherPlugin *m_plugin; + WIfaceCfg *m_iface; + QStringList m_ids; + QStringList m_names; +}; + +#endif + diff --git a/plugins/weather/weathercfgbase.ui b/plugins/weather/weathercfgbase.ui new file mode 100644 index 0000000..6203efc --- /dev/null +++ b/plugins/weather/weathercfgbase.ui @@ -0,0 +1,215 @@ + + WeatherCfgBase + + + + 0 + 0 + 337 + 196 + + + + Form1 + + + + 11 + + + 6 + + + + + 0 + + + 6 + + + + + Location ID: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + 1 + 0 + 0 + 0 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + + 0 + + + 6 + + + + + + 7 + 0 + 0 + 0 + + + + true + + + + + + + &Search + + + + + + + + + You can enter ID as part URL for your location on weather.com + + + false + + + + + + + + + + 0 + + + 6 + + + + + + Metric + + + + + Standart + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + 10 + + + + + + + Forecast days: + + + false + + + + + + + Units: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + LinkLabel + QWidget +
simgui/linklabel.h
+
+
+ + +
diff --git a/plugins/weather/wifacecfg.cpp b/plugins/weather/wifacecfg.cpp new file mode 100644 index 0000000..5d1123a --- /dev/null +++ b/plugins/weather/wifacecfg.cpp @@ -0,0 +1,129 @@ +/*************************************************************************** + wifacecfg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "wifacecfg.h" + +#include "weather.h" + +#include "misc.h" +#include "unquot.h" +#include "simgui/ballonmsg.h" + +using namespace SIM; + +static const char *helpList[] = + { + "%t", + I18N_NOOP("Temperature"), + "%f", + I18N_NOOP("Feels like"), + "%h", + I18N_NOOP("Humidity"), + "%b", + I18N_NOOP("Wind direction"), + "%w", + I18N_NOOP("Wind speed"), + "%g", + I18N_NOOP("Wind gust"), + "%x", + I18N_NOOP("Wind speed (m/s)"), + "%y", + I18N_NOOP("Wind gust (m/s)"), + "%p", + I18N_NOOP("Pressure"), + "%q", + I18N_NOOP("Pressure state"), + "%v", + I18N_NOOP("Visibility"), + "%d", + I18N_NOOP("Dew Point"), + "%l", + I18N_NOOP("Location"), + "%u", + I18N_NOOP("Updated"), + "%r", + I18N_NOOP("Sunraise"), + "%s", + I18N_NOOP("Sunset"), + "%c", + I18N_NOOP("Conditions"), + "%o", + I18N_NOOP("Obst"), + NULL + }; + +static const char *helpForecastList[] = + { + "%t", + I18N_NOOP("Temperature"), + "%n", + I18N_NOOP("Number"), + "%w", + I18N_NOOP("Day of week"), + "%d", + I18N_NOOP("Date"), + "%c", + I18N_NOOP("Conditions"), + NULL + }; + +WIfaceCfg::WIfaceCfg(QWidget *parent, WeatherPlugin *plugin) + : QWidget(parent) +{ + setupUi(this); + m_plugin = plugin; + setButtonsPict(this); + edtText->setText(unquoteText(m_plugin->getButtonText())); + edtTip->setPlainText(m_plugin->getTipText()); + edtForecastTip->setPlainText(m_plugin->getForecastText()); + edtText->setHelpList(helpList); + edtTip->setHelpList(helpList); + edtForecastTip->setHelpList(helpForecastList); + connect(btnHelp, SIGNAL(clicked()), this, SLOT(help())); +} + +WIfaceCfg::~WIfaceCfg() +{ +} + +void WIfaceCfg::apply() +{ + if (edtText->text() != unquoteText(m_plugin->getButtonText())){ + m_plugin->setValue("Text", edtText->text()); + } + if (edtTip->toPlainText() != m_plugin->getTipText()){ + m_plugin->setValue("Tip", edtTip->toPlainText()); + } + if (edtForecastTip->toPlainText() != m_plugin->getForecastText()){ + m_plugin->setValue("ForecastTip", edtForecastTip->toPlainText()); + } +} + +void WIfaceCfg::help() +{ + QString str = i18n("In text you can use:"); + str += "\n\n"; + for (const char **p = helpList; *p;){ + str += *(p++); + str += " - "; + str += unquoteText(i18n(*(p++))); + str += "\n"; + } + BalloonMsg::message(str, btnHelp, false, 400); +} + + diff --git a/plugins/weather/wifacecfg.h b/plugins/weather/wifacecfg.h new file mode 100644 index 0000000..ee9bcd2 --- /dev/null +++ b/plugins/weather/wifacecfg.h @@ -0,0 +1,39 @@ +/*************************************************************************** + wifacecfg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _WIFACECFG_H +#define _WIFACECFG_H + +#include "ui_wifacecfgbase.h" + +class WeatherPlugin; + +class WIfaceCfg : public QWidget, public Ui::WIfaceCfgBase +{ + Q_OBJECT +public: + WIfaceCfg(QWidget *parent, WeatherPlugin*); + virtual ~WIfaceCfg(); +public slots: + void apply(); + void help(); +protected: + WeatherPlugin *m_plugin; +}; + +#endif + diff --git a/plugins/weather/wifacecfgbase.ui b/plugins/weather/wifacecfgbase.ui new file mode 100644 index 0000000..5338adc --- /dev/null +++ b/plugins/weather/wifacecfgbase.ui @@ -0,0 +1,106 @@ + + + WIfaceCfgBase + + + + 0 + 0 + 371 + 236 + + + + Form1 + + + + 11 + + + + + + + Button text: + + + false + + + + + + + + + + + + Button tip: + + + false + + + + + + + + + + Forecast tip: + + + false + + + + + + + + + + + + &Help + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + + + LineEdit + QWidget +
simgui/editfile.h
+
+ + MultiLineEdit + QWidget +
simgui/editfile.h
+
+
+ + +
diff --git a/plugins/windock/CMakeLists.txt b/plugins/windock/CMakeLists.txt new file mode 100644 index 0000000..0266402 --- /dev/null +++ b/plugins/windock/CMakeLists.txt @@ -0,0 +1,24 @@ +IF(BUILD_DROPPED) +IF(WIN32) + ################### + # windock library # + ################### + SET(windock_SRCS + windock.cpp + ) + + SET(windock_HDRS + windock.h + ) + + # some needed include dirs + INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/plugins/ontop) + + REMOVE_DEFINITIONS(-DQT3_SUPPORT) + REMOVE_DEFINITIONS(-DQT_3SUPPORT_LIB) + REMOVE_DEFINITIONS(-DQT3_SUPPORT_WARNINGS) + SIM_ADD_PLUGIN(windock) +ELSE(WIN32) + MESSAGE(STATUS "Windock plugin can only be used on windows") +ENDIF(WIN32) +ENDIF(BUILD_DROPPED) diff --git a/plugins/windock/configure.in.in b/plugins/windock/configure.in.in new file mode 100644 index 0000000..3038590 --- /dev/null +++ b/plugins/windock/configure.in.in @@ -0,0 +1 @@ +AM_CONDITIONAL(ENABLE_WINDOCK, test "$kde_use_qt_win" = "yes") diff --git a/plugins/windock/windock.cpp b/plugins/windock/windock.cpp new file mode 100644 index 0000000..79729ae --- /dev/null +++ b/plugins/windock/windock.cpp @@ -0,0 +1,535 @@ +/*************************************************************************** + windock.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include + +#include +#include +#include +#include + +#include "misc.h" + +#include "windock.h" +#include "ontop.h" +#include "core.h" +#include "core_consts.h" +#include "mainwin.h" + +using namespace std; +using namespace SIM; + +const unsigned short ABE_FLOAT = USHRT_MAX; + +static WinDockPlugin *dock = NULL; + +Plugin *createWinDockPlugin(unsigned base, bool, Buffer *config) +{ + Plugin *plugin = new WinDockPlugin(base, config); + return plugin; +} + +static PluginInfo info = + { + I18N_NOOP("Dock"), + I18N_NOOP("Plugin provides dock main window to left or right side of screen"), + VERSION, + createWinDockPlugin, + 0 + }; + +EXPORT_PROC PluginInfo* GetPluginInfo() +{ + return &info; +} + +static QWidget *pMain = NULL; +static UINT WM_APPBAR = 0; +static WNDPROC oldProc = NULL; +static bool bOldVisible = true; +static bool bAutoHideVisible = true; +static bool bFullScreen = false; +static bool bMoving = false; +static bool bSizing = false; + +UINT appBarMessage(DWORD dwMessage, UINT uEdge=ABE_FLOAT, LPARAM lParam=0, QRect *rc=NULL) +{ + APPBARDATA abd; + abd.cbSize = sizeof(abd); + abd.hWnd = pMain->winId(); + abd.uCallbackMessage = WM_APPBAR; + abd.uEdge = uEdge; + if (rc) + { + abd.rc.left = rc->left(); + abd.rc.top = rc->top(); + abd.rc.right = rc->right(); + abd.rc.bottom = rc->bottom(); + } + else + { + abd.rc.left = 0; + abd.rc.top = 0; + abd.rc.right = 0; + abd.rc.bottom = 0; + } + abd.lParam = lParam; + UINT uRetVal = SHAppBarMessage(dwMessage, &abd); + + if (rc != NULL) + rc->setCoords(abd.rc.left, abd.rc.top, abd.rc.right, abd.rc.bottom); + return uRetVal; +} + +static unsigned short getEdge(RECT *rcWnd = NULL) +{ + RECT rc; + if (!rcWnd) + { + GetWindowRect(pMain->winId(), &rc); + rcWnd = &rc; + } + if (rcWnd->left <= 0) + return ABE_LEFT; + if (rcWnd->right >= GetSystemMetrics(SM_CXSCREEN)) + return ABE_RIGHT; + return ABE_FLOAT; +} + +static void getBarRect(UINT state, QRect &rc, RECT *rcWnd = NULL) +{ + RECT rcWork; + SystemParametersInfoA(SPI_GETWORKAREA, 0, &rcWork, 0); + rc.setCoords(0, rcWork.top, GetSystemMetrics(SM_CXSCREEN), rcWork.bottom); + appBarMessage(ABM_QUERYPOS, state, FALSE, &rc); + int w; + if (rcWnd) + w = rcWnd->right - rcWnd->left; + else + { + GetWindowRect(pMain->winId(), &rcWork); +#ifdef WIN32 + w = rcWork.right - rcWork.left-1; +#else + w = rcWork.right - rcWork.left; +#endif + } + switch (state) + { + case ABE_LEFT: + rc.setRight(rc.left() + w); + break; + case ABE_RIGHT: + rc.setLeft(rc.right() - w); + break; + } +} + +const int SLIDE_INTERVAL = 800; + +void slideWindow (const QRect &rcEnd, bool bAnimate) +{ + BOOL fFullDragOn; + + // Only slide the window if the user has FullDrag turned on + SystemParametersInfoA(SPI_GETDRAGFULLWINDOWS, 0, &fFullDragOn, 0); + + // Get the current window position + RECT rcWnd; + GetWindowRect(pMain->winId(), &rcWnd); + QRect rcStart; + rcStart.setCoords(rcWnd.left, rcWnd.top, rcWnd.right, rcWnd.bottom); + + if (bAnimate && fFullDragOn && (rcStart != rcEnd)) + { + static_cast(pMain)->m_bNoResize = true; + // Get our starting and ending time. + DWORD dwTimeStart = GetTickCount(); + DWORD dwTimeEnd = dwTimeStart + SLIDE_INTERVAL; + DWORD dwTime; + + while ((dwTime = ::GetTickCount()) < dwTimeEnd) + { + int delta = (int)(dwTime - dwTimeStart); + QRect rc = rcStart; + rc.setLeft(rcStart.left() + + (rcEnd.left() - rcEnd.left()) * delta / SLIDE_INTERVAL); + rc.setTop(rcStart.top() + + (rcEnd.top() - rcEnd.top()) * delta / SLIDE_INTERVAL); + rc.setWidth(rcStart.width() + + (rcEnd.width() - rcEnd.width()) * delta / SLIDE_INTERVAL); + rc.setHeight(rcStart.height() + + (rcEnd.height() - rcEnd.height()) * delta / SLIDE_INTERVAL); + SetWindowPos(pMain->winId(), NULL, + rc.left(), rc.top(), rc.width(), rc.height(), + SWP_NOZORDER | SWP_NOACTIVATE | SWP_DRAWFRAME); + UpdateWindow(pMain->winId()); + } + static_cast(pMain)->m_bNoResize = false; + } + EventInTaskManager((dock->getState() == ABE_FLOAT)).process(); + SetWindowPos(pMain->winId(), NULL, + rcEnd.left(), rcEnd.top(), rcEnd.width(), rcEnd.height(), + SWP_NOZORDER | SWP_NOACTIVATE | SWP_DRAWFRAME); + UpdateWindow(pMain->winId()); +} + +void setBarState(bool bAnimate = false) +{ + if ((dock->getState() == ABE_FLOAT) || !pMain->isVisible()) + { + appBarMessage(ABM_SETPOS, ABE_FLOAT, FALSE); + } + else + { + if (dock->getAutoHide() && !appBarMessage(ABM_SETAUTOHIDEBAR, dock->getState(), TRUE, NULL)) + { + dock->setAutoHide(false); + QMessageBox::warning(NULL, i18n("Error"), + i18n("There is already an auto hidden window on this edge.\nOnly one auto hidden window is allowed on each edge."), + QMessageBox::Ok, 0); + } + QRect rc; + getBarRect(dock->getState(), rc); + if (dock->getAutoHide()) + { + QRect rcAutoHide = rc; + int w = 4 * GetSystemMetrics(SM_CXBORDER); + if (dock->getState() == ABE_LEFT) + rcAutoHide.setRight(rcAutoHide.left() + w); + else + rcAutoHide.setLeft(rcAutoHide.right() - w); + + appBarMessage(ABM_SETPOS, dock->getState(), FALSE, &rcAutoHide); + if (!bAutoHideVisible) + { + if (bOldVisible) + dock->setWidth(rc.width() - GetSystemMetrics(SM_CXBORDER) * 2); + MINMAXINFO mmInfo; + rc = rcAutoHide; + SendMessageA(pMain->winId(), WM_GETMINMAXINFO, 0, (LPARAM)&mmInfo); + if (dock->getState() == ABE_LEFT) + rc.setLeft(rc.right() - mmInfo.ptMinTrackSize.x); + else + rc.setRight(rc.left() + mmInfo.ptMinTrackSize.x); + + } + else if (dock->getState() == ABE_LEFT) + rc.setRight(rc.left() + dock->getWidth()); + else + rc.setLeft(rc.right() - dock->getWidth()); + bOldVisible = bAutoHideVisible; + } + else + appBarMessage(ABM_SETPOS, dock->getState(), FALSE, &rc); + slideWindow(rc, bAnimate); + } + if (pMain->isVisible()) + { + EventOnTop(bFullScreen).process(); + if (!bFullScreen && (qApp->activeWindow() == pMain)) + appBarMessage(ABM_ACTIVATE); + } +} + +LRESULT CALLBACK dockWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + LRESULT res; + if (msg == WM_APPBAR) + { + switch (wParam) + { + case ABN_FULLSCREENAPP: + if ((lParam != 0) == bFullScreen) + break; + bFullScreen = (lParam != 0); + setBarState(); + break; + case ABN_POSCHANGED: + if (dock->getState() != ABE_FLOAT) + setBarState(); + break; + } + } + if(!oldProc) + return DefWindowProc(hWnd, msg, wParam, lParam); + unsigned type; + RECT *prc; + RECT rcWnd; + QRect rc; + unsigned oldState; + switch (msg) + { + case WM_DESTROY: + res = oldProc(hWnd, msg, wParam, lParam); + appBarMessage(ABM_REMOVE); + WNDPROC p; + p = (WNDPROC)SetWindowLongW(hWnd, GWL_WNDPROC, (LONG)oldProc); + if (p == 0) + p = (WNDPROC)SetWindowLongA(hWnd, GWL_WNDPROC, (LONG)oldProc); + oldProc = NULL; + return res; + case WM_SHOWWINDOW: + res = oldProc(hWnd, msg, wParam, lParam); + if (dock->getState() != ABE_FLOAT) + QTimer::singleShot(0, dock, SLOT(slotSetState())); + return res; + case WM_ACTIVATE: + if (dock->getState() != ABE_FLOAT) + { + if ((wParam == WA_INACTIVE) && dock->getAutoHide() && bAutoHideVisible) + { + bAutoHideVisible = false; + setBarState(); + dock->enableAutoHide(false); + } + appBarMessage(ABM_ACTIVATE); + } + break; + case WM_NCMOUSEMOVE: + if ((dock->getState() != ABE_FLOAT) && dock->getAutoHide() && !bAutoHideVisible) + { + bAutoHideVisible = true; + setBarState(true); + dock->enableAutoHide(true); + } + break; + case WM_ENTERSIZEMOVE: + bMoving = true; + bSizing = true; + if (dock->getState() == ABE_FLOAT) + { + bSizing = false; + GetWindowRect(hWnd, &rcWnd); + dock->setHeight(rcWnd.bottom - rcWnd.top); + } + return DefWindowProc(hWnd, msg, wParam, lParam); + case WM_EXITSIZEMOVE: + bMoving = false; + oldState = dock->getState(); + dock->setState(getEdge()); + GetWindowRect(hWnd, &rcWnd); + if ((dock->getState() == ABE_FLOAT) && (oldState != ABE_FLOAT)) + { + rcWnd.bottom = rcWnd.top + dock->getHeight(); + SetWindowPos(pMain->winId(), NULL, + rcWnd.left, rcWnd.top, rcWnd.right - rcWnd.left, rcWnd.bottom - rcWnd.top, + SWP_NOZORDER | SWP_NOACTIVATE | SWP_DRAWFRAME); + } + dock->setWidth(rcWnd.right - rcWnd.left); + setBarState(true); + return DefWindowProc(hWnd, msg, wParam, lParam); + case WM_MOVING: + case WM_SIZING: + if (!bMoving) break; + prc = (RECT*)lParam; + type = getEdge(prc); + if (type == ABE_FLOAT) + { + if (bSizing) + { + prc->bottom = prc->top + dock->getHeight(); + bSizing = false; + } + } + else + { + getBarRect(type, rc, prc); + prc->left = rc.left(); + prc->top = rc.top(); + prc->right = rc.right(); + prc->bottom = rc.bottom(); + bSizing = true; + } + return 1; + case WM_WINDOWPOSCHANGED: + res = oldProc(hWnd, msg, wParam, lParam); + if (dock->getState() != ABE_FLOAT) + appBarMessage(ABM_WINDOWPOSCHANGED); + return res; + } + return oldProc(hWnd, msg, wParam, lParam); +} + +static DataDef winDockData[] = + { + { "AutoHide", DATA_BOOL, 1, 0 }, + { "State", DATA_ULONG, 1, DATA(-1) }, + { "Height", DATA_ULONG, 1, 0 }, + { "Width", DATA_ULONG, 1, 0 }, + { NULL, DATA_UNKNOWN, 0, 0 } + }; + +WinDockPlugin::WinDockPlugin(unsigned base, Buffer *config) + : Plugin(base), EventReceiver(DefaultPriority - 1) +{ + dock = this; + + load_data(winDockData, &data, config); + + CmdAutoHide = registerType(); + + Command cmd; + cmd->id = CmdAutoHide; + cmd->text = I18N_NOOP("AutoHide"); + cmd->menu_id = MenuMain; + cmd->menu_grp = 0x7001; + cmd->flags = COMMAND_CHECK_STATE; + + m_bInit = false; + + m_autoHide = new QTimer(this); + connect(m_autoHide, SIGNAL(timeout()), this, SLOT(slotAutoHide())); + + EventCommandCreate(cmd).process(); + + WM_APPBAR = RegisterWindowMessageA("AppBarNotify"); + init(); +} + +WinDockPlugin::~WinDockPlugin() +{ + uninit(); + EventCommandRemove(CmdAutoHide).process(); + free_data(winDockData, &data); +} + +void WinDockPlugin::uninit() +{ + QWidget *main = getMainWindow(); + if (main && oldProc) + { + appBarMessage(ABM_REMOVE); + if (IsWindowUnicode(pMain->winId())) + SetWindowLongW(main->winId(), GWL_WNDPROC, (LONG)oldProc); + else + SetWindowLongA(main->winId(), GWL_WNDPROC, (LONG)oldProc); + oldProc = NULL; + } +} + + +bool WinDockPlugin::processEvent(Event *e) +{ + if (e->type() == eEventCommandExec){ + EventCommandExec *ece = static_cast(e); + CommandDef *cmd = ece->cmd(); + if (cmd->id == CmdAutoHide) + { + dock->setAutoHide((cmd->flags & COMMAND_CHECKED) != 0); + bAutoHideVisible = true; + setBarState(); + enableAutoHide(getAutoHide()); + return true; + } + } + else if (e->type() == eEventCheckCommandState) + { + EventCheckCommandState *ecs = static_cast(e); + CommandDef *cmd = ecs->cmd(); + if ((cmd->id == CmdAutoHide) && (dock->getState() != ABE_FLOAT)) + { + cmd->flags &= ~COMMAND_CHECKED; //Strokes the bit + if (dock->getAutoHide()) + cmd->flags |= COMMAND_CHECKED; //Sets the bit + return true; + } + } + else if ((e->type() == eEventInit) && !m_bInit) + init(); + if (e->type() == eEventInTaskManager){ + EventInTaskManager *eitm = static_cast(e); + if ((dock->getState() != ABE_FLOAT) && eitm->showInTaskmanager()) + { + EventInTaskManager(false).process(); + return true; + } + } + return false; +} + +void WinDockPlugin::init() +{ + if (m_bInit) + return; + pMain = getMainWindow(); + if (pMain) + { + if (IsWindowUnicode(pMain->winId())) + oldProc = (WNDPROC)SetWindowLongW(pMain->winId(), GWL_WNDPROC, (LONG)dockWndProc); + else + oldProc = (WNDPROC)SetWindowLongA(pMain->winId(), GWL_WNDPROC, (LONG)dockWndProc); + appBarMessage(ABM_NEW); + m_bInit = true; + setBarState(); + pMain->installEventFilter(this); + } +} + +void WinDockPlugin::slotSetState() +{ + setBarState(); +} + +void WinDockPlugin::slotAutoHide() +{ + if (pMain->isActiveWindow()) + return; + DWORD pos = GetMessagePos(); + int x = GET_X_LPARAM(pos); + int y = GET_Y_LPARAM(pos); + RECT rc; + GetWindowRect(pMain->winId(), &rc); + rc.left -= GetSystemMetrics(SM_CXDOUBLECLK) * 2; + rc.right += GetSystemMetrics(SM_CXDOUBLECLK) * 2; + if (x >= rc.left && x <= rc.right && y >= rc.top && y <= rc.bottom) + return; + if (getState() != ABE_FLOAT && getAutoHide() && bAutoHideVisible) + { + bAutoHideVisible = false; + setBarState(true); + enableAutoHide(false); + } +} + +void WinDockPlugin::enableAutoHide(bool bState) +{ + if (bState) + m_autoHide->start(1000); + else + m_autoHide->stop(); +} + +bool WinDockPlugin::eventFilter(QObject *o, QEvent *e) +{ + if ((e->type() == QEvent::Hide) && getAutoHide()) + return true; + return QObject::eventFilter(o, e); +} + +QByteArray WinDockPlugin::getConfig() +{ + return save_data(winDockData, &data); +} + +QWidget *WinDockPlugin::getMainWindow() +{ + CorePlugin *core = GET_CorePlugin(); + return core->getMainWindow(); +} + diff --git a/plugins/windock/windock.h b/plugins/windock/windock.h new file mode 100644 index 0000000..43762bc --- /dev/null +++ b/plugins/windock/windock.h @@ -0,0 +1,68 @@ +/*************************************************************************** + windock.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _WINDOCK_H +#define _WINDOCK_H + +#include + +#include "cfg.h" +#include "event.h" +#include "plugins.h" + +class QWidget; +class QTimer; + +struct WinDockData +{ + SIM::Data AutoHide; + SIM::Data State; + SIM::Data Height; + SIM::Data Width; +}; + +class QTimer; + +class WinDockPlugin : public QObject, public SIM::Plugin, public SIM::EventReceiver +{ + Q_OBJECT +public: + WinDockPlugin(unsigned, Buffer*); + virtual ~WinDockPlugin(); + PROP_BOOL(AutoHide); + PROP_USHORT(State); + PROP_ULONG(Height); + PROP_ULONG(Width); + void enableAutoHide(bool); +protected slots: + void slotSetState(); + void slotAutoHide(); +protected: + virtual bool processEvent(SIM::Event *e); + virtual bool eventFilter(QObject*, QEvent*); + virtual QByteArray getConfig(); + QWidget *getMainWindow(); + unsigned CmdAutoHide; + bool m_bInit; + void init(); + void uninit(); + QTimer *m_autoHide; + WinDockData data; +}; + +#endif + diff --git a/plugins/windock/windock.rc b/plugins/windock/windock.rc new file mode 100644 index 0000000..af5c9e9 --- /dev/null +++ b/plugins/windock/windock.rc @@ -0,0 +1,97 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,9,6,0 + PRODUCTVERSION 0,9,6,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Vladimir Shutoff\0" + VALUE "FileDescription", "Windocl plugin\0" + VALUE "FileVersion", "0, 9, 6, 0\0" + VALUE "InternalName", "windock\0" + VALUE "LegalCopyright", "Copyright © 2002-2003\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "windock.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "SIM\0" + VALUE "ProductVersion", "0, 9, 6, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/windock/windock.vcproj b/plugins/windock/windock.vcproj new file mode 100644 index 0000000..474cdf7 --- /dev/null +++ b/plugins/windock/windock.vcproj @@ -0,0 +1,312 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/yahoo/CMakeLists.txt b/plugins/yahoo/CMakeLists.txt new file mode 100644 index 0000000..9cefad1 --- /dev/null +++ b/plugins/yahoo/CMakeLists.txt @@ -0,0 +1,40 @@ +################# +# yahoo library # +################# +IF(BUILD_DROPPED) +if(OPENSSL_FOUND) + SET(yahoo_SRCS + crypt.cpp + yahoo.cpp + yahooauth.cpp + yahoocfg.cpp + yahooclient.cpp + yahoofiletransfer.cpp + yahoohttp.cpp + yahooinfo.cpp + yahoosearch.cpp + yahootransformtables.c + ) + + SET(yahoo_HDRS + yahoo.h + yahoocfg.h + yahooclient.h + yahooinfo.h + yahoosearch.h + ) + + SET(yahoo_UICS + yahoocfgbase.ui + yahooinfobase.ui + yahoosearchbase.ui + ) + + INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR}) + LINK_DIRECTORIES(${OPENSSL_LIBRARY_DIR}) + SIM_ADD_PLUGIN(yahoo) + TARGET_LINK_LIBRARIES(yahoo ${OPENSSL_LIBRARIES} ${OPENSSL_EAY_LIBRARIES}) +else(OPENSSL_FOUND) + MESSAGE(STATUS "OpenSSL library not found, yahoo plugin disabled") +endif(OPENSSL_FOUND) +ENDIF(BUILD_DROPPED) diff --git a/plugins/yahoo/configure.in.in b/plugins/yahoo/configure.in.in new file mode 100644 index 0000000..29a98d5 --- /dev/null +++ b/plugins/yahoo/configure.in.in @@ -0,0 +1,4 @@ +if test "$have_ssl" != yes; then + AC_MSG_WARN([OpenSSL library disabled. Yahoo! plugin is disabled]) +fi +AM_CONDITIONAL(ENABLE_YAHOO, test "$have_ssl" = "yes") diff --git a/plugins/yahoo/crypt.cpp b/plugins/yahoo/crypt.cpp new file mode 100644 index 0000000..ea9b5c3 --- /dev/null +++ b/plugins/yahoo/crypt.cpp @@ -0,0 +1,165 @@ +/* One way encryption based on MD5 sum. + Copyright (C) 1996, 1997, 1999, 2000 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* warmenhoven took this file and made it work with the md5.[ch] we + * already had. isn't that lovely. people should just use linux or + * freebsd, crypt works properly on those systems. i hate solaris */ + +#include + +#include "socket/socket.h" + +/* Define our magic string to mark salt for MD5 "encryption" + replacement. This is meant to be the same as for other MD5 based + encryption implementations. */ +const char md5_salt_prefix[] = "$1$"; + +/* Table with characters for base64 transformation. */ +const char b64t[] = + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +#define MIN(A, B) ((A < B) ? A : B) +#define MAX(A, B) ((A > B) ? A : B) + +char *yahoo_crypt(const char *key, const char *salt) +{ + static char *buffer = NULL; + static int buflen = 0; + int needed = 3 + strlen (salt) + 1 + 26 + 1; + + size_t salt_len; + size_t key_len; + size_t cnt; + char *cp; + + if (buflen < needed) { + buflen = needed; + if ((buffer = (char*)realloc(buffer, buflen)) == NULL) //warning C6308: 'realloc' might return null pointer: assigning null pointer to 'char * `char * __cdecl yahoo_crypt(char const *,char const *)'::`2'::buffer', which is passed as an argument to 'realloc', will cause the original memory block to be leaked + return NULL; + } + + /* Find beginning of salt string. The prefix should normally always + be present. Just in case it is not. */ + if (strncmp (md5_salt_prefix, salt, sizeof (md5_salt_prefix) - 1) == 0) + /* Skip salt prefix. */ + salt += sizeof (md5_salt_prefix) - 1; + + salt_len = MIN (strcspn (salt, "$"), 8); + key_len = strlen (key); + + std::string ct = key; + ct += md5_salt_prefix; + ct += salt; + + std::string ct_alt = key; + ct_alt += salt; + ct_alt += key; + ct_alt = (QCryptographicHash::hash(QByteArray(ct_alt.c_str(), ct_alt.length()), QCryptographicHash::Md5)).data(); + + /* Add for any character in the key one byte of the alternate sum. */ + for (cnt = key_len; cnt > 16; cnt -= 16) + ct.append(ct_alt.c_str(), 16); + ct.append(ct_alt.c_str(), cnt); + + char nil[] = ""; + + /* The original implementation now does something weird: for every 1 + bit in the key the first 0 is added to the buffer, for every 0 + bit the first character of the key. This does not seem to be + what was intended but we have to follow this to be compatible. */ + for (cnt = key_len; cnt > 0; cnt >>= 1) + ct.append((cnt & 1) != 0 ? nil : key, 1); + + /* Create intermediate result. */ + ct_alt = (QCryptographicHash::hash(QByteArray(ct.c_str(), ct.length()), QCryptographicHash::Md5)).data(); + + /* Now comes another weirdness. In fear of password crackers here + comes a quite long loop which just processes the output of the + previous round again. We cannot ignore this here. */ + for (cnt = 0; cnt < 1000; ++cnt) { + /* New context. */ + ct = ""; + + /* Add key or last result. */ + if ((cnt & 1) != 0) + ct += key; + else + ct.append(ct_alt.c_str(), 16); + + /* Add salt for numbers not divisible by 3. */ + if (cnt % 3 != 0) + ct += salt; + + /* Add key for numbers not divisible by 7. */ + if (cnt % 7 != 0) + ct += key; + + /* Add key or last result. */ + if ((cnt & 1) != 0) + ct.append(ct_alt.c_str(), 16); + else + ct += key; + + /* Create intermediate result. */ + ct_alt = (QCryptographicHash::hash(QByteArray(ct.c_str(), ct.length()), QCryptographicHash::Md5)).data(); + } + + /* Now we can construct the result string. It consists of three + parts. */ + + strncpy(buffer, md5_salt_prefix, MAX (0, buflen)); //warning C6387: 'argument 1' might be '0': this does not adhere to the specification for the function 'strncpy': Line: 43 + cp = buffer + strlen(buffer); //warning C6387: 'argument 1' might be '0': this does not adhere to the specification for the function 'strlen': Line: 43 + //warning C6053: Call to 'strncpy' might not zero-terminate string 'buffer': Line: 43 + buflen -= sizeof (md5_salt_prefix); + + strncpy(cp, salt, MIN ((size_t) buflen, salt_len)); + cp = cp + strlen(cp); //warning C6053: Call to 'strncpy' might not zero-terminate string 'cp': Line: 43 + buflen -= MIN ((size_t) buflen, salt_len); + + if (buflen > 0) { + *cp++ = '$'; + --buflen; + } + +#define b64_from_24bit(B2, B1, B0, N) \ + { \ + unsigned int w = ((B2) << 16) | ((B1) << 8) | (B0); \ + int n = (N); \ + while (n-- > 0 && buflen > 0) { \ + *cp++ = b64t[w & 0x3f]; \ + --buflen; \ + w >>= 6; \ + }\ + } + + b64_from_24bit (ct_alt[0], ct_alt[6], ct_alt[12], 4); + b64_from_24bit (ct_alt[1], ct_alt[7], ct_alt[13], 4); + b64_from_24bit (ct_alt[2], ct_alt[8], ct_alt[14], 4); + b64_from_24bit (ct_alt[3], ct_alt[9], ct_alt[15], 4); + b64_from_24bit (ct_alt[4], ct_alt[10], ct_alt[5], 4); + b64_from_24bit (0, 0, ct_alt[11], 2); + if (buflen <= 0) { + free(buffer); + buffer = NULL; + } else + *cp = '\0'; /* Terminate the string. */ + + return buffer; +} diff --git a/plugins/yahoo/yahoo.cpp b/plugins/yahoo/yahoo.cpp new file mode 100644 index 0000000..f7531c1 --- /dev/null +++ b/plugins/yahoo/yahoo.cpp @@ -0,0 +1,184 @@ +/*************************************************************************** + yahoo.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include "clientmanager.h" +#include "yahoo.h" +#include "yahooclient.h" +#include "core.h" + +using namespace SIM; + +Plugin *createYahooPlugin(unsigned base, bool, Buffer*) +{ + Plugin *plugin = new YahooPlugin(base); + return plugin; +} + +static PluginInfo info = + { + NULL, + NULL, + VERSION, + createYahooPlugin, + PLUGIN_PROTOCOL + }; + +EXPORT_PROC PluginInfo* GetPluginInfo() +{ + return &info; +} + +unsigned YahooPlugin::YahooPacket = 0; + +YahooPlugin::YahooPlugin(unsigned base) + : Plugin(base) +{ + YahooPacket = registerType(); + getContacts()->addPacketType(YahooPacket, "Yahoo!"); + registerMessages(); + m_protocol = new YahooProtocol(this); +} + +YahooPlugin::~YahooPlugin() +{ + delete m_protocol; + unregisterMessages(); + getContacts()->removePacketType(YahooPacket); +} + +YahooProtocol::YahooProtocol(Plugin *plugin) + : Protocol(plugin) +{ +} + +YahooProtocol::~YahooProtocol() +{ +} + +ClientPtr YahooProtocol::createClient(Buffer *cfg) +{ + ClientPtr yahoo = ClientPtr(new YahooClient(this, cfg)); + getClientManager()->addClient(yahoo); + return yahoo; +} + +static CommandDef yahoo_descr = + CommandDef ( + 0, + I18N_NOOP("Yahoo!"), + "Yahoo!_online", + "Yahoo!_invisible", + "http://edit.yahoo.com/config/eval_forgot_pw?.src=pg&.done=http://messenger.yahoo.com/&.redir_from=MESSENGER", + 0, + 0, + 0, + 0, + 0, + PROTOCOL_INVISIBLE, + NULL, + QString::null + ); + +const CommandDef *YahooProtocol::description() +{ + return &yahoo_descr; +} + +static CommandDef yahoo_status_list[] = + { + CommandDef ( + STATUS_ONLINE, + I18N_NOOP("Online"), + "Yahoo!_online", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + STATUS_AWAY, + I18N_NOOP("Away"), + "Yahoo!_away", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + STATUS_NA, + I18N_NOOP("N/A"), + "Yahoo!_na", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + STATUS_DND, + I18N_NOOP("Busy"), + "Yahoo!_dnd", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + STATUS_OFFLINE, + I18N_NOOP("Offline"), + "Yahoo!_offline", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef () + }; + +const CommandDef *YahooProtocol::statusList() +{ + return yahoo_status_list; +} diff --git a/plugins/yahoo/yahoo.h b/plugins/yahoo/yahoo.h new file mode 100644 index 0000000..7a5b8b9 --- /dev/null +++ b/plugins/yahoo/yahoo.h @@ -0,0 +1,48 @@ +/*************************************************************************** + yahoo.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _YAHOO_H +#define _YAHOO_H + +#include "contacts.h" +#include "contacts/client.h" + +class YahooProtocol : public SIM::Protocol +{ +public: + YahooProtocol(SIM::Plugin *plugin); + ~YahooProtocol(); + SIM::ClientPtr createClient(Buffer *cfg); + const SIM::CommandDef *description(); + const SIM::CommandDef *statusList(); + virtual const SIM::DataDef *userDataDef(); +}; + +class YahooPlugin : public SIM::Plugin +{ +public: + YahooPlugin(unsigned); + virtual ~YahooPlugin(); + static unsigned YahooPacket; +protected: + void registerMessages(); + void unregisterMessages(); + SIM::Protocol *m_protocol; +}; + +#endif + diff --git a/plugins/yahoo/yahoo.rc b/plugins/yahoo/yahoo.rc new file mode 100644 index 0000000..8a43084 --- /dev/null +++ b/plugins/yahoo/yahoo.rc @@ -0,0 +1,97 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,9,6,0 + PRODUCTVERSION 0,9,6,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "Vladimir Shutoff\0" + VALUE "FileDescription", "Yahoo plugin\0" + VALUE "FileVersion", "0, 9, 6, 0\0" + VALUE "InternalName", "yahoo\0" + VALUE "LegalCopyright", "Copyright © 2002-2003\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "yahoo.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "SIM\0" + VALUE "ProductVersion", "0, 9, 6, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/yahoo/yahoo.vcproj b/plugins/yahoo/yahoo.vcproj new file mode 100644 index 0000000..dc6674e --- /dev/null +++ b/plugins/yahoo/yahoo.vcproj @@ -0,0 +1,742 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/yahoo/yahoo_pch.h b/plugins/yahoo/yahoo_pch.h new file mode 100644 index 0000000..c8f6bc0 --- /dev/null +++ b/plugins/yahoo/yahoo_pch.h @@ -0,0 +1,43 @@ +#pragma once + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef NO_QT_MOC_HEADER +#include +//#include +//#include +#endif + +#include "yahoo.h" +#include "yahoocfg.h" +#include "ui_yahoocfgbase.h" +#include "yahooclient.h" +#include "yahooinfo.h" +#include "ui_yahooinfobase.h" +#include "yahoosearch.h" +#include "ui_yahoosearchbase.h" diff --git a/plugins/yahoo/yahooauth.cpp b/plugins/yahoo/yahooauth.cpp new file mode 100644 index 0000000..065264f --- /dev/null +++ b/plugins/yahoo/yahooauth.cpp @@ -0,0 +1,1379 @@ +/*************************************************************************** + yahooauth.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * Based on libyahoo2 + * + * Some code copyright (C) 2002-2004, Philip S Tellis + * + * Yahoo Search copyright (C) 2003, Konstantin Klyagin + * + * Much of this code was taken and adapted from the yahoo module for + * gaim released under the GNU GPL. This code is also released under the + * GNU GPL. + * + * This code is derivitive of Gaim + * copyright (C) 1998-1999, Mark Spencer + * 1998-1999, Adam Fritzler + * 1998-2002, Rob Flynn + * 2000-2002, Eric Warmenhoven + * 2001-2002, Brian Macke + * 2001, Anand Biligiri S + * 2001, Valdis Kletnieks + * 2002, Sean Egan + * 2002, Toby Gray + * + * This library also uses code from other libraries, namely: + * Portions from libfaim copyright 1998, 1999 Adam Fritzler + * + * Portions of Sylpheed copyright 2000-2002 Hiroyuki Yamamoto + * + * + * 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. * + * * + ***************************************************************************/ + +#include "yahooclient.h" +#include "socket/socket.h" +#include "socket/clientsocket.h" + +#define OPENSSL_NO_SHA0 // we need the new one! +#include +#include + +//#include +//#include + +#include + +extern "C" +{ + int yahoo_Dispatch(int Salt, int Parameter); +} + +char *yahoo_crypt(const char *key, const char *salt); + +/* This is the y64 alphabet... it's like base64, but has a . and a _ */ +char base64digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._"; + +/* This is taken from Sylpheed by Hiroyuki Yamamoto. We have our own tobase64 function + * in util.c, but it has a bug I don't feel like finding right now ;) */ +void to_y64(unsigned char *out, const unsigned char *in, int inlen) +/* raw bytes in quasi-big-endian order to base 64 string (NUL-terminated) */ +{ + for (; inlen >= 3; inlen -= 3) + { + *out++ = base64digits[in[0] >> 2]; + *out++ = base64digits[((in[0] << 4) & 0x30) | (in[1] >> 4)]; + *out++ = base64digits[((in[1] << 2) & 0x3c) | (in[2] >> 6)]; + *out++ = base64digits[in[2] & 0x3f]; + in += 3; + } + if (inlen > 0) + { + unsigned char fragment; + + *out++ = base64digits[in[0] >> 2]; + fragment = (in[0] << 4) & 0x30; + if (inlen > 1) + fragment |= in[1] >> 4; + *out++ = base64digits[fragment]; + *out++ = (inlen < 2) ? '-' : base64digits[(in[1] << 2) & 0x3c]; + *out++ = '-'; + } + *out = '\0'; +} + +typedef struct _auth { + int type; + int var1; + int var2; +} auth_function_t; + +struct buffer_t { + unsigned int buffer_start; + unsigned char buffer[257]; +}; + +#define NUM_TYPE_THREES 105 +#define NUM_TYPE_FOURS 56 +#define NUM_TYPE_FIVES 37 + +auth_function_t main_function_list[5][96] = { + { + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 }, + { 0, 0x0, 0x0 } + }, + { + { 2, 0x36056cd7, 0x4387 }, + { 3, 0x538920, 0x0 }, + { 3, 0x538a20, 0x0 }, + { 4, 0x55f320, 0x0 }, + { 3, 0x539320, 0x0 }, + { 4, 0x55f340, 0x0 }, + { 2, 0x4abb534d, 0x3769 }, + { 1, 0x1d242da5, 0x0 }, + { 2, 0x3c23132d, 0x339b }, + { 1, 0x191265c, 0x0 }, + { 1, 0x3db979db, 0x0 }, + { 3, 0x539868, 0x0 }, + { 1, 0x1a550e1e, 0x0 }, + { 1, 0x2f140a2d, 0x0 }, + { 2, 0x7c466a4b, 0x29bf }, + { 1, 0x2d3f30d3, 0x0 }, + { 2, 0x7e823b21, 0x6bb3 }, + { 4, 0x55f360, 0x0 }, + { 3, 0x5395a8, 0x0 }, + { 4, 0x55f604, 0x0 }, + { 3, 0x539ba8, 0x0 }, + { 4, 0x5628c4, 0x0 }, + { 3, 0x547818, 0x0 }, + { 4, 0x5628e4, 0x0 }, + { 3, 0x547978, 0x0 }, + { 4, 0x5628a4, 0x0 }, + { 2, 0x5b756ab9, 0x7e9b }, + { 3, 0x539d48, 0x0 }, + { 1, 0x1d1c4911, 0x0 }, + { 3, 0x539f60, 0x0 }, + { 3, 0x53a060, 0x0 }, + { 1, 0x46bd7771, 0x0 }, + { 1, 0x51ae2b42, 0x0 }, + { 2, 0x2417591b, 0x177b }, + { 2, 0x57f27c5f, 0x2433 }, + { 3, 0x53a588, 0x0 }, + { 3, 0x53a688, 0x0 }, + { 1, 0x71422261, 0x0 }, + { 4, 0x55f6a4, 0x0 }, + { 2, 0x58e937f9, 0x1075 }, + { 3, 0x53a7c8, 0x0 }, + { 4, 0x55f6c4, 0x0 }, + { 3, 0x53a8c8, 0x0 }, + { 3, 0x53aa20, 0x0 }, + { 2, 0xb4c3d13, 0x1597 }, + { 4, 0x55f6e4, 0x0 }, + { 1, 0xfe07d38, 0x0 }, + { 2, 0x689b4017, 0x3cfb }, + { 4, 0x562928, 0x0 }, + { 3, 0x547b00, 0x0 }, + { 1, 0x35413df3, 0x0 }, + { 2, 0x5b611ab, 0x570b }, + { 2, 0xda5334f, 0x3ac7 }, + { 1, 0x47706008, 0x0 }, + { 4, 0x55f744, 0x0 }, + { 3, 0x547548, 0x0 }, + { 4, 0x562884, 0x0 }, + { 1, 0x57611b36, 0x0 }, + { 2, 0x314c2cd1, 0x2b5b }, + { 1, 0x1ef33946, 0x0 }, + { 2, 0x28ea041f, 0x638f }, + { 3, 0x53b1d0, 0x0 }, + { 3, 0x53b2d0, 0x0 }, + { 3, 0x53b418, 0x0 }, + { 2, 0x511537cb, 0x7135 }, + { 2, 0x1cf71007, 0x5e17 }, + { 1, 0x583d4bcf, 0x0 }, + { 3, 0x53b550, 0x0 }, + { 1, 0x373e6856, 0x0 }, + { 2, 0x4d595519, 0x1a7d }, + { 3, 0x53b718, 0x0 }, + { 3, 0x53b838, 0x0 }, + { 1, 0xe2a36a7, 0x0 }, + { 3, 0x53bc10, 0x0 }, + { 3, 0x53bd10, 0x0 }, + { 4, 0x55f784, 0x0 }, + { 4, 0x55f7a4, 0x0 }, + { 1, 0x53f3604f, 0x0 }, + { 4, 0x55f7c4, 0x0 }, + { 4, 0x55f7e4, 0x0 }, + { 2, 0x1edc0ba3, 0x7531 }, + { 3, 0x53be50, 0x0 }, + { 1, 0x10df1038, 0x0 }, + { 4, 0x55f804, 0x0 }, + { 3, 0x53bf68, 0x0 }, + { 1, 0x4ede0cac, 0x0 }, + { 2, 0x2f076eeb, 0x5bcf }, + { 1, 0x6d86030f, 0x0 }, + { 1, 0x3f331713, 0x0 }, + { 3, 0x53c0e8, 0x0 }, + { 2, 0x41cd726f, 0x3f79 }, + { 4, 0x55f824, 0x0 }, + { 1, 0xece0054, 0x0 }, + { 2, 0x19b32b03, 0x4ad1 }, + { 4, 0x55f844, 0x0 }, + { 4, 0x55f864, 0x0 } + }, + { + { 2, 0x39731111, 0x419b }, + { 1, 0x54f7757a, 0x0 }, + { 4, 0x55f884, 0x0 }, + { 4, 0x55f8a4, 0x0 }, + { 3, 0x53c240, 0x0 }, + { 3, 0x53c368, 0x0 }, + { 2, 0x3cc0256b, 0x7ce7 }, + { 1, 0x79991847, 0x0 }, + { 2, 0x228f7fb5, 0x472d }, + { 2, 0x32da290b, 0x7745 }, + { 1, 0x7a28180d, 0x0 }, + { 4, 0x55f91c, 0x0 }, + { 4, 0x55f93c, 0x0 }, + { 2, 0x5c814f8b, 0x227f }, + { 3, 0x53c7b0, 0x0 }, + { 2, 0xb496f6d, 0x412d }, + { 1, 0x6f4b62da, 0x0 }, + { 3, 0x53c8b8, 0x0 }, + { 1, 0x64973977, 0x0 }, + { 3, 0x53c9e8, 0x0 }, + { 3, 0x53cae8, 0x0 }, + { 4, 0x55f9d0, 0x0 }, + { 3, 0x53cd28, 0x0 }, + { 3, 0x547230, 0x0 }, + { 1, 0x6dd14c92, 0x0 }, + { 3, 0x53ceb0, 0x0 }, + { 4, 0x560280, 0x0 }, + { 4, 0x56034c, 0x0 }, + { 4, 0x56036c, 0x0 }, + { 3, 0x53d168, 0x0 }, + { 1, 0x5e6324d8, 0x0 }, + { 3, 0x53d2d0, 0x0 }, + { 3, 0x53d3d0, 0x0 }, + { 3, 0x53d798, 0x0 }, + { 4, 0x5605b0, 0x0 }, + { 1, 0x62745ed0, 0x0 }, + { 2, 0x102c215b, 0x581 }, + { 3, 0x53d970, 0x0 }, + { 3, 0x53da70, 0x0 }, + { 3, 0x53dbd0, 0x0 }, + { 2, 0x19511111, 0x12c1 }, + { 3, 0x53dd70, 0x0 }, + { 2, 0x2a6e2953, 0x6977 }, + { 3, 0x53e0d0, 0x0 }, + { 1, 0x55cd5445, 0x0 }, + { 4, 0x560bcc, 0x0 }, + { 4, 0x560bec, 0x0 }, + { 2, 0x646c21eb, 0x43e5 }, + { 1, 0x71dc4898, 0x0 }, + { 1, 0x167519cb, 0x0 }, + { 1, 0x6d3158f8, 0x0 }, + { 1, 0x7ea95bea, 0x0 }, + { 4, 0x560c10, 0x0 }, + { 1, 0x47377587, 0x0 }, + { 1, 0x2d8b6e8f, 0x0 }, + { 2, 0x5e6105db, 0x1605 }, + { 1, 0x65b543c8, 0x0 }, + { 3, 0x540278, 0x0 }, + { 4, 0x560d34, 0x0 }, + { 2, 0x48af73cb, 0xa67 }, + { 1, 0x4fb96154, 0x0 }, + { 3, 0x5406e8, 0x0 }, + { 4, 0x560e38, 0x0 }, + { 1, 0x622c4954, 0x0 }, + { 4, 0x561014, 0x0 }, + { 1, 0x20d220f3, 0x0 }, + { 1, 0x361d4f0d, 0x0 }, + { 1, 0x2b2000d1, 0x0 }, + { 1, 0x6fb8593e, 0x0 }, + { 3, 0x5409e8, 0x0 }, + { 4, 0x561074, 0x0 }, + { 1, 0x2b7f7dfc, 0x0 }, + { 2, 0x5fc41a57, 0x693 }, + { 2, 0x17154387, 0x2489 }, + { 4, 0x561094, 0x0 }, + { 4, 0x5610b4, 0x0 }, + { 4, 0x5610d4, 0x0 }, + { 3, 0x540d18, 0x0 }, + { 1, 0x7e221470, 0x0 }, + { 1, 0x7a600061, 0x0 }, + { 4, 0x561190, 0x0 }, + { 4, 0x5611b0, 0x0 }, + { 3, 0x541218, 0x0 }, + { 4, 0x5611d0, 0x0 }, + { 2, 0xe813a5, 0x2ce5 }, + { 2, 0x3d707e25, 0x3827 }, + { 2, 0x77a53e07, 0x6a5f }, + { 4, 0x562968, 0x0 }, + { 3, 0x547d98, 0x0 }, + { 3, 0x547f10, 0x0 }, + { 1, 0x43a73788, 0x0 }, + { 3, 0x5387b0, 0x0 }, + { 4, 0x55f214, 0x0 }, + { 3, 0x539420, 0x0 }, + { 1, 0x55f4606b, 0x0 }, + { 4, 0x55f380, 0x0 } + }, + { + { 5, 0x55f3f8, 0x0 }, + { 2, 0x32ca58e3, 0x4f9 }, + { 1, 0x11756b30, 0x0 }, + { 2, 0x218b2569, 0x5db1 }, + { 1, 0x77d64b90, 0x0 }, + { 5, 0x562948, 0x0 }, + { 3, 0x547c10, 0x0 }, + { 2, 0x7d1428cb, 0x3d }, + { 1, 0x6f872c49, 0x0 }, + { 1, 0x2e484655, 0x0 }, + { 2, 0x1e3349f7, 0x41f5 }, + { 3, 0x541400, 0x0 }, + { 5, 0x561258, 0x0 }, + { 1, 0x61640311, 0x0 }, + { 5, 0x561278, 0x0 }, + { 3, 0x541588, 0x0 }, + { 3, 0x541688, 0x0 }, + { 3, 0x541988, 0x0 }, + { 1, 0x7044d3, 0x0 }, + { 5, 0x561298, 0x0 }, + { 2, 0x5c221625, 0x576f }, + { 3, 0x541b30, 0x0 }, + { 3, 0x541c30, 0x0 }, + { 1, 0x2d406bb1, 0x0 }, + { 2, 0x680b1f17, 0x12cd }, + { 5, 0x5613a0, 0x0 }, + { 2, 0x12564d55, 0x32b9 }, + { 2, 0x21a67897, 0x6bab }, + { 3, 0x541db8, 0x0 }, + { 2, 0x6405119, 0x7143 }, + { 1, 0x351d01ed, 0x0 }, + { 2, 0x46356f6b, 0xa49 }, + { 2, 0x32c77969, 0x72f3 }, + { 5, 0x5613c0, 0x0 }, + { 3, 0x541fe0, 0x0 }, + { 3, 0x5420e0, 0x0 }, + { 5, 0x5613e4, 0x0 }, + { 3, 0x542220, 0x0 }, + { 5, 0x561404, 0x0 }, + { 2, 0x74d52c55, 0x5f43 }, + { 1, 0x26201ca8, 0x0 }, + { 1, 0x7aeb3255, 0x0 }, + { 3, 0x53ab20, 0x0 }, + { 2, 0x578f1047, 0x640b }, + { 3, 0x542738, 0x0 }, + { 3, 0x542df8, 0x0 }, + { 5, 0x5615a0, 0x0 }, + { 5, 0x561628, 0x0 }, + { 1, 0x4a1352cf, 0x0 }, + { 2, 0x4bfb6ef3, 0x704f }, + { 2, 0x1b4c7fe7, 0x5637 }, + { 2, 0x4091a3b, 0x4917 }, + { 1, 0x270c2f52, 0x0 }, + { 3, 0x5430b8, 0x0 }, + { 5, 0x561748, 0x0 }, + { 3, 0x543220, 0x0 }, + { 5, 0x561768, 0x0 }, + { 2, 0x127549d5, 0x579b }, + { 2, 0xab54121, 0x7a47 }, + { 5, 0x5617f0, 0x0 }, + { 1, 0x751e6e49, 0x0 }, + { 3, 0x543580, 0x0 }, + { 3, 0x543680, 0x0 }, + { 1, 0x670c3f74, 0x0 }, + { 2, 0x6b080851, 0x7e8b }, + { 1, 0x71cd789e, 0x0 }, + { 1, 0x3eb20b7b, 0x0 }, + { 5, 0x561ea0, 0x0 }, + { 3, 0x543848, 0x0 }, + { 2, 0x58a67753, 0x272b }, + { 2, 0x1ab54ad7, 0x4d33 }, + { 2, 0x7d30a45, 0x569 }, + { 2, 0x737616bf, 0x70c7 }, + { 3, 0x543990, 0x0 }, + { 2, 0x45c4485d, 0x2063 }, + { 5, 0x561f38, 0x0 }, + { 1, 0x2598043d, 0x0 }, + { 2, 0x223a4fe3, 0x49a7 }, + { 1, 0x1eed619f, 0x0 }, + { 5, 0x561f58, 0x0 }, + { 1, 0x6f477561, 0x0 }, + { 5, 0x561f7c, 0x0 }, + { 5, 0x561f9c, 0x0 }, + { 3, 0x543bf8, 0x0 }, + { 2, 0x4bc13c4f, 0x45c1 }, + { 1, 0x3b547bfb, 0x0 }, + { 3, 0x543d08, 0x0 }, + { 2, 0x71406ab3, 0x7a5f }, + { 1, 0x2f1467e9, 0x0 }, + { 2, 0x9366d1, 0x22d1 }, + { 2, 0x587d1b75, 0x2ca5 }, + { 2, 0x213a4be7, 0x4499 }, + { 2, 0x62653e89, 0x2d5d }, + { 5, 0x562198, 0x0 }, + { 2, 0x4f5f3257, 0x444f }, + { 2, 0x4c0e2b2b, 0x19d3 } + }, + { + { 2, 0x3f867b35, 0x7b3b }, + { 2, 0x32d25cb1, 0x3d6d }, + { 5, 0x5622f0, 0x0 }, + { 2, 0x50fa1c51, 0x5f4f }, + { 3, 0x544130, 0x0 }, + { 1, 0x5fe7af1, 0x0 }, + { 2, 0x14067c29, 0x10c5 }, + { 3, 0x544298, 0x0 }, + { 2, 0x4a5558c5, 0x271f }, + { 1, 0x3c0861b1, 0x0 }, + { 5, 0x562864, 0x0 }, + { 3, 0x546d50, 0x0 }, + { 2, 0x18837c9d, 0x6335 }, + { 5, 0x56238c, 0x0 }, + { 1, 0x7dab5033, 0x0 }, + { 3, 0x544548, 0x0 }, + { 2, 0x3b87321, 0x7225 }, + { 1, 0x7f906745, 0x0 }, + { 3, 0x544700, 0x0 }, + { 5, 0x5623ac, 0x0 }, + { 1, 0x21c46c2c, 0x0 }, + { 2, 0x2b36757d, 0x28d }, + { 5, 0x5623cc, 0x0 }, + { 3, 0x5448a8, 0x0 }, + { 1, 0x106b4a85, 0x0 }, + { 1, 0x17640f11, 0x0 }, + { 3, 0x544a28, 0x0 }, + { 1, 0x69e60486, 0x0 }, + { 3, 0x547670, 0x0 }, + { 2, 0x3782017d, 0x5bf }, + { 5, 0x5623ec, 0x0 }, + { 3, 0x5480c8, 0x0 }, + { 1, 0x6bca53b0, 0x0 }, + { 3, 0x546af0, 0x0 }, + { 3, 0x546bf0, 0x0 }, + { 3, 0x544d20, 0x0 }, + { 3, 0x544e20, 0x0 }, + { 1, 0xb8236e3, 0x0 }, + { 5, 0x562908, 0x0 }, + { 2, 0x5ee51c43, 0x4553 }, + { 5, 0x56249c, 0x0 }, + { 3, 0x546fd8, 0x0 }, + { 3, 0x5470d8, 0x0 }, + { 3, 0x546970, 0x0 }, + { 2, 0x42b14c6f, 0x5531 }, + { 1, 0x4a2548e8, 0x0 }, + { 2, 0x5c071d85, 0x2437 }, + { 3, 0x5467d8, 0x0 }, + { 2, 0x29195861, 0x108b }, + { 1, 0x24012258, 0x0 }, + { 3, 0x546690, 0x0 }, + { 1, 0x63cc2377, 0x0 }, + { 1, 0x8d04b59, 0x0 }, + { 2, 0x3fd30cf5, 0x7027 }, + { 1, 0x7c3e0478, 0x0 }, + { 2, 0x457776b7, 0x24b3 }, + { 1, 0x86652bc, 0x0 }, + { 2, 0x302f5b13, 0x371d }, + { 3, 0x546548, 0x0 }, + { 2, 0x58692d47, 0x671 }, + { 1, 0x6601178e, 0x0 }, + { 2, 0xf195b9b, 0x1369 }, + { 1, 0x7ba21d8, 0x0 }, + { 5, 0x562544, 0x0 }, + { 5, 0x562564, 0x0 }, + { 1, 0x13ac3d21, 0x0 }, + { 2, 0x5bcf3275, 0x6e1b }, + { 2, 0x62725c5b, 0x16b9 }, + { 2, 0x5b950fdf, 0x2d35 }, + { 5, 0x5625a0, 0x0 }, + { 5, 0x5625c0, 0x0 }, + { 2, 0x73ba5335, 0x1c13 }, + { 5, 0x5625e0, 0x0 }, + { 5, 0x562600, 0x0 }, + { 1, 0x3e144154, 0x0 }, + { 2, 0x4eed7b27, 0x38ab }, + { 3, 0x545c58, 0x0 }, + { 2, 0x627c7e0f, 0x7f01 }, + { 2, 0x5d7e1f73, 0x2c0f }, + { 3, 0x545aa0, 0x0 }, + { 2, 0x55c9525f, 0x4659 }, + { 1, 0x3765334c, 0x0 }, + { 2, 0x5df66ddf, 0x7c25 }, + { 3, 0x545d78, 0x0 }, + { 3, 0x545e78, 0x0 }, + { 1, 0x16ae5776, 0x0 }, + { 3, 0x545ff8, 0x0 }, + { 3, 0x546190, 0x0 }, + { 5, 0x562620, 0x0 }, + { 5, 0x562640, 0x0 }, + { 3, 0x546290, 0x0 }, + { 2, 0x4392327b, 0x7e0d }, + { 3, 0x546398, 0x0 }, + { 2, 0x3d8b0cb5, 0x640d }, + { 2, 0x32865601, 0x4d43 }, + { 5, 0x562660, 0x0 } + } + }; + +struct buffer_t type_three_list[NUM_TYPE_THREES]={ + { 0x538920, "\x7a\x61\x31\x57\x9\xbc\x11\x8d\x6a\x12\x3a\x4d\x76\xbf\x19\x86\x2c\xc8\x69\x60\x84\x1\xc9\x21\xb1\xa6\xf\x99\xcd\xa0\x71\x8b\x5f\xb2\xd2\x53\xed\xf9\x55\xa\x50\x14\x15\xad\x88\x52\x5d\xbb\xe\xe5\xd\x56\x3e\x9b\xc7\x17\x9a\x97\x92\x23\x0\x37\xaa\x27\xf6\xb6\x33\xb5\xc5\xd1\x38\x1b\x85\x42\x13\xe1\x64\x1d\x4c\x87\x9f\x3c\x40\xdf\x7b\xd5\xae\xc6\x7c\xec\xd7\x49\x35\x2f\x2b\x9d\x32\xbd\x93\x45\x73\x91\x34\xd4\x39\x1e\x96\x65\xeb\x82\x5a\xf3\xd8\xf1\x41\xce\x9c\xe6\x90\x7d\x6b\x29\x6\xc1\x3d\x4e\xe3\xdb\x48\x6c\x62\x72\x7f\xfe\xdd\xcf\xa1\x24\x4f\xc0\xd0\x3f\x2d\x5c\x78\x6f\x3b\x10\xef\xba\xb\x25\xd6\x1f\x58\x8c\xf8\xcc\xc2\x5\xb3\xfa\xa4\xac\x6e\xf5\x18\x2a\x26\x5e\xf4\x79\xb8\xc3\x16\xe2\xf2\x83\x30\x59\xda\xe9\x36\x7\x46\xa9\xde\x77\xd3\xa3\x98\x8\x1c\xe7\xee\x51\xe8\xfb\x2\xc4\xfd\xff\x22\xaf\x7e\xcb\x68\xc\x28\xe4\x63\xca\x70\x75\xb0\x74\xa7\xea\x20\x4\x4b\xa5\xb7\xf7\xfc\x4a\x47\xf0\xa8\x81\xbe\xe0\x66\x8e\x44\x54\x6d\x80\xb9\x95\x2e\xab\x8a\x1a\x94\xdc\x89\xb4\x5b\x9e\xd9\x8f\xa2\x43\x67\x3" }, + { 0x538a20, "\x28\xeb\x74\xef\xb7\x73\x79\xd1\x46\xcc\xfb\x3b\x91\xc2\x16\xcb\x93\xaf\x51\x88\xb0\x5d\xfa\xfc\xc\xf\xc8\x4a\x53\x17\x8e\xec\x81\x36\xc6\xdc\xbc\x89\xa\x1f\x78\xdd\x76\x6c\x85\xd2\x13\xb9\x3a\x97\xde\x86\x3e\x12\xbe\x68\x23\x6a\x58\xce\xea\xe3\xa8\x5a\x8c\x3\x8a\x9d\xfe\xf3\x47\x63\xdf\x44\xaa\xd9\x24\xf0\x5b\xe2\x9c\xd3\xa9\x2e\xfd\x8b\xbd\xa4\x7a\x42\x5f\x4d\xa2\x48\x83\xcd\xe\x27\x61\xcf\xd\x50\x6f\x49\xae\xc7\x2f\x31\x39\x8f\x11\xdb\xad\x6b\x7f\xb6\x55\x62\x4c\x66\xc4\x75\xf6\x1b\xc1\xf1\x90\x95\x65\x9\xe0\xb4\xbf\xf4\x35\x37\x1c\x67\xe8\xf9\xe6\x56\x99\x22\xc0\xe9\x92\x21\xe1\x7d\x6e\x34\xd4\x8d\x96\x20\x52\xd0\x69\x2d\xf8\x7e\x4f\xb\xac\x71\xa3\xe5\x2a\xa5\xc5\x18\x5e\x6\xca\x2\x4b\x26\xf5\xab\x9f\xe7\x15\x3d\xd6\x4\x8\xee\xbb\x57\x0\x40\xd5\xa7\x1d\x45\xa6\x2c\xff\x9a\x32\x84\x1a\x14\xf7\x80\xd8\x43\x72\x7\x98\x38\x87\x33\xb1\x29\xb3\x7c\x30\xba\x94\xc9\x64\xe4\x1\x77\x3c\x2b\x82\x54\x6d\x9e\xf2\x3f\xed\xc3\x4e\x5c\x60\x70\x19\xa0\xb8\xda\x5\xb2\x10\x7b\x25\xb5\x9b\x59\x41\x1e\xa1\xd7" }, + { 0x539320, "\x9c\x3b\xec\x3e\x7b\x79\x6f\x88\x42\xe6\xe1\x9b\xa3\xd\x83\x86\x7a\xfc\xc5\xb3\xdb\x7c\xf6\xa\xb7\xe7\x3c\x53\x28\x65\xf2\xa9\x6a\xf4\xef\x2c\x3d\xf8\xed\x6\xaf\x31\x75\xab\xf3\x73\xee\x20\x95\x1b\xe\x19\xa8\x5b\xa5\x66\x74\x85\x11\x60\x1e\x2a\x6c\x48\x50\x2f\x9a\x2e\x55\xaa\xcb\x64\x40\x4c\x25\xe9\xd0\xfd\x2d\x46\x8b\x81\x8d\xd2\x32\x4a\xc6\x7\xd6\xbf\xfb\x98\xd4\x76\x7e\xc\xfa\xde\x14\xa6\xd5\xe2\x90\xd1\xeb\xd3\x58\xbb\x5f\x94\xf7\x78\x54\x27\x52\xb6\x22\xea\x8c\xc8\x7d\x87\x12\x9d\xa1\x63\x38\xd8\x35\x2b\xc9\x56\x10\x9f\x1a\x2\xbe\xf1\x59\x17\x9e\xac\x5a\xb8\x1\xb5\x30\xad\xff\xe0\x49\xe8\x23\x4e\x6b\x16\xdc\x4f\x89\x68\x43\xc1\x99\x4\xa7\x33\x92\x84\xa4\x26\x34\x41\x1d\xb2\x91\x61\xc2\x51\x8f\x36\xfe\x5\xa2\xf9\xb\x13\x71\x82\x6e\x5d\xb4\xdf\xdd\x7f\xa0\xcd\x44\xc7\x70\x4d\xf0\x1c\x4b\x45\x57\x37\x3a\xcc\xf5\x8a\xd9\xe4\xbc\x15\xc3\x62\xc4\x39\x72\x47\x97\xbd\x8\xe5\x67\x18\xb1\x77\x8e\x1f\x9\xba\xf\xd7\xb0\x24\xce\xda\x0\x96\xca\x69\x3\x6d\x93\xae\xe3\x3f\x5c\xcf\xc0\xb9\x29\x80\x21\x5e" }, + { 0x539868, "\xf2\xc3\x9\x40\x62\x4b\x94\xd2\xf8\x4a\xdf\xa\xb1\x61\xf9\x9c\x13\x35\x3\xe8\xc4\xf6\x49\x1a\xc\x45\x97\xe\x83\x33\x6d\xa0\x73\xb9\x3d\x9d\xff\x60\xc6\xaf\x68\xb6\x89\x10\xb0\xde\x98\x7f\x8c\x5a\xa5\x1e\x6f\x7c\x17\x12\xd7\xdc\x75\xfc\x20\x1d\x92\xcf\xf1\x16\xd\x50\x41\x39\xab\xeb\x14\x65\xc8\xa4\x99\xb5\x8a\x21\x90\xba\x4d\x3c\xf3\x66\xd1\x96\xf\xac\xa6\x7b\xbc\x8f\xd0\x29\x1f\xb3\xce\xd8\x79\x2\x36\x0\xe5\x91\x5e\xbb\xaa\x52\xc2\x31\x6b\x88\x8b\x9b\x2a\x44\x6c\x2f\x8e\xfb\xa3\x6\x48\xa2\x69\xc9\x28\x43\x47\x37\xef\xb8\x84\xe0\x4f\x30\xae\x56\xb7\x4e\x34\x81\x77\x67\xfd\x74\x93\xcd\x7a\x51\x76\x54\x5b\x2b\x3e\x80\xea\x9f\x15\xe1\x9a\xbf\x38\xfa\x8\x24\x42\xee\x7e\x4\x5f\xa8\xc5\xdb\x4c\x2d\xd9\xca\x19\xcc\xcb\x85\xa1\x32\x25\xec\x64\x57\xad\xf5\xb\x71\x11\x3f\xfe\x58\x1c\xd3\xb2\x72\xf7\x2c\xa9\xf0\x8d\xe9\xbe\x70\xe7\x95\xe6\x6e\x7\x9e\x46\x53\xdd\xed\xe2\xf4\x3b\x22\xc1\x3a\x55\x26\xd6\xc7\xd4\xc0\x27\x5\x7d\x5d\xe4\xd5\x5c\xe3\xb4\x63\xa7\x59\x82\xda\x18\x23\x2e\x1b\x1\xbd\x78\x86\x6a\x87" }, + { 0x5395a8, "\xfa\xb9\xda\x78\xde\x7f\x6\xab\xd7\xb1\x5c\x10\x1b\xf5\x62\x85\xf4\x98\xfb\xb2\xff\x5e\x5\x2b\x81\xd1\x7d\x58\xa7\x6b\x23\x7b\x26\x9f\xa9\xe\x59\xb8\xac\xd9\x64\x6e\x4f\x6a\x2d\x3c\x15\xc7\x63\x42\x54\x9\x90\xf6\xa0\x86\x9d\xea\xcf\x7c\xfe\xc5\xd4\x4d\xa6\xd5\xba\xcd\x5d\x9b\x2a\x6c\xb5\x7a\xbe\xf0\x44\x65\x0\x17\x3\xaf\xed\xfd\x1f\xc2\xd8\x5a\x16\xad\xc3\x35\x43\xbb\xa5\x37\x40\xf\x60\x99\x94\x1e\x89\x68\x88\xc8\xc4\x4a\x66\x24\x55\x3d\x4b\xe2\x1d\x1a\xe8\x19\x5b\xbf\x51\x8c\xae\x8a\x87\x8d\x3b\x22\x82\xd6\x80\x95\xef\x50\x21\xd\xd3\x33\x6d\x2c\xf1\xee\x38\xdc\xc1\x6f\x2\x46\xc6\x7e\x18\xb0\xce\x8\xd2\xb6\x53\x73\xe6\xf9\x3a\x4c\x48\x96\x1c\x70\x8b\x93\x69\xf7\x56\x30\x31\xdb\xa1\x1\xb\x77\xbc\xf2\x8e\x27\xa3\x7\xe4\x3f\xfc\x49\xcb\xe0\x45\x12\x67\x13\xb7\x74\xc\x52\xcc\xdd\x76\x29\x32\x57\xe1\xe9\x8f\xca\xaa\xbd\x71\x2e\x4\x97\xa4\xc9\x79\xdf\x83\xb3\x3e\x72\xc0\xb4\xec\x9a\x14\xa\x2f\x5f\x39\x25\x28\x75\xa2\xf8\x9c\xe3\xa8\x11\x9e\x4e\xd0\xe7\x61\x41\x84\xeb\x20\x36\x34\xf3\xe5\x92\x91\x47" }, + { 0x539ba8, "\x88\x82\x72\x56\xde\xa5\x45\x91\xf9\xe4\xee\x32\x59\x18\xb8\x6f\x79\xc7\xb0\x8c\x11\xd2\xe7\xef\x48\xe6\x20\xa1\x22\x12\xc8\x15\x6a\x8f\x3b\xd5\x3c\xe8\x63\x28\x10\xe9\x2c\xf5\x69\xa7\xf6\xd0\x83\xe0\x80\x81\x46\x29\x38\x2e\xf8\x34\x5b\x1a\x9d\xfa\xa4\x35\x54\xc1\x7e\xe\xae\x7f\x6e\x57\xb4\xbc\xff\x9b\x4a\xb7\x2b\x0\x5f\x31\x6d\x74\xd8\x36\x5c\xc3\xa2\xdf\x3d\xe2\x86\xfb\x5a\xca\x30\x50\x3e\x73\x4e\x9a\x94\xf0\x7d\xc5\x4f\xe3\x66\x39\xeb\x70\x52\x4b\xe5\x71\xc0\x76\x44\xa9\xa0\x7b\x27\xb1\x6c\xf\xc6\x96\xcb\xba\xda\xea\x37\x1c\xac\xb3\xd6\xb9\xbf\xdb\x1d\x8a\xfe\x9\x21\x75\x5d\x97\xe1\x8e\x25\xbd\x2d\xdd\xf7\xcd\x2a\x1e\x5e\x7a\xc\xfd\x9f\x60\x8\x64\xce\xf4\x61\x8d\x9e\xcf\xd4\x49\xb\x67\x1\xf1\x87\x53\x13\xaf\x2f\xa\xec\x3a\xbb\xa8\xbe\xc9\x90\x43\x6\x7c\xb6\xcc\xc2\x4c\x62\xb5\xc4\x77\x3\xf3\xab\xd3\x33\x24\xf2\x55\x6b\x1b\xa3\x2\x4\x23\x16\x14\x95\x3f\x65\xad\x89\x26\x5\x42\xfc\x98\x7\xaa\x19\x9c\xa6\xd\x93\xed\xb2\x8b\x40\xd7\x47\x1f\x99\x78\x17\x92\xd1\x4d\x51\x58\x84\xdc\x41\xd9\x68\x85" }, + { 0x547818, "\x73\x5\xde\x12\xaf\xb4\xaa\x9\x31\xcb\xba\x55\xd3\x1b\xf7\xbe\xd9\x45\x6d\x50\x2d\x74\xfa\x9c\xb3\xb2\xc0\x34\x16\x8d\x3d\x3f\x65\x13\xc8\xe3\xc\xfd\xea\x56\x67\x32\x7b\x24\xd1\xee\xc4\x1f\x3e\x4d\xd7\x33\xd5\xbf\xf\xca\x82\x63\x8b\x60\x86\xfe\x37\x51\x6\xe5\xe8\xe6\x64\x2b\x8a\xbb\xd0\xb8\xb1\xdc\xb9\x8c\x75\x5c\x14\x88\x22\x94\x96\x9d\xb7\x58\x2e\xbc\xc9\xa1\x1\x77\xec\xa2\x2\x6b\xc1\xad\xac\x62\xe1\x9b\x40\xb5\xd6\x78\x80\xc3\x4\x3\x4a\xa0\xeb\x8e\xf5\xc6\xab\xf6\x57\xa5\x8\xcc\x5b\xf2\xff\x2f\xa\x25\xb0\x3a\x7d\xf4\x43\x10\x85\x15\x44\xae\x92\x61\x27\x1c\xce\x19\xf9\xa6\xc5\x48\xe2\x59\xb\x89\xef\xc2\x0\xa8\x5d\x99\x54\xed\x2a\x3b\x4e\x42\xf3\x8f\x2c\x18\x6f\x69\x53\x68\xcd\x29\x6a\x1d\xc7\xf0\xd\x23\x4c\xe\x91\xfc\xe9\xcf\x98\x9a\x52\xfb\x21\x1e\x5f\x30\xda\x9e\x9f\xa9\x7a\x6c\x4b\x39\x7f\x20\x5a\xd2\x83\xdb\x49\x81\x93\x7\x3c\x95\xe0\x70\x26\x41\xa3\x79\x47\xa4\x11\x76\x97\x17\x35\xd8\xf8\x5e\x7e\x71\xbd\xf1\x28\x84\x46\xb6\xa7\xdf\x38\x66\x72\xdd\x90\xe4\x7c\x6e\xe7\x87\x36\x1a\xd4\x4f" }, + { 0x547978, "\x4f\xf2\x63\xe9\xdd\x53\x55\xf0\xf6\x86\x76\xab\x8b\x91\x5\xa9\x5c\x92\xc9\xf3\x24\xdc\x3c\x6\xf4\x54\xb\xad\x28\x46\xaf\x60\xc1\xae\xc2\xec\x74\x84\xb3\xcc\x75\x1b\x34\xa6\xf\x6e\x85\xf9\x44\x69\x3d\x4e\x8e\x1f\xed\x15\x12\x62\xdb\xbd\xea\x68\x50\xfc\x30\xde\x5b\x9b\x33\x99\x8d\x61\x98\x56\x78\x19\xc\xb4\x8f\xc8\x10\xb0\x38\x17\x21\x2a\x5e\xe1\xb1\x81\xbc\x2b\xe3\x94\x7b\x6f\x9a\x7e\x48\x3\xc6\xb5\x65\x43\xaa\x23\x1d\x59\x31\xcf\x1\xb7\xfa\xfe\xbf\x1a\x96\xf5\x87\xac\xbb\xfd\xdf\x82\xd1\x13\x8a\x11\xe4\x40\x0\xc5\x7\xa5\xb6\xd9\x4b\xba\x3b\x93\xa0\x9e\x52\x9c\xe\x14\xd2\x3e\x7d\x9f\xd8\x72\x9\xe0\x39\x27\x77\x97\x29\xd5\x88\x95\xee\x22\x3a\x47\xc7\x16\xc4\x25\xb9\x6d\x8\x2c\x35\x6c\xcd\xb2\x5f\xf8\xff\x41\x18\x3f\xe5\x57\x2e\x67\xc3\x49\x89\x90\xcb\xe6\x26\x4\xa8\xbe\xca\x2f\xfb\xd4\x71\xf7\xda\xe8\x6b\x5d\x79\x70\x1c\xce\x7a\xa3\x2d\x4a\xd7\xe2\xb8\x64\x6a\x51\x73\xa\x37\xa2\xd3\x4d\x80\x5a\xa1\x36\x45\x66\xa4\x20\x58\x4c\xd6\x1e\xd\xeb\xe7\x42\x7f\x9d\xf1\xa7\xef\x32\xc0\x2\x8c\x83\x7c\xd0" }, + { 0x539d48, "\x29\x0\x10\x9\x37\xc0\xb\xa\x91\xc8\xc9\xb6\x8e\x1\x9f\x64\xae\x13\xa6\xb7\x62\x27\xf7\xd0\x9e\x68\xf1\xf9\x15\xdd\x3a\x56\xca\xde\x96\x89\x8\x90\x38\xeb\x99\x57\xb8\xd7\x65\x94\x77\xb1\x16\x45\x5d\x67\x2f\x79\xd5\xcc\xdf\x44\xbe\x31\x8a\xef\x88\x7a\xfb\xa3\xa5\x39\x78\x84\x3\xe8\xbd\x8c\x85\x6f\xb2\x59\x6d\x93\x7\xaa\x36\xee\xe7\x7c\x21\x2b\xc7\x40\x54\xcd\xb9\x1f\x30\x80\xea\xcb\xfd\x20\xbf\x2c\xd\x6e\x73\x4b\xe5\x74\x18\x9d\x3f\xb4\xb3\x50\x81\x9a\xd4\xf3\xf2\x3e\x6b\x1d\x9b\x12\x49\xa1\xcf\x4f\x51\x41\x71\xc2\xd9\xdb\x5a\x97\x6a\xe0\x87\x6\x5\x2d\xf8\x47\x5b\x1b\x69\xc4\xad\xff\x43\x46\x24\xc\x82\x33\x8d\x26\x86\xab\x5c\x61\xe4\x66\xaf\x11\xa0\x42\xa2\x2e\x34\xdc\x25\x4d\xd6\xd2\x63\x70\x22\x83\x19\xa7\x4e\x92\xb5\xf\xda\x55\xed\x7f\x7b\xa4\xfc\x1a\x1e\x8b\xbc\xb0\xc3\x98\xec\x17\x60\xc1\x3d\x8f\x4c\x48\xac\xce\x7e\x72\xd1\x5e\x35\xa8\x32\x4\x1c\xe\x3b\xfa\xbb\xa9\x2a\xf6\xd8\x2\x6c\x23\x76\xe2\x53\xba\x28\x9c\xe1\xd3\x52\xf0\xe9\x7d\xe6\xfe\x58\x14\x5f\xf4\xe3\xc5\x4a\x3c\xf5\x75\xc6\x95" }, + { 0x539f60, "\x5f\xfc\x77\xa1\x39\xa6\x43\xf3\x2b\xbf\xab\x35\x4b\xbe\xad\xcd\xd3\x87\x22\x4f\x62\x3a\x1b\x3c\xef\xb1\x71\xae\x8c\x96\xc4\x86\x38\xf8\xa\xf9\x9b\xfb\x33\x41\xea\x69\x4e\x5c\x42\x58\xcc\x67\xf1\x26\xc9\xf5\xa3\x74\xe4\xbb\x56\x8\x7d\xbd\x99\x72\x80\x5d\xed\x2d\x65\xe6\x9\xa0\xb3\xb5\xc5\xa9\x85\x7\xd\x82\x1f\x9e\xd2\x6f\x2\xaf\x57\x55\x93\x48\x76\xc6\x30\x16\xe0\x60\x51\xf7\x59\x1c\x45\x6c\x4\x92\x32\x7a\xf2\x2f\x4a\x36\x63\x2c\xdd\x70\xd7\x4c\xec\xce\x13\xd9\x89\x97\xc7\x81\x15\xdc\xa5\x7c\x5a\x3\x1a\x2a\x49\xb2\x11\x88\x68\xc1\xb4\x9d\x73\x9a\xc0\x47\x21\x12\xe2\x78\x31\x0\x3e\x6\x6d\xca\xb8\x7f\xcf\x25\xb0\x91\xff\xb\x84\x24\xe9\x8e\xa4\x6b\xc\xac\xe3\x17\xc2\xe7\x6a\xc8\x8d\xf0\x14\xe\x95\xcb\xc3\xd6\x3f\x6e\x64\xfa\xd4\xee\x90\x9f\xe8\xd5\x98\xdf\xeb\xf\x2e\x19\x20\xaa\x44\x46\xbc\x53\x8b\x4d\x3b\x7b\xfd\xa7\x29\x28\x34\xe5\x8f\xb7\xa2\xd8\xa8\x3d\xb9\x5b\x75\xdb\x5\x83\xb6\x50\x5e\x7e\x52\xfe\x37\xe1\x54\x66\x9c\xda\x1d\x40\x10\xba\x1e\x27\xf4\x1\xd0\x18\x94\xde\x8a\x79\x23\x61\xd1\xf6" }, + { 0x53a060, "\x1e\x91\xb3\x15\xe7\xc6\x8d\xfe\xc9\xb5\xa6\xdf\x86\xa\x8e\x2b\x54\xbf\x2c\x1d\xbd\x9e\x5f\xcf\x6\x4d\x14\xf\x9c\x2f\x3f\xe8\x49\x1b\xa7\x4a\x10\x88\x7d\xbe\xb0\x35\x11\xe1\xa4\x6d\x30\x2e\x38\x60\xf6\xf7\xdb\xb7\x33\x75\xc\x20\x77\xa9\x9f\xef\xf4\x9b\x79\xfa\x5e\xd5\x3a\x3e\xe6\x44\xd8\x17\xda\xe5\x31\x78\xde\x39\x19\x93\xb4\xa3\xcb\x48\x9d\x45\x21\xf1\x67\xed\xce\x29\x95\xe0\x55\xc1\xfc\x5c\x82\x5\xd3\x80\x76\xab\x72\xb\x97\xd1\xf3\xea\xae\x34\x2d\x98\x73\xc2\xf5\x26\x8a\x1\x37\xfd\x47\xeb\x5d\x0\x56\x8\x66\x36\xd6\x7b\xb2\xe9\x70\xc7\xa5\x7a\x6b\x4c\xdd\x74\x6a\xbc\x43\xc8\x81\x64\x62\xa0\xd2\xfb\x83\x4e\x53\x1c\x52\xcc\x1a\x59\xd0\x99\xf8\x3b\x5a\x28\x41\xf0\xd9\x40\x90\xc0\x69\x7f\x4f\x8f\x8b\x42\x18\xe2\x57\xb6\xb1\xe4\x16\x61\xbb\x23\xa2\xd7\x1f\xc4\x85\xa1\x7c\x9\x65\x8c\xb8\x58\x7\x22\x12\xdc\x13\xcd\xc3\x89\x2a\xee\x27\x7e\xa8\xe\xba\x3d\x4b\x96\x50\x3\xac\x94\xad\xec\x6f\x5b\x87\xb9\xaf\xd4\x63\xf2\x6e\x51\x84\x68\x92\x25\xaa\xe3\x46\x3c\xc5\x24\x4\xd\xff\xf9\x2\xca\x9a\x71\x6c\x32" }, + { 0x53a588, "\x87\xca\xb5\xe\xb6\xee\x76\xd4\xda\x6a\x2b\x3b\x46\x9e\x44\x1d\x38\x3\xa\xb3\x1b\xf5\xea\x80\x94\xe6\x33\x43\x95\x0\xe1\x5c\x41\xc8\x97\x36\xaf\x34\x53\xb0\x6d\x29\xf9\x32\x2\xd6\x75\xbe\x7\xae\xe3\x6c\xa8\xe5\x4d\x56\x68\xb\xf4\x5d\x51\xc5\x54\x6b\x85\xba\x65\x86\xa7\xa9\x2f\xf1\x28\x5b\x4\x9c\xe7\x3f\x70\xd\xd5\xbf\xac\x5e\xad\x5a\x6\x2d\x30\x45\xd2\x17\x8d\x25\xed\x16\xc7\xd3\xde\x78\x22\x4a\xa0\x20\xe2\x89\x11\xa6\x2e\xff\xfc\xec\xfe\x9d\x18\xfd\x27\x60\xb1\xc0\x81\x99\x69\xa5\x64\x3d\xf2\x39\x1c\x9b\xc9\xc4\x8a\x21\x1f\x57\x4b\x5\x62\xb2\x14\x59\x2a\x12\x5f\xd1\x50\x90\x52\xcf\x1\x9\x4f\x7d\x74\x10\x42\x19\x8e\xe0\x40\x8f\xc2\xc\x82\x6f\xbb\xa4\x63\x55\xd7\x24\xab\x92\xbd\xf8\xcb\x8\xe9\x26\x49\x58\xf3\x1a\xc1\xd9\xdb\x4c\xbc\xb8\x84\xc3\x88\x8c\x98\x77\xeb\xcc\x3c\x83\xdf\xfa\x79\x15\x91\x7e\x3a\xf\x93\x66\xce\xa2\x7b\x37\x9a\x1e\xd0\xa3\x71\x3e\x47\xaa\xb4\x23\x96\xe4\xb9\x4e\x7f\xf0\xcd\x9f\x61\xf6\xfb\x7a\xdd\x73\xb7\x13\x7c\x35\x2c\xa1\xe8\x8b\x31\xd8\x72\xc6\x67\xdc\x6e\xf7\x48\xef" }, + { 0x53a688, "\x62\x6f\x9b\x9c\x31\x48\x4c\xca\xc1\xe6\xa2\x2e\xed\xb4\xe2\xc8\x8f\x45\xc7\x76\x7a\xa5\x40\xb8\x15\x36\x93\x13\xc2\xf6\x17\x2f\xf0\x23\xc5\x95\x79\x1e\xba\xc\x73\x8\x0\x60\xc9\x1f\x54\x58\xc6\xbb\x2c\xb3\x68\x55\xbe\x41\xfa\xc0\x2\xa7\xbd\x78\x57\xa9\x69\x6d\xe4\x12\xe8\x7\x3f\xac\x6c\x16\x4\x87\xb5\xa0\x33\x5e\xe1\x28\xee\x4f\x6b\x50\x99\xaf\x51\xbf\x7c\x7d\x6\x5c\xfe\x6a\x53\x9d\x2a\xd4\x14\x66\xcc\x65\xa3\x3b\xfd\xfc\xf9\x3\xb2\x19\x8e\x91\x49\xdf\x1\x44\xa\x98\x9f\x3a\x80\xf8\xb1\x42\x32\x3d\x22\x37\x8a\x35\xae\xd0\x8c\xdc\xab\xc3\x18\xd9\xe5\x10\x5d\x38\x27\xaa\x52\x3c\xf\x74\xf5\x90\xe7\xec\xd1\x81\x84\x2d\xd5\x8b\x82\x5b\x46\x11\x5\x4a\x4b\xea\x5a\xb\x92\x24\xf4\x1b\x5f\x21\x9e\x7f\xff\x6e\xb6\x8d\xfb\xdd\xcb\x1d\xf2\xe3\xb0\xef\xb7\x4e\x25\x86\xa1\xce\xcd\x72\x34\x64\xd3\xf7\x83\x94\x89\x9a\xd\xd8\x71\x67\xad\xbc\xf1\xa6\x63\x88\xd7\xe\x70\xc4\x20\xde\x3e\xd2\x7b\xb9\x1c\x1a\x39\x30\xda\x59\x47\x43\x29\x9\xe0\xcf\x77\x4d\x75\x97\x56\xdb\x2b\xa4\xa8\x7e\x96\x85\x26\xf3\xd6\xe9\x61\xeb" }, + { 0x53a7c8, "\x84\x5c\x65\xae\x56\xa1\xcc\x60\xa9\x28\x29\xf5\x35\x54\x33\xd1\xd6\x48\x44\x68\x34\xef\xee\xf3\x80\xa5\xcf\x2c\x22\xdf\xac\x53\x18\x2a\x19\xdb\xf1\x3d\xbb\x1b\xc4\xf2\xa6\xbf\x32\x2b\xe7\x8c\xb6\xba\xf8\x8b\x1c\xb7\xfe\x11\x75\xf6\xf7\x59\x76\x9c\xb1\x6e\xb4\xc6\xd\xb2\xb8\xc\x1f\x6\x12\x62\xa0\x47\x74\x5e\xd3\xde\x6a\xe\xaf\xc1\x8d\x57\x7\x89\x0\xa8\xbc\x51\x95\x4d\x97\x98\xfb\x9a\xea\x61\x7d\xe5\x50\x4f\xdd\x52\x64\xe4\x16\x8\x70\xff\x40\xd7\x9\x87\xad\xc7\xf4\x4c\x83\xd2\x63\x6c\xeb\x3\x79\xf\x13\x27\x88\xc5\x8e\x20\x3c\xb9\xf0\xc9\x94\xc3\x96\x1\x67\xb\x3e\x7e\xd8\xd5\x2d\x42\x58\x6f\x6b\xcd\x86\xdc\xab\xed\xfc\x24\xa3\x5d\xe9\x9d\x3a\x38\x8f\x55\x30\x46\xca\xc2\x25\x5f\x66\xc8\xe2\x23\x7a\x6d\xfa\xce\xe6\x36\x45\xb3\xb5\xfd\x92\x1a\x39\x21\x31\xaa\x7f\x71\x9b\xbd\x93\x43\x4\xa4\xd0\x81\x41\xf9\x78\x5a\xa7\x17\xcb\x9f\x3b\x90\x2\xe3\x5b\x69\x1e\xec\xe1\x5\x91\xd4\x4b\x7b\x8a\x77\x4a\x7c\xd9\x82\xc0\x26\xbe\x85\xda\x14\x2e\xa\x9e\x72\x4e\xe0\xa2\xe8\x99\x3f\x37\x10\x2f\x15\x73\xb0\x1d\x49" }, + { 0x53a8c8, "\xfe\x9b\xe5\x18\xb2\x38\x1d\xd4\x98\xa9\x52\x58\xc3\xe1\xe8\xbf\x39\x4a\x36\x9\x6f\x7e\xb0\x4f\xca\xcd\x3\xe0\x66\x1e\xdf\xd2\x59\x95\x71\x2a\x16\xa2\x86\xcf\x64\xf0\xdb\xf3\x8e\x35\x7f\x19\xb1\x33\x90\xbe\xc0\x8f\x5d\x6e\x51\x56\xda\xaf\xa\x25\x54\xd3\x41\xb9\x7d\x82\x62\x97\xfc\x4d\x88\xe3\x57\xff\xb4\xc7\x1c\xbd\x80\xef\xe6\x1\x23\xce\x17\x44\xdc\x67\x26\x6a\xbc\x8d\x45\xb8\xa3\x1f\x9e\x7\x74\xb3\xc9\x0\x9c\x78\xf4\xf1\x32\x49\x14\x73\xc5\x7a\x65\x5b\xf\x42\xbb\xa4\xb\xcc\xe7\x27\x9a\xfb\x55\xd6\xd\xad\xeb\x10\x79\x1a\x2d\xed\xe4\x2e\x5a\x7c\x3f\x3c\x47\xa6\x20\x92\x46\xb5\x84\x7b\x37\x89\xee\x2b\xf8\xa1\x30\x48\x9f\x87\x68\xb7\xae\xa0\x29\xb6\xc6\xf9\x2f\x22\xf6\x43\x83\x5c\x21\x5\xd1\xfd\x6b\x50\x11\x93\x8c\xe2\x28\xa5\x3b\x2c\xba\xd0\xcb\x91\x4c\xc1\x69\x53\x75\x12\x85\xab\x4\xf2\xd8\x34\xf7\xc2\x40\xec\x3d\xe9\xc\xa7\xd7\x8a\xaa\xac\x99\x15\x2\x31\xea\x6\x60\x4e\x72\x70\x94\x63\xfa\xc8\xc4\x3a\x4b\x13\x3e\xa8\xf5\xde\x24\xd9\x6c\x76\x5e\x96\x5f\x1b\x6d\x9d\xd5\xdd\xe\x77\x61\x8b\x8\x81" }, + { 0x53aa20, "\xfc\x7a\xc6\x79\x44\xfa\x78\x60\xb5\xd8\xa\xc0\x19\x5e\x12\xa9\x29\xb3\xcd\x75\xe3\x7b\x3a\xf1\x85\xab\x2f\x33\xe9\xc1\x14\xf0\x96\x82\xf9\x72\x77\xa3\xdd\xc9\x8c\x53\x4e\x1\xd1\x2e\x5\xec\x16\xdb\xd7\xb2\x35\x10\x74\xb1\xf6\xbe\x8a\x15\x50\x92\xe0\x7\xde\x24\x9c\xe7\x22\xda\x5d\xc3\x9e\x42\x59\xb\x11\x4a\xaf\x5f\x76\xd0\x94\x2c\x3f\x48\x97\x99\x2b\x34\x1e\x89\x6b\x23\x30\xce\xc\x8b\xaa\x57\x91\xc7\xea\xf4\xb8\x21\x8d\x3e\x70\x6\xa2\x64\xd3\x9f\xf3\x4b\x13\x2a\x1c\x7d\xee\xa1\xe5\x58\xbf\x98\x3\xfb\x6e\x81\x61\x56\x8e\x71\xa6\x26\x5a\x46\x80\x7e\x9\x37\xa4\x6a\x90\x1b\x1d\x51\x27\x5b\x2d\xba\x4f\xbb\x7c\xa8\x93\xf7\x4\xf5\x68\xd5\xc8\xc4\xef\x36\x84\xe8\xcf\x62\x2\xcc\x67\x49\xb0\x43\xc2\x3b\xa7\xa5\x1f\xfe\xac\x40\xb9\xc5\xae\x6f\xd4\x9a\x95\xbc\x17\x47\x9d\x86\xb7\xfd\xeb\x63\x65\x39\x69\x3c\x55\xe1\x9b\xd2\x66\xdc\x73\xbd\xf8\x83\xff\xf\xcb\x52\xb4\x88\x4d\xe6\x8\x6c\x20\x18\xe2\x45\x25\xe\xf2\x32\xdf\x38\x41\x4c\x5c\x31\x8f\xb6\xed\x0\x54\x28\x3d\xe4\xd9\x6d\xca\xad\xd\x7f\xd6\x87\xa0\x1a" }, + { 0x547b00, "\x72\xf0\x14\xcb\x61\xa5\xb2\x2\x75\x22\xc3\x9d\x5a\x63\xfa\x5f\xd9\x55\x58\x43\x24\x7d\x77\x93\xba\x50\x1d\xf7\x49\x18\xb0\x42\xbb\xec\x52\x38\xdc\xc8\x16\x54\x17\x19\x89\x67\x33\x3c\xa\xad\xc9\xde\x81\xed\xbd\xe\xb\x6d\x46\x30\x35\x2b\x8c\xa0\x1c\xd\xfd\xa1\x70\xc6\xd8\x41\xb3\xc0\x44\xeb\x92\xbe\x6b\x98\x1a\x76\x71\xc5\x51\x56\x80\xfc\x1\x53\x4b\xd0\x8b\xd2\x7b\xe7\x15\x5d\xe5\xa6\x8a\xd3\x9b\xf4\x69\x23\xe8\xb6\xc7\xe2\x73\x9f\x88\xdf\xb4\x28\xee\xc2\x94\xb8\xf9\x7f\x4a\x57\x6\xf6\xbf\xc1\xab\xfb\xa4\x8e\xd1\xd7\xf5\x7c\xa3\x1e\x3b\x32\x3\xaa\x90\x5c\x48\xe0\xe3\xcf\xd4\xef\x59\xd5\x1b\x34\x1f\x95\xce\x7a\x20\x26\x87\xb7\x78\x9c\x4f\xa2\x12\x97\x27\x3f\xff\x7\x84\x96\x4\xaf\xa8\xea\x2c\x6c\xae\x37\x91\xa9\x10\xdb\xcd\xda\x8\x99\xf1\x4d\xcc\x68\x79\x2e\xb1\x39\x9e\xe9\x2f\x6a\x3d\xf\x85\x8d\xca\x29\x86\xd6\xdd\x5\x25\x3a\x40\x21\x45\xac\x11\xf3\xa7\x9\x2a\x31\xe4\xc\xf8\x6e\x3e\xb5\x82\xfe\x74\x13\x65\xe1\x2d\x8f\xe6\xc4\x0\x5b\x4e\xb9\x66\xf2\x62\x36\x4c\x83\x5e\x6f\x47\x64\xbc\x9a\x60\x7e" }, + { 0x547548, "\x7c\x11\x4d\x5b\x41\x55\x97\x3f\x59\xed\xda\x6f\x85\x33\x16\xc8\xb1\x18\x50\x6c\x9c\x38\x2\x71\x2e\xec\x93\xa1\xa5\x0\x91\xaf\x7a\x92\x1b\xc7\x3a\xa9\xbe\xb6\x9b\xe5\xee\x57\xf1\x99\x47\x4\x6b\xd8\x20\xf4\x3\xd3\x75\xe3\xb8\xdc\x7\x54\x4f\x2d\x37\x49\x14\x9f\x69\xc4\xf7\xc6\xf0\xce\x24\x7b\x7e\x89\x4e\x3c\x7f\xcc\x9\xe6\x2f\x61\xfc\xcd\x86\x62\x83\x56\x29\xd6\x32\xc\x76\xc1\x5c\x68\x51\xf3\xa8\xe2\x87\xcb\xe0\xdb\xb\xba\xe4\x46\x9a\x84\x95\xf\x10\x81\x82\x53\x1c\x26\xc2\x31\xb0\x8c\xb3\x9d\xd9\x96\x5a\x79\xd1\xb2\x25\x80\x1f\xa4\xff\x60\x44\x1a\xb9\x45\xf9\xd2\x6e\xd0\x5e\x35\x98\x66\xc3\x90\xae\xa0\x78\xb5\x34\x2c\x12\xf5\xcf\xaa\xe9\x77\x8b\x70\xde\xeb\x65\xbb\x72\xa6\x88\x58\xa2\x27\xc5\x4b\xbc\x19\xdf\x36\x1e\xa\x74\x15\x17\xbd\x22\xe7\xac\xf6\xf2\x30\xe8\x13\x1\xef\x8f\xd4\x2b\x23\x48\x5f\x21\x3d\x73\x8\xa7\xd\xfd\x63\x67\x4a\x8e\x6a\xd7\xb4\x3b\x40\xc9\xfa\x64\x39\x7d\xea\xab\xfb\xd5\x8d\x42\x8a\x6d\xca\x94\xc0\xe1\xad\xbf\xa3\x9e\x28\x3e\x1d\x43\x6\xb7\x52\xe\x2a\xfe\xf8\x5d\x4c\xdd\x5" }, + { 0x53b1d0, "\xf\x8\xef\x6c\x8f\x19\x5e\x9c\xdb\xec\x35\x6f\xe9\x5\xe0\xd\xf3\x17\xa2\xb3\xcf\x28\x46\xe1\xa0\x6\x4e\x38\x4d\x25\x3f\xb5\x12\x80\xb2\xa7\x3\xbc\xca\x41\x6b\x2f\x1d\x4b\x66\x6a\x68\xaa\xc4\x77\xa4\x59\x4\xbe\xc9\xb9\x7b\xd1\xc5\xde\x57\x85\xa9\xcc\xc8\x6e\x78\xb\x82\x2\x5f\xae\x51\x7f\x2d\x8c\xee\xcb\x69\x62\x67\x81\x87\x5c\x1f\x8b\x74\xa5\xe\xf2\x5b\xc0\xc2\x18\xe5\xfd\x95\x65\x20\x97\x58\xc6\x3b\xb7\x9\xdc\x21\x11\xe4\xe3\x16\xa8\x63\xf6\x33\x6d\x8d\x9e\xb6\x34\x7\x14\x36\x71\x60\x45\xfb\x4a\x9a\xea\x1b\x90\x31\xb0\x99\x1c\xd3\x7c\x24\x47\xe2\xdf\xe8\xc7\x29\x30\x1\x2b\xd4\x8e\xb8\xd6\x7e\x2a\x7a\x3d\xf4\xdd\xd0\xb1\xf0\x73\xab\xbb\xa6\xf7\x3a\x1e\xba\x52\x4f\xbd\x4c\xb4\x72\xc1\xe7\xfa\x1a\x54\xf5\xac\xff\x5d\x40\x37\xd9\x43\x23\x93\xa1\x3c\x79\xad\x44\x76\xed\xaf\x84\x94\x49\x50\x91\x10\x70\x5a\xce\xc\xd8\x0\xfe\x92\xd5\x55\x56\x2e\xeb\x89\x13\x88\xc3\x64\xe6\x75\xa3\xf8\xf9\xa\x9f\xcd\x61\x83\x96\xfc\x22\x9d\x7d\x2c\x53\xd2\xbf\xd7\x39\x3e\xf1\x48\x8a\x15\x42\x98\x27\xda\x26\x32\x9b\x86" }, + { 0x53b2d0, "\xab\xdf\x86\xff\xce\xfa\xaa\x1\xd2\x41\x9e\xe7\xbc\xc0\x77\x22\xe8\x7c\x4e\xfb\x8e\xf3\x33\xc9\x4b\x26\x60\x89\xc4\x69\x79\x96\x54\xcd\x10\x48\x23\x31\x38\x44\x82\xe5\x6a\x8\xd7\x3f\xe1\x28\xd3\xa6\x4c\x7\x34\x5b\x7f\xb0\xd\x81\xd0\xf\xc1\xaf\xcc\x3d\x99\x19\x24\x57\xb4\x2c\x8d\x7d\x58\x55\x27\x8a\x42\xb\xa2\xca\x53\xc5\xe0\xf4\x4f\x2f\x8b\x21\x2\x2d\x12\x65\xf5\xf2\xc8\xed\x1d\x47\x5c\x1c\xa8\x40\x7a\x8f\xda\x87\xd5\xb1\x4\x70\xea\xe\xeb\x29\xb5\xb8\x9f\xf8\x2a\x3b\xb3\xfd\x5d\x0\x71\x2e\xc2\x46\xec\x92\xf9\x6\x74\xe4\x6d\xa0\x59\x6e\x25\xa9\x7b\x5f\xe2\x64\x3e\x37\xfc\xd4\x9b\x5\x61\x84\x20\xa\xc6\xa7\x76\x83\x62\x32\xa3\x6f\xc7\x78\xa5\xf6\x30\x6c\xdc\xa1\x2b\xbd\xae\x15\x3a\xf1\x4d\x45\x5e\x75\x98\x68\xad\x1b\xd1\x49\x35\x6b\x52\x14\x1a\x11\x88\xbe\x8c\xac\xc\xe3\x66\x13\xd9\x17\xcf\xdd\x93\xbf\x39\x56\xf7\x18\x94\x63\x3\x1f\xd8\xb6\xcb\xf0\x9d\x9\x16\xe6\x90\xa4\xb2\xba\x85\x3c\xd6\xfe\x36\x50\xc3\x43\x80\x1e\xb9\xee\xb7\x9a\x51\x9c\xdb\xef\x67\xde\xe9\x7e\x97\xbb\x5a\x72\x4a\x73\x95\x91" }, + { 0x53b418, "\xc6\xcb\x61\x7f\xb\x44\x1c\xea\xc1\x87\x7d\x4e\xd4\x23\xbc\x82\x10\xa7\x3e\xaa\xbf\x46\xb2\xd2\xa3\x33\x20\x27\xc0\x9f\xe2\x45\x6b\x96\x6\x8b\x1d\xb7\x26\x56\x88\xc3\x13\x2b\x15\x37\x9e\x57\xe5\xc8\x21\xa9\x92\x2\x38\xfe\xd7\xba\x9a\xc7\x5a\x84\x28\x58\xfb\xa8\x90\x42\xf4\x3d\xfa\xdc\xa\x4c\x48\x8f\x8e\x39\x3b\x63\x5\x79\x4a\x2c\x65\x71\xe\xdb\x29\xe0\x50\x1\x8d\x19\x31\x94\xd\xb4\x9c\x6c\xb3\x68\xc2\x2e\xce\x97\xe6\x2d\xcf\x36\x91\x1f\x7a\xf\xc4\x8a\x5d\x9b\xad\xfd\x93\xd8\x3f\x9d\x64\x85\x4d\x99\x69\xd5\xd1\x18\x1a\xd9\x12\x2f\xf5\xf2\xda\x80\x51\x1e\x4\x60\x7c\xd6\x86\x54\x62\xac\x5b\x17\xf8\x66\xa4\x43\x49\xff\x0\xe1\x9\xb9\xed\xdf\xd3\x55\x72\x16\x4f\xe9\xe3\xab\x81\xe8\x2a\xcd\xb1\x53\x77\x75\xb0\xdd\xc5\x67\xf3\xa6\xe4\x34\x3a\x40\x1b\x83\x6f\xef\xa5\xa2\xca\x73\xb5\x47\x8\x76\x11\xc9\x3\x3c\xf7\x6a\x25\x41\x30\xf9\xaf\x5c\x95\xa0\xb6\x35\x78\xbe\xd0\x14\xec\x59\xbb\x70\x5e\x74\x6e\xb8\xae\x7e\xfc\x7\x6d\x52\xe7\x32\x8c\xcc\xeb\xf1\x89\x7b\xbd\xa1\xf0\xc\x98\x24\xf6\x5f\xde\x22\x4b\xee" }, + { 0x53b550, "\xa0\xb9\x6e\x86\xd9\x98\x97\x73\x25\x76\xf\xcc\x7\xe8\x7a\x79\xb5\xe5\x38\xf4\xc2\x16\x10\x2f\xa2\xec\x3a\xb0\xdf\x5f\xb4\x6a\xb1\x60\xd4\x3e\xd2\xde\x6\x95\x62\xd5\xab\x9\x13\x11\x92\xa6\x37\xa\x2c\x64\xf1\x80\x1b\xfc\x31\x22\x3b\xff\x94\x70\xca\x84\x24\xdd\xd7\xd3\xb2\x32\x3d\xb6\xb7\xa9\x26\x9b\x48\xc0\x1f\xaf\x83\x6c\x58\x29\xc3\x7d\xc5\xf3\x8d\xb\x8a\x2a\x69\x1d\x91\x7e\x9c\x3\xb8\xf2\x9f\x45\x28\x4c\xbb\xcb\x2b\xfd\x61\x7f\xb3\x99\x6b\xbc\x7c\x19\x52\x2\x78\xea\x5c\x49\x74\xa7\xc7\x59\xf6\xf0\x8f\x81\x82\x8c\x1\xf5\xc4\xad\x21\xa5\x0\x5a\x39\x75\xd8\xc\xc1\x85\x17\x5b\x77\x43\xc6\x89\xa1\xf9\x20\x93\xee\x12\x1e\x1a\xe1\x57\xf7\x4\xae\x18\xcf\x33\x47\xfe\xe9\x8\x71\x65\xbd\xd\xcd\x6d\xe4\xac\xba\xdc\xd0\xf8\x4e\xe0\x8e\x5d\x41\x3f\x54\x42\xa4\x40\x34\x5e\x87\x7b\xe3\xdb\xe7\x51\xd6\x9a\xaa\xce\xbe\x36\x67\x35\xd1\x68\x4f\xfa\x23\xfb\xed\x8b\x44\x9d\x50\xeb\xc8\x14\x15\xe6\xc9\xe\x88\x4d\x66\xa8\x5\x3c\x46\x2e\x27\x6f\x72\xbf\xa3\x2d\x96\x9e\xda\xe2\x63\x1c\x53\x55\xef\x56\x4b\x90\x4a\x30" }, + { 0x53b718, "\xd4\x58\xf7\x7\xc3\xfd\x69\x49\x23\x17\x65\x84\x9b\xf\x77\x97\xb\xc4\x67\xb1\xbd\xba\x85\xc7\xff\x8f\x32\x28\xea\x6b\xd7\x9f\x31\xab\x9e\x5b\x11\xa8\x36\x8\x96\xa4\x4f\xa2\x70\xed\xd3\x91\x2a\xd9\x73\x6\xb4\xaa\x35\x72\x48\xf3\x0\x1e\xc0\xdf\x2e\x29\xdd\xb7\xa\xd\xaf\x2f\x56\x19\xc\x39\x5c\x46\xec\xac\xfc\x7d\xe6\x92\xf2\x15\xa3\x5d\x93\x3d\x98\x2d\x79\xb0\x52\x5f\xb3\x89\x3\x4\x1d\x55\x42\xcc\xe9\x83\x16\x80\xd2\x8e\x5a\x66\x1b\x47\xfa\x88\xa7\x9a\xd1\x25\xf8\x44\xe2\x26\x59\x9\x61\x40\x3c\x34\xd8\x30\x45\xbb\xc6\x7f\xe7\xbc\x7b\xa9\x3a\x1c\xe5\x68\x21\x5e\xb2\x12\x2c\x74\xcf\x8a\xb9\x24\x1\xcd\xe4\xb5\x9d\x1f\x18\x3b\xe0\x71\x4e\x4b\x4d\x62\xa0\xd0\xc2\xd6\xeb\x43\x51\xf9\xa6\xf4\x2\x90\x1a\xa5\xef\x5\x7c\xb8\x57\xc1\xfb\x8d\xde\x50\x33\xf5\x82\x86\x3e\x76\xc9\x8c\xa1\x8b\xc5\xee\xbe\xe3\xda\xae\x14\xf1\x6f\xe1\xd5\x10\xf6\x27\xfe\x6d\xce\x9c\x6e\x94\xe8\xb6\xca\x60\x37\x53\xe\x54\x3f\x99\x75\x81\x20\xcb\x4c\x7a\x6c\x38\x78\xdb\x64\x95\x6a\x13\x4a\xf0\xbf\x22\x41\xdc\x87\xc8\x7e\x63\x2b\xad" }, + { 0x53b838, "\xe3\x57\xc6\x8b\x64\x27\x80\x87\x9b\x49\x29\x6e\xa8\xda\x5b\x20\xbb\x69\x19\xd3\x5e\x30\x9e\x9d\x24\xcd\x2c\x1c\x79\xb\x9f\x8d\xff\x41\x6f\x68\xbd\xd9\x55\xcf\x36\xe6\x5f\x93\x99\x33\xe1\x72\xf2\xe\xd2\xe2\x2e\xd7\xa7\x32\x31\xa2\x25\xfd\xef\x67\x21\xe4\x2d\x3e\xd0\xac\x34\x35\xf1\x44\xee\x5a\x83\x71\xc1\x59\x3f\xa3\x10\xfb\xa6\xcc\x0\x40\x18\x3b\x9a\x47\xfa\xa5\x66\x5d\x6a\x2f\x16\x23\x88\x7a\x84\xc5\xc9\xea\xce\x58\xeb\x11\xaf\x5\x37\x89\x17\x1a\xe5\xb8\xa\xc0\x95\x48\x81\xb7\xf\xf6\x7e\x60\x8f\x8\xd5\x42\xd1\xf8\x45\x2b\x5c\x1b\x76\xf0\xc8\xf4\x3\x7d\x50\xb5\x86\xb3\xe0\x7b\x3a\x1f\xdc\x92\x28\xca\x61\x4a\x78\x1e\x51\xdd\x3d\xbc\x77\xd8\x53\xf9\x94\x74\xc3\x9\x4f\xb6\xec\x2a\x91\x8c\xd4\x38\x4e\x26\x1d\x96\xdf\x4\xd\xab\xa4\xfc\xc4\x15\xa9\x3c\x97\x6b\x7\xde\x9c\xe8\x22\xe7\x2\x6d\xa1\x39\xf3\x54\xba\x6\x65\x90\xb0\x6c\x63\xad\xf5\xb4\xb9\xc\xe9\x1\xc7\xd6\xc2\xb2\x56\xbe\xaa\xb1\xcb\x52\x82\x14\xed\x7c\xfe\xae\x85\x8a\x13\xbf\x4c\x98\x4b\x62\x12\xa0\x4d\x7f\x73\x8e\x43\x75\xf7\x46\x70\xdb" }, + { 0x53bc10, "\xf\xc6\xa1\xa3\x50\xbd\xce\xa7\x9\xa4\xf7\x1b\x8c\x3d\xf0\xe5\xdf\x3c\x20\x75\x3f\xdd\x12\x81\xde\x3b\xaf\x68\xf6\xea\x41\x58\xeb\x5d\xae\x61\xa\x46\xed\x91\x23\x65\x99\x86\x27\x92\x8e\x83\x51\x8\x4b\x3e\x32\x1f\xbf\x5b\xa9\xc5\xfe\x7c\xf4\x15\xdc\x89\xf5\x2b\x72\xad\x6b\xba\x5a\xf2\x24\x53\xe7\x29\xee\x4\xd\xf3\xe0\xb7\x67\xcf\xb0\xc3\xbc\xc9\xfa\x66\xcd\xb4\xd5\xd9\x71\xe3\xb8\xa0\x25\xf8\x78\xc4\x5\xe9\x87\xfd\x35\x1a\x98\x9f\x16\xb3\x6\x26\x22\xb2\xd6\x74\xc7\x84\xc2\x7d\x64\xec\x54\x37\x4c\xef\x70\xe\x48\x9b\x4e\xd7\x80\x7\x73\xbe\xd3\x2\x3\x94\xfc\x59\xb5\x8b\x21\x9d\xf1\x69\xe1\x10\x38\x2d\xd2\x45\x30\x42\x85\x6e\x52\xc\x76\x82\x6d\xa6\xd4\xe4\x90\xa2\x62\x7e\x1\xe6\x1d\x4a\xff\x8d\x79\x8a\x55\x77\x2f\xca\x9e\x47\x19\x6c\x28\xb6\x93\x97\x6a\x18\x5c\x4f\x95\x6f\xc0\x14\x40\xdb\xa8\x17\x34\x36\x39\x56\x11\x13\xd1\xc8\xcc\x1e\x2c\x5f\x43\x5e\xa5\xe8\xd0\x9a\xe2\xab\xf9\x4d\x3a\xaa\x1c\xb\x2a\xb9\x31\x7a\x60\xac\xfb\xb1\x44\x0\x88\x8f\x33\xc1\x7b\x49\x2e\xda\x63\xd8\x96\x57\xcb\xbb\x7f\x9c" }, + { 0x53bd10, "\xba\x9d\x27\x84\x89\xcd\x60\x67\x68\xd9\x1f\xea\xf2\x15\xd2\x6\x12\x5d\x54\x75\xbc\xa0\x29\xe8\x16\x70\xc8\xf1\x9\xa4\x26\x30\x49\xd\xbd\xf4\xf8\xef\x8d\x1d\x41\x38\xf7\x9c\x1e\x87\xf3\xbe\x7a\x37\x88\xcb\x36\xe6\xfc\xd6\xd0\xad\x78\x71\x93\x96\xf0\x3c\xfe\x57\xe9\x4f\x7d\xaa\xf9\x62\x9a\xab\x18\x39\xbf\xc\xc3\x4d\xe7\x97\x7f\x8a\x3f\x1\xc9\x80\x76\x9e\xfb\xa1\x3e\xfa\xb3\x45\x3b\xdc\x5c\x5b\x58\x61\x2b\xec\xb4\x55\x1a\x9f\x6a\x3\x11\x32\xd1\xe1\xb2\xa8\x6c\xe4\xa3\xa7\x4b\xf5\x17\x40\x6e\x8\xff\x81\x4c\x5\x79\xae\x1c\x83\x46\x25\x6b\xdf\x24\x64\x2e\x4e\x21\x31\x2\x73\x6f\x3a\x8b\xc4\x7b\xac\x23\x72\x20\x65\x7\x33\xa2\xe0\x47\x77\x85\x2d\xdd\x0\xf6\xd8\x9b\xb9\x63\xd4\x53\xaf\xb7\xda\xa5\xc5\xc6\x2f\xa\x6d\x92\xb8\x50\x74\xbb\x14\xd3\xf\xb0\x4a\x95\xe3\xce\xee\xca\xe\x91\x82\x8c\x3d\x8f\x22\xa9\xb1\x86\xc0\x5f\x28\x90\xdb\x7c\x4\x94\xb\xc7\xd5\xfd\xc2\x2a\x1b\x98\xed\xcc\x59\x8e\xe5\xe2\x42\xb6\x34\xd7\xa6\x13\x2c\xc1\x44\x51\xcf\x99\x48\x69\xeb\x7e\xb5\x52\x35\x19\x66\x10\x56\x5e\x43\xde\x5a" }, + { 0x53be50, "\x64\xe7\x66\xd5\xf\xc3\xc8\x20\x4e\x9\xd3\x30\x3f\xef\xa9\x80\xe3\x72\x42\x68\xa5\x51\x99\xb\xbf\x4d\xd1\x34\xaa\xdf\x2f\xec\x55\x58\xb0\xdb\xb8\xd6\xc5\x9b\x9a\xa\xbb\x40\xc2\xb2\x2e\x78\x89\x97\x5d\x74\xf7\x52\x5b\xa1\x2b\x83\xae\x7b\xd9\x5e\xfe\xfd\x98\xd2\x29\x13\xc6\x8e\x5c\xca\x7\xd4\xe4\x49\xa8\xa0\xff\xee\xc9\xcf\x16\xb4\x61\x8f\x60\x1\x84\xb5\xac\x62\x54\x6\x2d\x63\xa7\x48\x73\x1e\x92\x2c\x3c\x82\xe1\xcb\x10\xf2\xd8\x50\xf1\xfb\x96\xc\xd7\x6b\x87\x77\x7e\x15\x8a\xde\x31\xe\xab\x59\xd\x3b\xf3\x79\x1f\xfc\x81\x27\x1a\xf9\x94\x2a\x45\x88\xfa\x47\xe9\x7d\xb7\xed\x7c\x32\x7f\xe2\xbd\x6f\x18\x76\x4b\x65\x70\x22\x1d\xaf\xeb\x28\x4f\x9c\xbc\xf8\xcd\xc0\x1b\x43\xb1\xea\xa3\x6c\x12\x35\x44\x8d\x25\xb3\x1c\x24\xc4\x9d\xa2\x36\x56\xb9\x19\xe8\x21\x11\xf0\x75\x5\x17\xc7\xce\x41\x4\x4a\xe0\x6e\x67\x69\x4c\xdd\x53\x3e\xa6\xd0\x3d\xdc\xcc\xe6\x9f\x93\xc1\x33\x90\x57\x37\xb6\xa4\x9e\x6d\x8b\x46\xad\xba\x86\x38\x85\xf6\x5f\x8\x14\x2\xe5\x8c\x5a\x39\x95\xf5\x91\xda\x7a\xbe\x23\x26\x6a\x71\x3\xf4\x0\x3a" }, + { 0x53bf68, "\x36\xbe\x8a\x3c\x5d\xaa\xc4\xf5\xfa\xc\x3f\xd\xa0\xc6\x49\xc1\xe1\x20\x7a\x31\x84\x87\xf7\x9f\x71\x6b\xeb\xa8\x11\x35\x22\x78\xe4\x83\x97\xdd\x53\x39\x45\xb9\x3\xad\x4c\x34\x8e\x79\xfc\x57\xb8\x47\x66\xfd\x54\x96\x33\x48\x4b\x88\xf9\x7\xa2\x3e\x64\x1b\xb2\xf\x5f\xcb\xcd\x18\xfb\x74\x70\xb1\x2a\x37\x2c\x98\x9a\x7c\x30\xe2\x75\x28\x26\x63\x1c\xec\x3a\xa3\x8\x85\xc5\xe\x2b\x4\xe9\xc9\x4f\xd1\xd2\x25\x9d\x6c\xd0\xfe\xce\xca\x15\xbc\x82\x2d\x27\x3d\xbb\x56\xe6\x24\xd7\xe3\xf2\x6e\x12\x9c\x6a\xe0\xe8\x4a\x9b\xd5\x10\x86\xc7\x90\x7d\x61\x67\xd8\xb5\xf1\x1a\x8f\xf8\x89\x4d\xa\xe5\xf4\x7b\x60\xa1\x40\x42\x2f\x1\xb6\x1f\xef\xd3\x81\xc2\x5b\x6d\x41\x5c\xff\x95\xc8\x76\x94\xd6\xd9\x19\xf3\x38\xb4\xdf\x59\xb\x52\xb7\xab\x73\x14\x62\xbf\x9e\xb3\x21\x3b\x17\xba\x58\xcc\xdb\x6\xda\x5\xa5\x16\x4e\x80\x1e\xa7\x8d\xa6\x7e\x99\xae\x0\x5e\x2e\x77\x50\x65\x29\x7f\xd4\xee\xf6\x2\x13\xdc\x69\xa4\x44\x8b\x32\xde\x92\x68\x1d\x51\xcf\xa9\xbd\xf0\xc3\x72\xed\xb0\x8c\xac\xc0\x23\x9\x46\x55\x91\x43\x5a\xe7\x93\xaf\x6f\xea" }, + { 0x53c0e8, "\x6d\x90\x16\x84\x89\x48\x99\x24\xad\xbc\x92\xe\x6a\xf5\x4e\xea\xaf\x38\xcb\xbd\x8a\x12\x9e\xd6\xb\x8e\x9c\xf8\xb5\xa1\x81\xe3\x9d\xfa\x65\x77\x6\x7b\xb8\x98\xda\x54\xf6\x3b\x7\x93\x5c\x7a\x15\xfe\x2a\x30\x36\x80\x39\x8c\x2b\x4b\x5b\x21\xe0\x13\x6c\x29\xc0\xbb\x27\x3a\xdd\x3f\xa2\xe9\xac\x4c\xef\x44\x70\x19\x5a\x72\x7c\xc5\x3c\xdc\xcf\x88\xf2\x51\x47\x61\x3\x67\x82\xfb\xed\x18\x9f\xb7\xa7\xb0\xc4\xf\x26\x5\x28\xe5\xd2\x4f\xa\xd0\xb3\x1\xd5\x1a\x37\x6e\x8\x9a\x1f\x60\x45\x5f\xf9\x33\x9b\x6f\x2d\xca\x9\xb4\x3e\xbf\x96\x95\x4a\x11\x1d\x74\xcd\x87\xce\xb9\x20\x68\xc3\x40\xf1\x31\x8d\x25\x7f\x2\x17\xb6\xcc\xd3\xa5\x59\xf4\x91\xd1\x83\x4d\xc2\xe1\x22\xec\x4\x52\xf0\xd9\xae\xc8\x56\xf7\xd4\x85\x42\x1e\x35\x1c\x7e\xeb\xe2\x76\x6b\x49\x75\x3d\x58\xff\x57\xbe\x43\x46\xf3\xba\x2e\x69\xa3\x34\x78\xb2\x73\x5e\xe7\x1b\x8f\xd8\x8b\x94\xa8\xe6\x97\x7d\xde\x2c\xa6\xab\x23\xfd\x50\xe8\x79\x62\xa4\x66\xfc\xee\x86\x41\xc6\xd7\xa0\xc7\xe4\x5d\xc9\x53\x32\x63\xaa\xc1\x64\xdb\xb1\x0\x10\x2f\xc\xdf\xd\x14\x55\x71\xa9" }, + { 0x53c240, "\x74\x4b\x7\xe3\x16\x70\x33\x94\xb\xb6\xe6\xc0\x62\xd5\xe5\xfb\xbe\x8d\x67\xc8\xc7\x58\xc6\x2e\xf9\x47\x77\x12\x4a\x68\x6c\x84\x35\xe1\x69\x14\xc4\x48\x32\x11\x9d\xb1\xe\x5a\xd0\x17\x60\xed\x28\x21\xef\x10\x2b\x5b\x31\xab\x23\x89\xf0\x18\x66\x0\x87\x99\x30\xe2\xda\x49\x7f\xd2\x4d\xcc\x81\xd6\xdf\x37\xd\x1a\xaa\x51\x97\xb3\x73\xd3\x50\xb2\xdd\xc3\xbf\x3e\x92\x1\x64\xf4\xcd\x1c\x8f\xaf\xa9\x24\x36\x91\x9e\xa4\xd1\x75\xc9\x59\x42\x4e\xb4\x6a\x4f\xa1\xe8\x6d\x61\x63\xea\x3c\x38\x5\xe9\x9c\x46\xb9\x9f\xb7\x43\xeb\xf5\x5c\x76\x3b\xd7\xba\xa5\x7b\x6f\x5f\xde\xad\xe7\x15\x2\x2f\x5e\xf7\xa6\xbb\x52\x95\xd9\x86\x26\xa\xa8\x8\x20\xf1\x45\x13\xca\xf6\x65\xcf\xe4\x98\xdc\x80\x19\x7a\xfd\x9b\x4\x1e\xa3\x9a\x5d\x72\xb5\xfa\x3\x53\xc2\xc\xa7\x57\x55\x7e\x29\x6e\x83\xb0\x1f\xbd\x8e\x93\x8a\x79\x96\x39\x7d\x88\x27\xcb\x71\xf\xf3\xfc\x25\x40\x3a\xd8\x85\x2c\x6b\xd4\x2d\x34\x54\xec\x8c\xe0\x1b\xb8\x8b\x3f\xf2\xac\xff\x7c\xa0\xee\xbc\x22\x44\xce\xc5\x9\xdb\x82\x78\x90\xae\xc1\x6\xa2\x41\x4c\x1d\x3d\xf8\xfe\x2a\x56" }, + { 0x53c368, "\x8b\x9c\xe5\x1a\x2d\x5a\xf5\xa6\x77\x3\xd4\xb4\x99\x84\x32\x53\xcd\xca\x43\xb5\xe2\xcb\x1e\x8c\xc7\x81\x89\x49\xb3\xf7\x71\xbb\x4e\xe8\x7d\xaa\x2e\xd0\x7f\x3e\xf1\xe9\x60\xbf\x87\xe6\x6c\x6d\xff\x47\x10\xc5\xc9\x3a\x5e\x30\x3b\x0\x4a\x18\x63\x11\x8e\x92\xab\xf9\x8a\x9f\x9e\x1d\x45\x62\xf8\x83\xce\x5d\xcf\x78\xdd\x93\x8f\xc2\x76\x2b\xd3\x54\xd\x4d\x44\x31\xa\x42\x91\x23\xfd\x36\x48\x79\x2a\x4f\x2c\x80\x7c\x7\xb9\xb0\x68\x52\x33\x70\xe1\x6a\x9\xbe\xad\xf0\xb8\x37\x5c\x41\x95\x59\x72\xa5\x67\xf6\xa2\x13\x82\xfb\x19\x34\x66\x3f\x5b\xac\x5f\x9d\xeb\xd8\xb7\x21\x1c\x3c\x75\x4c\xd1\x7e\x74\x40\xb6\x22\x98\x69\xee\xea\xa4\x7a\xe4\x6e\x58\xc0\x12\x1b\xe\x14\xae\xde\x9a\x7b\xd7\x28\xed\x1f\x61\x55\xf\xb\x57\x17\x9b\xef\xe7\x97\xfa\xaf\x24\x4b\xd2\xa3\xd9\x85\x64\x8\x2f\x96\x50\x35\xa7\xe3\x25\xc1\x46\x8d\xcc\x73\xe0\x56\x15\x90\xa8\xbd\x5\x4\x20\xc4\xf3\x39\x16\x6\x38\x65\xf2\xdb\x86\x6f\x27\x1\xf4\x6b\xb1\xbc\xdc\xba\xc6\x26\x3d\xdf\xa1\x29\x51\x2\xa0\xc8\xda\xa9\xec\x94\xc3\xc\x88\xd6\xb2\xd5\xfe\xfc" }, + { 0x53c7b0, "\x5f\xb6\xef\xa1\xfb\xd0\xa3\xb\xc9\x67\x54\xdd\x92\x4\xa5\xe0\x99\xa7\x62\x53\x87\x3c\xf6\xcc\x12\x45\xd5\xa6\x7b\xb4\x8e\x6f\x3e\x6e\xe3\x41\x44\x61\x8b\x5e\x2a\xb9\x2b\xdc\x46\x7c\x4b\xf0\x50\x4d\x9b\xad\xc3\xa8\x7d\x81\x8f\x2e\x1d\x79\xf3\xfe\x29\x8a\x3f\x22\x35\x4c\xa2\xf1\x90\x58\x9a\x70\xac\x88\xc4\xbb\x43\xb5\xbd\xaf\x24\x2c\x1c\xb0\xe9\xbc\x3\x3d\x18\xc5\x7\xd8\x9f\x97\xdf\xd9\xc6\x68\x5c\x15\x2\xda\xa9\xc2\xaa\x6\x55\xc7\x76\xf4\x2d\x7a\x32\x85\x86\xee\x19\x95\x4a\xec\x94\x80\x89\xbe\x9c\xcd\x56\x38\x10\xd3\x8\xdb\xb1\x6d\x6a\x2f\xf5\x33\x52\xcf\xab\xe6\x1f\xa4\x73\xf9\xf\xc8\xc0\xe8\x93\x13\xd\x84\xf7\x9d\xba\x64\x83\xb3\xae\x71\x37\x1e\x8c\x25\x0\xf2\x21\x9\xea\xd1\x1a\x7f\x42\xe1\x16\x48\x6c\xc1\x1b\xf8\xd6\x20\x27\x74\xb8\x49\x60\xcb\x6b\xa\x3b\x72\x75\x9e\x47\xeb\x4f\x91\x31\xe4\x63\xd2\xe7\xfc\xde\xb2\x28\x4e\xce\x57\xc\xb7\x98\xed\x36\x7e\x5a\x34\x40\x51\x23\x30\x59\x77\xfa\x5d\x1\x96\x39\x8d\xff\x17\x11\x66\x5\xfd\xd7\x14\xe5\xa0\xbf\x69\xe2\x82\x26\x65\x5b\xd4\x3a\x78\xca\xe" }, + { 0x53c8b8, "\x69\x23\xad\xbe\xc\x4e\x2f\x48\x7e\xe3\x30\xaa\x9d\x42\xc3\xc1\x6e\x13\x64\xff\x3d\xd9\xdf\xb3\x4b\x98\xfc\xeb\x92\x83\x95\x50\xaf\xc9\x7b\xf\xc7\x8d\x53\xa8\xbb\xb5\xd8\x2e\x9f\x3\x81\xe8\x2d\xed\x74\x6c\x97\xe9\xb\xbd\x1d\x15\x4\xa0\x5a\x16\xbf\x3f\x7c\x35\x6\xcf\x7a\xae\x44\x8b\xf4\xf7\x5e\x1e\xef\x27\x8f\x29\x55\xf2\x4f\xd\xea\xc4\x5\x88\x18\x94\x34\x8\xb4\x62\xd7\x26\x56\xfb\xf8\x37\x33\xce\x1c\xd0\x47\xd5\xe0\x71\x41\xd6\x87\xee\x72\xf1\x70\xe5\x75\x7f\x21\x54\xca\x80\xb2\x11\x7d\xbc\xdc\x7\xe\x91\x38\x96\xa1\xb6\x3a\xfd\x2\x6f\xa6\x3e\x10\x60\x9c\x63\x77\x59\xec\xa\x86\xf5\x28\xfa\xe7\xe1\xb7\x76\x36\x1a\x1f\xa5\x9a\x45\x39\xdb\x5d\xd2\x5f\x2b\xf9\xfe\xde\x31\xab\x52\xd1\xa4\x3b\x4a\xb0\x0\xb9\x9b\x9e\x43\xc0\x12\x89\xa9\xa3\x20\x65\x14\x1\x46\x2c\xcc\x17\x8a\x68\xe2\x19\x4c\xd3\x32\x5b\xdd\x66\x73\xcb\x85\x1b\xc6\x67\x6a\xd4\xc2\x8e\x61\xda\xf3\x57\x79\xa7\xb8\x8c\x9\x40\x5c\x6d\xb1\xa2\x22\xc8\xf0\x25\x49\x58\x24\x6b\xe4\xcd\xba\x93\x2a\x99\xc5\x4d\xe6\xf6\x84\x3c\xac\x90\x82\x51\x78" }, + { 0x53c9e8, "\x1\x69\x88\x4f\xf0\x48\xe7\xbd\xc3\xba\x8\x63\x75\x6d\x3a\x4b\xd7\x86\x59\x47\xb\xde\xa\xf1\xbe\x58\xe1\x5d\x91\xab\x9\xee\xad\x5e\x28\xca\x6\xa9\x4\xe9\x8e\xc5\x6f\xd0\xfe\xdf\x12\xc1\x7e\x4c\x2b\xcb\xb1\x96\x7a\x90\xf8\xc2\xa4\xe6\x73\xa2\xdd\x1c\xaa\xe4\x30\x3f\xcc\xc4\x35\x66\xb3\x1d\xdb\xa0\x7\x36\xa3\x54\xb9\x43\x94\xc\x8b\x98\x72\x44\xbc\xf5\xcd\x2d\x2\x5b\xed\x1f\x29\xf7\x0\x7f\x53\xda\x85\x2f\xc0\x89\x33\xa5\x9f\x9a\x8d\x64\x68\xd2\x9e\xaf\x40\xeb\xec\xfa\x26\x41\x9d\xd4\xa1\x10\x8c\x37\xbf\x4a\x81\xac\x45\xd6\xa7\xe3\x9c\x8f\x21\xf2\xff\x42\xea\x87\x32\x1a\x2e\xcf\xbb\x3e\x15\x22\x65\x7b\x61\x3d\x83\xa6\x78\x6a\xd8\xf\x2c\x31\x62\x97\x5c\x14\x27\x49\x46\xf4\xd1\xf3\x93\xb6\x60\x95\x3b\x99\xc6\x70\xfb\x67\x24\x6c\x9b\x25\xc9\xe5\xb4\x4d\xd5\x76\x71\x2a\x1b\xdc\xfc\x8a\xae\xe2\xef\xe0\x17\x13\x5f\x57\xb5\x79\x50\x6b\x56\x7c\x52\x11\x3\xd\x23\x7d\xa8\xd9\xe\x6e\x3c\x16\x38\x92\xce\x51\x34\xc7\x55\x18\xb7\xe8\x74\x82\xb2\xd3\x19\x20\x77\x5\xb8\xc8\xfd\xf9\x80\xf6\x1e\x4e\x84\x5a\x39\xb0" }, + { 0x53cae8, "\xa4\x6d\xc3\xfc\x24\xa5\xb7\x3f\x26\xc0\x2d\xe3\x49\x71\xe0\x36\xaa\x39\x6a\xb4\x21\x67\x9a\xfa\x23\xe5\xec\x12\x25\xd\x72\x87\x27\x7a\x5d\x60\x6f\x57\x78\x94\x44\x56\xde\xc9\x95\x97\x2f\x77\x9d\x53\x89\xfe\xff\x8b\x46\x2c\xcb\x61\x8\xdf\x79\xb6\x20\xc\x15\x3d\x4a\x2e\xb2\x7\x73\x3e\xcf\x6\x88\xf4\x37\x32\x19\x3a\xf6\xe9\x75\xac\xeb\x30\xf9\xbb\xa7\x84\x63\x5f\xa8\x1a\x91\xc8\x9c\x7f\xd6\xd5\xed\x3c\x98\xd8\xbc\xb1\xf\xfd\x9\x3\x99\x6b\x16\x8e\x59\x4e\x1f\x66\x82\x2\x8d\x96\x4b\x22\xc5\xa3\x50\x74\xdd\x2b\x5e\xa1\xda\xcd\x5b\x58\x9e\x28\x1d\xe8\x62\x47\xf1\x33\x35\xaf\x34\xef\x5a\xa2\xbd\xe\x81\x4\x5\xee\x7c\x51\x4f\xbe\xc4\x42\xb\xca\xd3\x70\x9f\xba\xd4\x8c\x10\xfb\x90\x14\x13\x1b\x3b\x11\xc1\xad\xb9\x64\x48\xd0\x31\x4d\x8a\xd2\x86\x38\x0\x92\xdb\xf5\x5c\x9b\xea\x17\xf8\x68\x83\x18\x4c\x52\x1e\x2a\xe6\xa\x69\xab\x6c\x6e\xf7\xd9\xc7\x41\xf3\xc2\xa6\x1c\x7d\xb3\xd7\xdc\xd1\x93\xe2\xce\x85\xbf\xb8\xe1\x76\x40\x54\xcc\x7b\x8f\xa9\x7e\xe4\xae\x55\x1\x80\xf0\x43\xc6\xb5\xf2\x65\x29\xb0\xa0\x45\xe7" }, + { 0x53cd28, "\xed\x8e\xda\x43\x63\x70\xc8\x69\xee\x7\x3b\xd6\xe9\x1c\x17\xc\x38\x97\xa3\xe1\xe\x6\x40\x96\x0\x7c\xbb\x39\x9\x2b\xd7\x78\x19\x59\x4\x44\xb9\xa7\x13\x68\x16\xcd\x8d\xa8\xc2\x54\xb5\x30\xac\x72\x5b\x12\x1b\x6b\x89\x6f\x99\xc6\xd3\x51\x76\x87\x91\x60\x27\xa0\x4d\x4f\x47\xf3\xd\xcc\x98\xaf\xf8\x6e\x9d\x9f\x7b\xfc\x36\x5e\x9c\xb8\xf5\x8b\xdf\x7f\xfa\xe4\x75\xcb\x9b\xf0\x77\x3\x41\x62\xb3\x11\x32\xa5\x2d\xa2\x6c\x3d\x86\xdb\x80\xba\x2a\x83\x90\xf2\x22\x24\xc5\xff\x5f\xb0\x15\x31\xbd\x1e\xcf\x57\x4e\xc7\xae\xf4\xe3\xb4\x4b\xce\x35\x3c\xb2\xa\x95\xfe\xa1\x5\xf9\xd1\x8a\xf6\xdd\x74\xa6\x2\x1\xe2\x52\xa4\x10\xb7\x93\xf7\xc4\x18\x28\xd4\x84\xa9\x9a\xc0\xe8\x8f\x53\x2f\x7a\x5c\x58\x26\x79\x42\x4a\x25\xad\x33\x67\xbe\x7d\x34\x1a\x46\x29\xde\x20\xd5\x3f\x1d\xd8\x3e\xe0\xb\xc1\x71\x14\x1f\x73\x6a\xfb\x61\x55\xab\x50\x85\xbc\xb6\x7e\x9e\xd9\xeb\x5d\xd0\xd2\x21\x64\xf1\xbf\xdc\x56\x45\x94\x65\x4c\xe5\x3a\xb1\x6d\xe6\x49\x8\x23\x88\xaa\xfd\xc9\x5a\x81\x37\x2e\xf\xef\x2c\xca\x92\xe7\x48\x82\x8c\xc3\xec\x66\xea" }, + { 0x547230, "\x31\x69\xdc\xcc\x61\xe2\xd4\xad\x9a\x51\xe5\xfa\x53\x6d\xfe\x6\x89\x79\x46\x99\x24\x7c\xa0\x18\x56\x27\x7f\x2e\x2a\x77\x0\xd8\xcd\xb6\x1e\x4b\x4e\xfc\x4\x23\xa4\x75\x8\x44\x19\x80\x7\xf3\x16\x5c\x9\x93\xb9\xdb\x92\x10\x30\xd0\x43\xd7\x85\xfb\xdd\xe\x49\x39\xca\x2\x64\x8a\x35\xa6\xee\x13\xe0\x91\x9b\xce\xc2\x12\x82\xab\x4d\x74\x22\xd\x70\xb2\x90\x98\x3\xec\xc7\xcb\x9c\x71\xba\xac\x50\x21\xf8\xc0\xda\x67\xa\x72\xfd\x2d\xc\xf6\xa7\x52\x65\xaf\xc3\xa3\xa1\xea\x5a\xd5\x17\xbe\x7e\xcf\x94\xb0\x34\xd1\x1b\x6e\xf0\x54\xf2\xe8\x76\xbc\xe4\x3f\xf4\x73\xe9\xae\x7b\x6c\x3a\xbb\x8f\xe7\x4a\xb1\xb\x7a\x68\x86\x11\x2f\xf1\x8d\x81\x47\x42\x2c\x7d\x8c\x95\x55\xf7\xc5\x84\x1d\x59\x41\xd6\xbf\x8b\x33\x9f\xe6\x38\x45\x87\x1\xc4\x1a\x78\x40\x3c\xbd\xe1\xb7\x1f\x26\x6a\x6b\xa8\x96\xf5\xa9\x60\x37\xed\xa2\x15\x58\x3d\x8e\x48\x3b\x9d\xb4\x5b\x29\x62\x4c\xc6\x83\x66\xb3\xb8\xde\x1c\x2b\x5e\x63\x57\xd2\x5f\x25\x36\x20\x28\xb5\xc1\x5d\xc9\xf9\x9e\xf\x88\xa5\x5\xef\xdf\x97\x4f\x14\xc8\xd3\xff\xd9\xeb\xe3\x32\xaa\x3e\x6f" }, + { 0x53ceb0, "\xbc\xb2\x5e\x24\x9d\xc6\x26\xc5\x91\x6c\x87\xb3\x70\x47\x6f\x5f\x1\xad\x7f\xa5\xea\x4\x7c\x31\x39\xdb\x15\x9e\xdd\x64\xb8\xf4\x9a\xd0\xe0\xf\xf0\xcd\xef\xd4\x23\xc0\x14\xcf\x79\x5b\xba\x48\x2f\x18\xc\x95\x55\x43\xab\x67\x99\xa3\xbd\xd9\x90\xec\xbf\x21\xff\xd2\xb6\x96\xf1\x5d\x6a\xe3\xd5\x4f\x7d\x8f\x46\xb1\x7e\x12\xb4\x6e\x97\x37\xa\x36\x94\xc8\x1f\x51\x8d\x60\x78\xaf\xfa\x9c\x2a\x40\x7b\x1d\xbb\xe9\x75\xe8\x5a\x3a\x11\xf5\x7\xed\x5\xc7\x9b\xf7\xb5\xb0\x1c\xd1\x4a\x83\xc4\x81\x7a\x92\xf2\x3b\x4e\xb9\x2\xde\xaa\xe\x1a\xcb\x5c\x44\xe1\xd6\x98\xa2\x4c\xee\xd7\x45\x9\x32\x20\x3e\x3d\xa7\x57\x58\x0\x73\xa6\x10\xfb\x6\x4b\xce\x74\x35\xfc\xae\x77\x89\xfe\x19\x53\xfd\x82\xc2\x85\x30\x50\x84\x8\xc3\x28\xf9\x22\x80\x65\x62\x13\xe4\xca\x34\x3f\xdc\x4d\xf3\x8a\x86\x8b\x69\xf8\xda\xa4\xc9\x61\xe7\x38\x6b\x54\x2b\x49\x29\xa0\xc1\x71\xd8\x2e\xa1\x1b\xd\xcc\x8e\x8c\xa8\x2d\x27\x42\x56\x16\x41\xf6\x72\xa9\xb\xe2\x68\x25\x63\x93\x1e\xb7\x9f\x59\xd3\xac\xe5\xdf\x2c\xe6\x88\x76\xeb\x3c\x52\x33\x17\x66\xbe\x3\x6d" }, + { 0x53d168, "\x3\x21\xa0\xee\x97\xa8\x35\x87\x9f\x6e\x88\xf0\xc1\x1a\x19\xbd\xd2\x17\x78\xb9\xd6\x29\xf4\x28\x40\xe6\x8d\x1c\x2f\xf6\x56\x14\xdd\xa5\x57\x48\x9a\xce\xb4\xff\x5a\x5\x3a\x9d\x7e\x6d\x96\x6c\x55\x3b\x38\x4b\x51\x1f\x60\x8\x1d\x70\x22\xae\xd3\x8f\x99\xc3\x83\xe0\xde\xea\x6\xf9\x9b\x5c\x52\x2a\x72\xb7\xc9\xdb\xfa\xd7\xdf\x68\xbc\xb6\x59\x98\x74\xb2\x27\x9\xf\x44\x6f\x91\x7d\xcc\x12\x4e\x2d\x42\x7a\xf7\x9c\x7c\xe4\xf8\x94\xad\x23\xef\x8a\xaf\xb8\xe2\x80\xb5\x86\x54\x47\x4a\x2\x3c\x5f\xf3\xec\x4d\xe7\x8b\xbf\xb0\x26\xc5\x67\x24\x3e\xca\xbb\xd8\x1b\x63\xc6\x82\x75\x69\x5e\xdc\x45\xac\x71\x30\x76\xa\x81\xda\x33\x32\xd5\xbe\xd\xfc\xf2\x3d\xa4\xf1\x73\xed\x43\xd4\xe5\x2e\xe9\xd0\xcb\x41\x37\x5d\x34\xd9\x77\x7b\x7f\xa3\x39\x6a\x61\x16\xcf\x1\x7\xfd\x58\x13\xa2\x20\xc7\xc2\x66\x2c\x50\xd1\x65\x79\xc8\xb1\x64\xb3\x90\x0\x5b\x11\x31\xe\x25\x6b\x89\xe1\x8c\x53\x10\xaa\xc\x4\x4f\xa1\xa7\xc4\x85\x92\x36\x46\x1e\x3f\xfb\x84\xe8\xc0\x8e\xa6\xa9\xcd\xf5\xba\xab\x62\x15\x18\x9e\xb\x4c\x2b\x49\xeb\x93\x95\xe3\xfe" }, + { 0x53d2d0, "\x43\x2f\x53\xa0\xc2\xfd\xcc\x6\x29\x3e\x1f\x44\xab\x65\x74\x54\x49\x27\xb7\xe2\x2c\x5a\x33\x34\x1e\x16\xa7\xae\xa\x92\x55\x20\xad\x98\xf8\xa9\xe\x8b\x32\xdf\xa5\x15\xfc\x9f\x23\x3c\xc4\xc0\x4c\xbe\x89\x9a\xf0\xe4\x73\x59\x30\x9e\x82\x58\x51\x8f\xbf\xa1\xc7\xeb\xf1\x64\x1b\x4b\xc8\xc3\x38\x31\xd2\xfe\x3d\xd0\x77\xcb\xd6\x24\xf7\xc\xe5\xff\xd8\x4d\xac\x10\xe6\x76\xbb\xf\x9c\x6c\x2e\xb\x75\x78\x5d\xa3\xaf\x17\x5e\xb0\xe1\xb1\x9b\xf9\x7\x39\x6d\x7b\x1c\x2a\x9\x3f\x12\x4\xc9\xc1\xc5\x19\x61\x5\xb4\x47\x37\x5f\xd5\x94\x28\x21\x88\x97\xfa\xd3\xcf\x7f\xdd\xd4\xf3\x68\xf4\x81\x62\x84\x91\x83\x8c\x7e\x67\x63\x66\xed\xe7\xe9\x85\x6f\xdb\xaa\x87\xec\xde\x90\xba\x25\xa2\xd\x6b\x5b\x7a\x96\x70\xe0\x86\xa8\xe8\x6a\x4e\x42\x57\x2b\xb6\x40\xce\x69\x46\xb5\x72\x80\xcd\x13\xf6\xf2\x0\xda\x93\x22\x60\x3b\x7c\xb2\x48\xef\x3\xb9\x71\x4f\xc6\x45\x36\x26\xfb\xf5\xca\x2\x6e\xd9\x8d\x95\x14\x2d\x8a\xd7\xdc\x52\xee\x99\xa4\xbc\xb8\x8e\x1a\x3a\x1d\x4a\x7d\x1\xe3\x56\xa6\x50\x35\x18\x8\x79\x5c\xbd\x41\xb3\xea\x9d\x11\xd1" }, + { 0x53d3d0, "\xf1\xbb\x4b\x7e\xc1\x8a\x41\x12\x97\x5e\x57\x56\x9f\x2c\x5f\xb6\x47\xff\xb1\x4c\x8b\x9c\x63\xc4\xa7\x98\xb2\x31\x84\xb4\xd\x1d\xe0\x67\xfd\x2\x13\x10\xdb\x8\x83\x48\xc6\x86\xaa\xe5\x80\x9\x38\xfc\xe2\x85\xc7\x8d\xa9\x3b\x18\xa5\xb7\x32\x9b\x6a\x2e\x87\xc0\x24\xa0\xfa\x6b\x76\xa2\xe6\x7f\x5d\x7b\x40\x33\xfb\x62\xf6\x43\xd1\x6d\xa1\x29\xd5\x17\x50\xf9\x1c\xeb\xf2\x22\xc2\x51\xe4\x26\xca\x5b\xf\xf8\x96\x4e\xba\xf3\x55\xa4\x37\x36\x82\x70\x99\x20\xc9\xf5\x7c\xa8\x92\x6\x72\xe7\xb5\x9d\x44\xd2\xbf\x64\x16\x49\x3\x4a\xe3\x68\xd0\x1a\x34\x95\x7d\xcb\xbc\xd3\x78\xd7\x5a\xb0\xb9\x2f\x27\x77\xf7\x45\x25\x52\x1b\x3c\x3d\x9e\x2b\x74\x89\xa\x1f\xfe\xf0\x2a\xe1\x1\x3a\x9a\x39\x8e\x79\x71\xd8\xcc\x46\xe8\x69\x3e\xaf\x7a\x21\xad\xea\x75\x93\x15\x30\xf4\xe9\xdd\xe\x60\x28\x6e\x88\xae\x81\x4\x59\xc5\x90\xee\x61\xcf\x8f\xb8\xb3\x54\xed\x58\x6c\x91\x3f\x65\x6f\xd6\xbe\x4d\xef\xde\xa6\x8c\xc\xc3\x23\x35\x5c\xac\xd4\xda\x5\xc8\x14\x94\xd9\x19\xcd\x4f\x2d\x0\xdf\xbd\x7\x42\xab\xdc\x73\xa3\xb\x66\x53\x1e\xce\x11\xec" }, + { 0x53d798, "\xcc\xbb\x69\x91\x5\x73\xbe\x41\xf4\x59\x24\xa5\xf6\x28\xc7\x7a\xc1\xd5\xd\x62\x40\xb1\x32\x16\x6d\x77\xdb\xee\x65\x95\xd7\x35\x2f\x64\x30\x7\xfa\x5a\xe3\x88\x93\x6a\xeb\x31\xde\xd4\xcb\x4f\x92\xc8\x11\xfb\xd0\x4e\x3a\xdc\x7e\x15\xf1\xb4\x61\x58\xad\x9e\xfe\xb9\x6\x4a\x0\x6f\x3\x7f\x8a\x20\x3d\x22\x78\xe1\xe9\xe6\x14\xbc\x75\xe4\xf8\x19\x5b\xc4\xb3\x7d\x76\x2d\x3c\x9d\x9b\xac\x8e\xb2\x3b\xb5\xa7\x47\x9f\xc3\x36\xdf\xf9\x90\x80\x43\xf5\xa4\xe\x4d\x33\xe0\xc\xdd\xb8\x2\x7c\x8b\xf0\x45\x46\xa9\x8c\xcf\x9a\xca\xce\x84\x83\x71\x48\x39\xba\xfc\x2a\xe2\x57\xc5\x98\x97\x60\xc6\xae\xc0\xd8\x37\x81\xaa\xb6\x2b\xea\x26\x21\x4b\x55\xe5\xd2\x85\xab\xb7\x34\xbf\xd9\x70\xcd\x53\x96\xc2\xef\x63\x13\x1e\xed\x12\xc9\x74\x42\x5e\x3e\x54\x9\xd3\x89\x6e\x72\x49\x2e\xd6\x1a\x9c\xa\xa8\x6c\xbd\x10\x86\x4\x38\x50\xf2\xb\x1f\x87\x2c\x29\x17\xfd\x52\x66\x67\xf\x8d\x1\xb0\x18\xda\xe8\x1d\x94\xa3\x25\x79\x3f\x8f\x51\xa2\x23\xf3\xaf\x68\x5d\xa1\xf7\x99\x1b\xff\xec\x56\x44\x8\xa6\x6b\xe7\x5c\xd1\x1c\xa0\x5f\x7b\x4c\x82\x27" }, + { 0x53d970, "\xb9\xd7\x6b\x9c\x5b\xfb\xc0\x9b\xf\x49\x55\xa9\x6d\xa5\x17\xd0\xc3\xdc\x4b\xb8\xf2\xb0\x93\xee\x3c\xeb\xdf\x8d\xe1\xf6\x2f\xe2\xc4\x32\x4c\x35\x62\xb4\x92\x91\x1c\x6f\xb6\x30\xe3\x5a\xb2\x2\x5e\x64\x21\xd5\x0\xcd\xd2\xb7\xd\x81\xef\x14\xb1\x87\xf0\x8f\x20\x39\xfc\x16\x63\x38\x1a\x7a\x56\xe4\xf3\x6e\xf4\xcb\x27\x57\x34\x2b\x12\x86\x79\x3f\x7\x6\x5d\xe\xbd\x7b\x54\x8e\xf1\xc8\x51\xf5\xbf\xd8\x5\x26\x47\x67\xda\x53\x95\x98\xea\xed\x5f\x74\x41\x3a\xc\x8c\xa6\x94\x59\xb3\x8b\x46\x6c\x7c\xbe\x9e\x7d\x83\x36\x88\x31\x7e\x18\xdb\x5c\x19\xe6\xe0\x58\x9d\x72\x13\x77\xdd\xc2\xac\x75\x96\x8\x73\xd4\xa\x2c\x22\xe5\x2d\xf8\x71\xaf\x45\x2e\xc6\x76\x3d\x65\xf9\x29\x4f\x80\xd1\xd3\xe9\x69\x9a\xab\x90\x1b\x1\x1e\xc7\x15\x24\xec\xcc\xe8\xad\x3b\x10\x4d\xcf\x85\xa1\xa7\x89\x25\x11\xd9\xc1\x1d\xae\x9\xde\x6a\x44\x4a\x3e\xbb\x48\xca\xe7\x70\x4\x9f\xa8\x68\x43\xb\x8a\x52\x42\x50\xba\xfa\xce\xd6\x33\x61\x60\xa0\xa3\xf7\x3\x1f\x84\xfd\xbc\x40\x7f\x66\xaa\xc5\xb5\xa4\x37\xfe\x97\x28\xff\x78\x23\x82\xc9\x2a\x4e\x99\xa2" }, + { 0x53da70, "\x46\x47\x9d\xa8\xcf\xa7\x62\xc7\x30\x42\x69\x3a\x34\x5a\xbe\xd5\x59\x63\x33\x21\x2c\xa0\x6\x1e\x31\xa6\x92\x3f\xc8\x57\x5e\xbf\xa9\x90\x19\xb0\x29\x7\x12\x1f\x23\x97\xe3\xa4\xdd\xb8\x3c\xb2\x5c\xce\xda\xd0\x52\x8\x64\xc3\xc0\x9a\xca\xea\x43\x6b\x41\x1c\x8c\x7a\x7b\xd1\x94\x5\xc\x93\x15\x51\xd9\xd4\x3e\x4c\x2f\x49\x4\xd2\xee\x73\x0\xa2\x8d\x6d\x55\x2\x3\xfe\xb\xc2\x1a\xe2\xf1\x83\x80\x36\x78\xf5\x96\x40\x75\xe\x9c\x7d\xad\x32\x5f\x2b\xc9\xbb\xf4\x7c\x66\xb7\x54\x8a\x89\xff\x50\xdc\x60\x25\xb3\x6a\xfb\xe4\x4d\xab\xb9\x74\xc5\xbc\xb6\xe8\xc6\xfd\x7f\x4a\x76\x3b\x9f\x45\x18\x4f\x9e\x95\x13\xb5\x10\xf8\x22\x5d\x1d\xdb\xbd\xb4\x6f\x84\xba\x17\xd\x6c\xaa\x44\xae\xf6\xde\x81\x11\x79\x85\x86\x39\x99\x82\x38\x6e\xa3\x26\x68\xeb\xc1\x27\xed\xcb\x2e\xdf\xf7\xef\xfa\xb1\x9\xd7\xd8\x8b\xac\x37\x4e\xe7\xf0\xe1\xd6\xa\xd3\xec\x61\x72\x5b\x28\xa1\x87\x70\xf3\x71\x98\x8e\x20\x53\x16\x3d\xa5\xf2\xf9\x4b\x9b\x91\x88\x2a\x65\xf\xfc\x67\xe6\x58\x2d\x14\x56\x48\x1\x7e\x35\xaf\xc4\xe9\x8f\xe0\x1b\xcc\x24\xe5\xcd\x77" }, + { 0x53dbd0, "\x77\x1f\x49\xca\xc3\x17\x39\x14\x66\xde\xc5\xd9\x2f\xf\x6e\xd3\x7d\x21\x60\xec\x9a\x4b\x25\xc2\x71\xfc\xb\x81\x8e\xbf\x36\x99\xf7\x6b\x7e\x86\x10\xdc\xa7\xb0\x8b\xb9\x72\x20\xf4\x5e\x31\x74\x6c\x4f\x80\x4\xb1\xc9\xb7\xd0\xab\x7b\xd\xf6\x1d\xbc\x38\x78\xaa\x43\x3f\xf0\x82\xcf\xcb\x96\xf5\xeb\xce\xb5\x12\x29\xc0\x62\x63\x9\xf1\x2\xc1\x44\x32\x2c\xe8\x4e\xe6\x57\x7a\x83\x95\xb8\xfb\x37\xd7\x2a\x3\x5d\xef\xc7\x11\xd6\xa2\xb2\x5c\x85\xa3\x5a\x19\xfe\x8a\xad\xd2\xbd\x28\x9b\x34\x6f\x3c\x67\xe1\xc\x24\x68\x97\xb4\xda\xe3\x98\x7c\x2b\xd5\xee\xe4\xcc\x47\xcd\xb3\xe7\xfd\x61\x42\x3d\x4d\x9c\x5\x9e\x4a\xdd\xa9\xdf\x6d\x45\x6a\xd8\xfa\x16\xae\x58\x1b\x76\xf9\xa0\xe5\xb6\x1a\x59\xa5\xba\x9f\x65\xbb\xa4\xe\xd1\xd4\x51\x41\x40\xc8\xe2\xdb\xaf\x94\x64\x7f\x22\x3b\xf2\x2d\xc4\x70\x2e\x5b\x69\xc6\x56\x33\x7\xa\x15\xea\x91\x53\x1\xf8\x84\xe0\x30\x90\x75\x87\x5f\x54\x6\x46\xe9\x35\x92\x50\x79\x88\x1e\x8d\x3e\x8f\x73\x0\x18\x89\x93\x9d\x8c\x27\x1c\xa6\xbe\x23\xf3\xed\x55\x52\xa8\x26\xff\x8\x13\xac\x4c\x48\x3a\xa1" }, + { 0x53dd70, "\x97\xd5\x40\x91\xed\xf1\xce\xf3\xc2\x6e\x94\x19\x5f\x5b\x7d\x9b\xc\x29\x5d\xda\x71\x7c\xab\x9d\xb4\x9e\x2d\x48\x2\xa8\x0\xbe\x7b\x86\xf\x38\x56\xee\xd3\x34\xa6\xbf\x7f\x1b\x8d\x53\xe8\xdb\x61\xa4\xe2\xe1\x2e\x78\x3d\xb6\x80\xd8\xe\xfa\x6d\xd1\xe7\x6\x4e\x14\x77\x54\xae\x5\xd4\xbc\x6a\x74\x3b\x1c\x8a\xc0\xb7\x45\x92\x26\x11\xd0\x99\x57\xaf\xb3\x95\x84\xfd\xc4\xa3\x22\xa7\x39\xbd\x41\x1e\x4f\x3e\x1a\x2b\x15\xba\x64\x1\x23\xa9\x37\x58\xd\x67\x76\x2c\x8e\xca\xc8\xdc\x65\x98\x90\xea\xad\x6f\xcc\xe5\x32\xbb\x28\x70\xf5\xa5\x12\xb9\xc6\x75\xf0\x3c\x4c\x6c\x85\x73\x88\xe6\x7\x72\x69\x82\x8b\x2f\xb2\xde\x10\x6b\xdd\xff\xb1\x43\xd6\x50\xcf\xd7\xb8\x4\x68\xe0\x93\x18\x79\xa\x9\xc5\xaa\x83\x7e\x16\xf4\xc3\xcb\x96\x87\xc7\xb\x49\x3a\x62\x3f\xb5\x31\x24\xa0\x8f\xf7\x13\x30\xe9\x51\x59\xa2\x4d\x47\x4a\xe3\x8c\x55\x81\xa1\x5c\x1d\xfc\x2a\xfe\xeb\xcd\xdf\x60\x25\x89\xef\x33\x7a\x20\x66\x27\xc1\xb0\x3\xf2\x9f\xf8\x1f\x9a\x5a\x9c\x5e\xf6\x35\x21\x52\xd9\x44\xe4\x4b\xc9\xec\xd2\x63\xf9\x36\x8\xac\x42\xfb\x17\x46" }, + { 0x53e0d0, "\xed\xb6\x90\x15\xcd\x25\x37\x67\xfc\xf3\xd9\x12\xb8\x36\x3\x5d\xe5\x44\x43\x20\x93\x47\xfb\x9b\xca\x3b\xd0\x9c\xbf\x34\x42\x3a\x68\x73\x76\x3c\xc1\x8e\xb1\x51\x31\x98\x19\x1b\xb\xfe\xeb\x3d\xe6\x82\xea\x2\x9f\x9e\xf2\x46\x87\xfd\xb2\x83\x1f\x9\x8b\x4f\x5e\xa8\x16\xd7\xad\x71\xd2\x64\x24\x66\xe4\x48\xa\x79\x4\x84\x49\x52\xda\x8\x58\x8d\xec\x0\x7b\xe1\x2b\xd3\xc7\x96\x38\x32\x74\x2f\x60\x7a\x7d\xac\x85\x99\xa5\xbb\xc0\xf4\x10\xd4\x61\x6f\xba\x26\xc5\x3f\x8c\xb0\xf7\xee\xe8\xb3\x11\xa6\x2d\x54\x30\x1d\x2e\xe0\x1e\x6b\xc\xce\xcb\x6c\x65\x39\x4e\x5f\xdd\xef\x41\xc9\xf8\xe7\xf6\x92\xd8\x4a\xdc\x53\x40\xbd\xa4\xb5\x22\x9a\xe\x5b\xb7\xde\x5c\x8f\x29\xaf\x8a\x56\xb9\x95\x94\x5\x27\x35\x5a\x78\x18\xae\xd5\xb4\x3e\xa9\x6e\xaa\xc4\x6\x80\xc8\xf5\x6d\x55\x33\x72\xa0\x1c\x89\xa1\xa7\x2a\x97\x4b\xcf\x4d\x6a\xf9\x9d\x28\xf\x14\xa2\xff\x7e\xd6\x81\x91\x7f\x23\xd\x57\x62\x4c\x17\xc2\xc6\xf0\x77\xf1\xa3\x21\x88\x7\xab\x69\x63\xe2\xd1\x50\xcc\xe9\xdb\xc3\x86\xbc\x59\xe3\xbe\xfa\x75\x1\x45\x13\x70\xdf\x1a\x7c\x2c" }, + { 0x540278, "\x6c\x9f\x49\x77\xa9\x27\x95\x66\xde\xf\x58\x2f\x4c\x1c\x4b\x73\x22\xcc\xfb\x1a\x85\xf6\x9c\x8b\xc5\xdd\xb0\x15\x46\x37\x79\x2\xab\x3d\x44\x8a\x10\x87\x9e\xfc\xba\xb9\x2b\xa\xf4\xd9\xbf\x78\xf1\xef\x11\xdc\x80\xd2\xd5\xf7\x5c\xbe\xe2\xd4\x9d\xd3\x13\x1\xe1\x18\x50\x53\x43\xd7\x64\xf8\xdb\xf2\x62\xcd\x99\xe7\xa2\x0\xaf\xbc\xff\x25\x91\x5f\x83\x60\xec\x42\xb6\x47\x8e\x6a\xd\x4f\x16\xe6\x51\x14\x8f\x5\xea\x70\x3a\xca\xc7\x74\xce\x5d\x98\x31\x3b\xe9\xe0\xc3\xa4\x1b\x92\xd0\xc\x40\x4d\xb5\x7f\x8\xf9\x39\xb1\x29\xc4\xd1\x21\xac\xc0\x54\x4\x55\xcb\x17\x69\xfe\xe5\x3e\x88\x1d\xe\x7c\x76\xb2\xc6\x24\x81\x9\xe4\x59\x34\x7a\x86\xf5\xad\x5e\x38\xbb\x4a\xe3\xc8\x26\x30\xbd\xfd\x33\x72\xb4\x20\x2a\x19\x6b\x97\x32\x96\x7b\xa1\xa6\xdf\x61\x71\x7\x23\xee\xc2\x75\xb7\xaa\x7e\x67\xa0\xa3\x94\xd8\xa5\x1e\x68\xda\xa7\x48\x8c\xf0\xb3\x4e\xfa\x9b\xb\x6f\x2d\x6d\x8d\xcf\x5b\xc9\xae\x9a\x3f\x6\x1f\x90\x65\x6e\xf3\x93\xa8\x45\x12\x2c\x52\x36\xeb\x82\x3c\x7d\x57\x28\x56\xed\xd6\x63\x2e\x3\x41\xc1\xb8\x5a\x89\x35\xe8\x84" }, + { 0x5406e8, "\xbb\x3b\x8c\x61\x95\x4d\x8e\x4c\xe1\xae\xff\xc4\x47\x64\xc9\xb7\xd3\xca\xb\xed\xef\xc0\xc7\x43\x1c\x66\xb9\xd9\xea\x2f\xa0\xfb\xcc\xfa\x50\xd\x55\x46\x96\x24\x21\x70\xe0\x6\x33\xf3\x0\xd5\x67\x1a\x13\xde\xa5\x7c\x74\xfe\x1f\xaa\x73\xc3\x15\x93\x9f\xd7\x2b\x14\xcb\x7b\xb8\xe4\x91\xf0\xaf\x9\x23\x4f\x5e\x6d\xe\x89\xc5\x30\x77\x68\x1\xfc\xe3\xf4\xa8\x9e\xc2\xcd\xe6\x71\x44\x2c\x3\xc1\xa9\x62\x9b\xee\xbf\x2e\x65\x12\xb2\x25\x8f\x5a\x31\xe2\xf6\x7\xd6\x48\xad\xeb\xcf\x19\xd0\xbc\x29\x92\x16\xba\x9d\x3c\x9c\x94\x3a\x80\x2\xa4\x7f\x11\x1d\x63\xe7\x6c\x40\x86\x76\xf9\x83\x54\xa3\x84\x72\x18\x4b\xf7\x7a\xf1\x4a\xd2\xfd\xec\x2d\x8a\x3d\x7e\x78\xda\x42\x3e\x27\xdd\x5c\x69\xc6\xe9\xf8\xa1\x98\x36\x35\x60\x51\x85\x88\x53\xac\x10\xd4\x4\xdc\x6a\x7d\x9a\xb0\xa6\xc\xe5\x56\x32\x6b\xa2\xe8\x57\x38\x20\xce\x5b\x8d\xf2\x81\x22\x1b\x3f\x87\xbd\xa\x17\xb5\x34\xc8\x1e\x8b\x5\x8\xb1\x75\x59\xf5\x45\x79\x49\x5f\x41\x37\x28\xd1\x39\xab\x26\xa7\xb4\xf\xdf\xb6\xdb\xb3\x4e\x2a\x58\x52\xd8\x82\x90\x5d\x99\xbe\x6f\x97\x6e" }, + { 0x5409e8, "\x2e\x94\x26\x55\x6c\xd6\xe3\x30\x16\x24\xae\xb8\x39\x13\x48\x85\x2\xa\xa8\xb9\xfb\x58\x3e\x59\x40\x37\x89\x4c\x68\xc9\x5b\xdb\xee\x83\xb\x64\x49\xf0\x52\xeb\x3f\x65\xbc\xfa\xa4\x6\x76\x27\xec\xc2\xe0\x53\x2a\x3c\x2b\xa2\x3d\x12\xde\xc7\xfc\xd7\x5\xed\xff\xc0\x9d\x14\x4a\xf7\xa3\x87\x79\x96\xa6\x7e\xd3\x1b\xf5\x90\x3\x80\x19\x4f\x77\x2f\xb1\x84\x7a\xe\x8e\xef\x62\xcd\xce\x9a\xd8\xb2\x69\xc4\xb0\xda\x23\x8\x11\xa0\x6b\x73\x4d\x9\x4e\x8c\x17\x21\x67\xbb\xd5\xcc\x20\x36\xea\x95\xe1\x5c\xe2\x7d\xe7\xc\x33\x5f\x99\xa5\xf4\x44\xdd\x25\xc1\x35\x29\x1a\x1c\x28\xb4\x9c\x34\x6f\x15\xa7\xf9\xe6\xb5\xd4\xe9\x9b\x1\x31\xf8\x72\xb3\x2d\x70\xdc\xfd\x46\x1f\x42\x8f\xcb\x54\x63\x93\x8d\x41\x5e\x9f\xe8\xf1\xe4\xb6\x71\x18\xbd\x6e\x7f\x81\x32\xd0\x74\xfe\x0\xcf\x47\xc6\xaf\x82\x38\x91\xac\xad\xc3\xb7\x6d\x1d\x8a\x98\xca\x97\x1e\x60\x7b\x88\xaa\xd2\xd1\xa1\x86\x61\xba\xc8\x10\x22\x3a\x9e\x51\x43\x92\x75\x3b\x56\xf2\x45\xa9\xbe\xd9\x78\x5d\x5a\x4\x4b\xd\x66\xf3\x7\x57\x7c\x2c\xe5\x50\xc5\xbf\xf\x6a\xf6\xdf\x8b\xab" }, + { 0x540d18, "\x7a\x2e\x7c\x16\x54\x74\xa6\xd7\x3d\x42\x25\xa\x4c\x87\xff\xbd\xc6\xcf\xaa\x78\x0\x95\x91\x68\x50\x7e\x4\xbe\xf\x83\xc7\x82\x9a\xa1\x36\xe2\x9b\x43\x62\x79\xe4\x73\x93\x56\x17\xb5\x60\xf9\xf0\xd\x2\xef\xbb\x22\x1c\xfb\x28\x94\x1e\xdc\x1d\x2a\x7\x72\xa0\x2f\x40\xed\x6c\x7b\xcc\xb4\xbc\xeb\xf4\xa3\x96\x7d\xb8\xf6\x75\x9\xc5\xf2\x70\x33\xc2\x13\xf7\xdb\x97\x1b\x6f\x3\xe3\x6\x44\xc1\xd3\x2b\x4d\xe9\xb9\xe1\x64\x20\x8d\x18\x76\x9d\xda\x67\xa7\x9c\x32\xb\x6a\x99\xf1\x41\x59\x71\x23\x14\x88\xac\x49\x37\xba\xe6\xe0\x51\x4f\xfd\x8e\xe7\xd5\xcd\xd6\xb2\x58\xa8\x55\xa2\xc3\xdf\x5e\x9e\xc9\xd2\xd8\x7f\x84\x39\xb6\xab\x63\x9f\xfa\x69\xfe\x21\xb0\x3a\x1f\x34\x5c\x4a\xbf\xe8\x52\x8a\x4e\x30\x5b\x92\x46\x4b\x8b\x5f\x8f\x90\x6e\x61\x89\x3e\xd9\x27\xaf\xee\x26\x98\xb1\xde\x19\xca\xf3\x86\x53\xa4\xd0\xad\x1a\x47\x80\x85\x45\x2d\xc8\xe\xa9\x3b\x65\xb7\x8\x24\xb3\xc\x11\x35\x15\xdd\x5\xce\x5a\xea\x2c\x6b\xec\xe5\xf8\x3c\x77\xcb\x6d\xc0\xd4\xae\x81\x57\x31\x12\x10\xfc\x3f\x1\x29\xd1\x38\x8c\x5d\xf5\xc4\xa5\x66\x48" }, + { 0x541218, "\x6e\x60\xba\x8c\x16\x67\xc7\xd9\xa1\xf9\x25\x41\x77\x6\x4b\x81\x98\xfb\x39\xe0\x7d\xa0\x10\xa4\x31\xf\xe5\x2b\x2d\xea\x68\xdf\x3d\xc8\xd5\x62\xaf\x83\xbd\xdb\x18\x88\xc4\xa9\x14\x38\x7f\x95\x5b\x51\xeb\x8e\xc\x2\xd0\x1\x6a\xcf\x92\x20\x7e\xc2\xc5\x36\xa6\xcd\x89\x64\x22\x8a\x96\xff\x49\xad\xb0\xc1\x13\x32\xa2\x99\x59\x17\xa5\x56\x29\x3b\x84\x93\x33\x5\x1c\x26\x94\xe8\x5d\xb8\x4\x5c\x4d\x46\xe9\x80\x4c\x45\x85\x9c\xb6\x11\xb1\xdd\x9b\x78\x9e\x8d\xac\xe2\x73\xbf\x82\xd2\x97\x57\x12\x63\xa8\x1a\xf2\xbc\x0\xc3\xcb\x7c\xf3\xe4\xdc\xd1\xed\xce\xd4\x6d\x15\x44\x8b\x52\x75\xd8\x7\x48\xfe\xe\xf6\x1f\xe3\x6c\x4e\x40\x4a\x91\x61\x70\xae\xe6\x19\xcc\x66\x1e\xa7\xd3\x43\xda\xde\x2a\xb4\x3e\x3a\xca\x9a\x5e\x71\xd\x34\xef\xb5\xb\x55\xbb\xee\x35\x50\x69\x4f\x9\x7b\x1d\x47\x86\x53\xb3\xbe\x79\xa3\xb9\x24\x8f\xe1\x1b\x58\xa\xd7\x2f\xfc\x8\x72\xf5\xe7\x7a\x5a\x54\xb7\x87\xfd\xf0\xc0\xc9\x30\x27\x3\xf1\xd6\x74\x3f\x90\xf7\x37\xf8\x28\x9f\x42\x6b\xab\x76\x23\x65\x6f\x2e\xb2\x21\xc6\x3c\x2c\xfa\xf4\x9d\x5f\xec\xaa" }, + { 0x547d98, "\x84\xf6\x55\x2c\x2b\xb\x30\xb6\xd7\x91\x7b\xea\xfc\x8b\xb9\x6d\x11\x2a\x4a\xba\xc5\xfb\x8\x5c\xda\x3\x9f\x52\x8e\x81\xc4\xb3\xa5\x38\xf1\xc7\xca\xd9\xfe\x58\xcd\x42\x1a\xd8\xbd\x9a\xa4\x45\x36\x4f\x4e\x43\x9c\xe0\x9d\xd2\xd4\x19\x98\x26\xdd\x5d\xa8\x28\xfd\xc2\x31\xa0\xed\xbe\x1d\xd6\x68\x3a\x9\x12\xcc\x48\xa6\x95\x66\x6a\x92\xbb\xbc\xaf\xaa\x93\x53\x2d\xb0\xf2\xd\xd1\xcb\x2\x76\xb4\x5\x4c\x85\xde\x51\xe1\x54\x47\x8f\x70\xf5\xb1\x96\x18\x78\xfa\x39\x62\x88\x6e\x9b\x59\x8d\x8c\x87\x1\xf\x4d\x6\xa7\xe3\xb7\x77\xb2\xf0\x1b\x7a\x83\x50\x1f\x8a\xe8\x5f\xae\x4b\xeb\x13\xe5\xdf\x7\x41\x63\xf4\xc3\x64\x32\x21\x29\x94\xa9\x16\x6b\xa\x3b\xd3\x69\x5a\xa2\xff\x72\xef\x89\x2e\x7c\x82\xab\x49\x22\x61\x34\xdb\x7d\x5b\x5e\x65\x6c\xdc\xf7\x2f\x10\x3f\x60\xac\xc\xf3\xbf\x46\x86\x44\x99\xf9\xc8\x35\xec\xd5\x1e\x6f\x15\x4\x97\xc6\x25\x90\x1c\x80\x75\x3d\xa1\x33\x0\xd0\x7e\xb5\xe\x57\xe7\x67\x23\x17\x74\x27\x7f\xce\x3c\xad\xee\x3e\x37\x24\xe9\x71\x20\xe6\xe4\x9e\xa3\x73\xf8\xe2\x14\xc1\x56\x79\xcf\xb8\xc0\xc9\x40" }, + { 0x547f10, "\x5\x3d\xbf\x26\xdf\xc3\xc0\xfd\xa2\xb\xee\x82\xad\xbd\x48\x1f\x66\x2c\x57\x13\x3e\x5c\x50\xe7\x29\xb7\x62\x32\x85\xe3\x9c\xf0\x69\xa6\x65\x92\x84\x9f\x54\xec\xa0\x15\xf9\x0\x78\xf7\xe1\xb5\xb8\xf2\x7f\xae\xf5\x44\xb2\xd6\xcb\xc\x8e\x7d\x4\xb1\x36\x24\xe\xa\x16\x43\xfe\x77\xb9\x63\xc5\x49\x3f\x71\xf6\x64\xc6\x87\xd0\x1c\xa1\x7e\x7c\x23\xd8\x67\x9b\x59\x53\xf3\xa5\xce\x7a\xb0\x68\x3a\xd9\xe9\x8a\xcc\x80\x45\xe4\x6\x4e\x2f\xd5\x6c\xea\x19\x9e\x97\xe2\x8d\x60\x37\x8b\xd4\xdd\x81\x5b\xa4\x8\xf1\x2d\x4d\x6a\xfa\xe0\x75\xa9\xe6\xd3\x76\x31\x86\xc1\xa8\x46\x72\x58\x38\x2a\x96\x73\xc4\xc7\x51\x9d\x30\xd2\x88\x27\xc8\x95\x52\x1d\x21\x94\x5e\x1\x56\x3b\x9\xdc\xa7\x79\x3\x7b\x39\x28\x6e\x1e\xc2\x2b\x70\x99\x6f\xff\x17\x18\xda\xaf\x2e\xb3\xba\x42\x5a\x55\x10\xd7\xe8\x47\xfb\x83\x8c\x5d\x6b\x3c\xab\xeb\xef\x25\x5f\x22\xb6\x33\x9a\xcd\x2\xb4\x91\x7\xd\xf\xdb\x1a\x61\x12\xbc\xcf\x34\xbb\x6d\x20\x4c\x11\x4a\xaa\xfc\x41\xe5\x1b\x74\xde\xbe\x4b\x40\x90\x98\xf8\x4f\x14\xca\xf4\xac\x93\x35\x8f\xc9\x89\xd1\xed\xa3" }, + { 0x5387b0, "\x78\x56\x88\x23\x55\xb3\xa8\xaf\x59\xea\x6\x1f\x73\x25\xb0\xe1\x70\x4d\x82\x58\x26\xe7\x40\x1a\x6c\xc1\x48\xb1\xf0\xba\xff\x0\xab\x2d\xa6\x22\x43\xee\x19\x8c\xe\xda\x17\x53\x85\xbd\x1d\x6b\xf8\x50\xce\x76\x4\xdd\xa7\xf1\x8e\x52\x37\xa2\x51\xe3\x69\x3a\x1c\x16\x68\x4a\x86\xbb\xb6\x6f\xdc\xfe\x14\xc\x79\x5e\xf4\x96\x42\x54\x2e\x84\x5f\xb5\xbf\xcf\x61\x7d\xd7\x98\x71\x3e\xcd\x20\x3f\xd0\xae\xa9\xd\xc7\x8\x65\x8d\x3c\x81\x29\xb8\x6d\xb4\x80\xd1\x4b\x5b\x28\xa5\x4c\xa0\x6e\x90\xa\x11\x3\x64\x21\xdf\x2f\x24\xeb\xf2\x7b\xc5\xac\xb\xec\xed\x66\xd6\xe0\x9\x41\x32\xcb\x83\x93\xfa\x15\xe5\x27\x5a\x87\x44\xd4\xde\xf\x3b\x1\xb7\x2a\xf3\xa1\xd5\x72\xb2\x6a\x2b\x95\x7a\x8b\xca\x7e\x18\x7f\x47\xe6\xdb\x49\xf7\x9a\x9e\xad\x9d\x57\xf6\x60\xd2\xfc\x30\xfb\x9b\x45\xd9\x2c\xf5\x5d\x33\x1b\xc4\x89\x13\x35\x67\xef\x2\x36\x92\x99\x39\xf9\xaa\x74\xe2\x5c\x3d\xc3\x63\xcc\xc9\x62\xa4\xfd\x34\x12\xbe\xc0\xc8\xc2\x7\x10\x75\x31\xe8\xbc\xd8\x97\x4f\x46\x1e\x7c\x38\x4e\x94\x9f\xc6\x8f\xe9\x91\xe4\x8a\xa3\xb9\x9c\x5\x77\xd3" }, + { 0x539420, "\xbb\x1a\x8e\x40\x7\x47\x3e\x6e\xb1\xfa\xa5\x63\x7c\xec\xa9\x75\x55\x76\xd2\xa6\xcb\xe4\x2d\xc6\x43\xa8\x18\x79\x48\xf0\x38\xd0\x9a\x8\xd5\xa0\x22\x7b\xc1\x84\x5a\x6b\xae\xd7\xbe\xb9\x50\xcf\x46\x70\x91\xed\xba\x8f\x7f\x1\xc5\x7d\x34\xf4\x14\x2\xe3\x2f\x64\x96\xb2\xee\x94\x4e\x90\x20\xd9\x95\x30\xca\x65\xf\xb\xd4\xd6\xde\xeb\x2a\x62\xd8\xc7\xdd\xe8\xe2\x4c\xbc\x77\x81\x66\x24\xc9\xb7\x60\x12\x39\xda\x71\xf1\x4d\x6c\xa\xf9\xb5\x6\x52\x3b\xa3\xb3\x7a\x35\x13\xe5\x57\x33\xc0\x16\x17\xfb\x87\xe7\xa1\x42\xe1\x67\x44\x54\x3d\xa4\x9\x19\x61\x15\x29\xb0\x0\xbf\xac\x5d\x1e\x27\x99\x56\x26\x83\x11\x5f\x69\x4f\x1d\xf5\x5\x8c\xff\x2b\x1c\x59\x21\xaf\xa2\xe\xdc\xb8\x85\x78\x80\x6a\x5c\x4\xfd\x25\x6d\x32\x9c\x8a\xc2\x8b\xf3\x9f\xb4\xd\x74\x9b\x8d\x97\x4a\xc3\x9d\x7e\xad\x28\x1b\x98\x53\xaa\x36\xf2\x49\xc8\xce\x73\xf8\xfc\x68\xef\xe6\x89\x3a\xea\x37\x31\xcd\xe0\x86\x3f\xb6\xab\xdf\x58\x23\x41\x3c\x88\x1f\xbd\x2e\xe9\xc4\x82\x72\xcc\x6f\xf6\xd3\x4b\xa7\x93\x5e\xfe\xf7\x51\x45\xd1\x10\x2c\x92\x5b\x9e\xdb\x3\xc" }, + { 0x547c10, "\xb4\x8f\x68\x29\x2d\x91\x41\x34\x56\x3a\x46\xf8\xcf\x63\xb8\xb2\x1d\xcc\xb5\x5f\xe0\x83\xd0\x66\x28\x60\xa0\x20\x88\x3\x9b\x4\x36\x55\x1f\x6d\x24\x62\x7b\x99\x53\xf2\x86\x4b\xff\x3b\xe9\xce\x92\xa5\x71\x5a\x7\xd2\x4a\xdb\xa2\x9d\xf4\xfc\xc9\x90\xac\x72\x77\x1\xb9\x2a\xf1\xd4\xfa\xc2\x61\xc0\xcb\xf5\x6b\x18\x67\xc6\x0\x9\x58\xfb\xba\x3c\x1c\x49\xae\xe6\x38\x40\x80\x97\xdd\x14\xf\x69\x89\x4c\x59\x16\x9a\x2e\x4f\x4e\x5\x33\x3d\xa6\xb6\x6a\x13\x30\xca\xeb\x25\x65\xd7\x57\xa9\x6c\xb1\xde\xd5\xcd\xed\x7c\x15\xbc\x19\xa4\x85\xc1\xa1\x73\xef\xbe\xc5\x35\xe\x7e\x47\x8\x64\xf6\x3f\x8a\xf7\x52\x75\xe5\x48\x37\x23\x8c\xdf\xa7\xd3\xe1\x2\xd\xa8\xe4\x74\x5d\xc4\xad\xf3\xbb\x54\x70\xbf\xdc\x1a\xec\xc3\x31\x1b\xa\x7d\x93\xb7\x9e\x2c\xd1\xfd\xe3\x3e\x96\xd9\x51\x12\xe7\xd8\x50\xb\xe8\xe2\x17\x4d\x5e\xd6\x39\xc7\x5b\x6e\x21\x84\x22\x11\x82\xf9\x26\x1e\x6f\x95\x6\xea\x10\x98\x2f\x78\x5c\x32\x45\xaf\x8d\xf0\x7a\xbd\xaa\x81\xda\xb3\xc\xfe\xc8\x2b\x76\x79\x8b\x94\xb0\xa3\x7f\xee\x42\x87\xab\x27\x9c\x44\x43\x8e\x9f" }, + { 0x541400, "\x7b\x35\x11\x79\x7\x2f\xf6\x82\x8e\xb4\x6e\xd2\x6d\xc5\x8c\x1c\xe0\xd6\x34\xf0\x4f\x25\x59\xe8\xdf\x1d\xeb\x32\x86\x51\xa4\xf2\x5c\xd1\xc8\x41\xec\x9d\x62\xac\xdd\x3e\xb8\x65\x75\x89\x12\x6c\x40\x4e\xc7\x27\xe1\x37\xcf\x9\x16\x78\xaa\x58\xd\xe6\x54\xfe\x8f\xfd\xf9\x61\x26\x3f\x2e\xcd\x2c\x4\xb2\x80\xf\x14\x6f\xc6\xab\xfb\x13\xdb\x9a\x21\xb3\xc0\xa9\x19\x70\xf3\x2b\xae\x9b\x49\xb7\xa8\x24\x1b\x48\xea\xed\xd9\x47\x9e\x9c\x69\x3c\x66\xbb\x6\x46\x38\x17\xb5\xcb\x5\x4a\x5e\x15\x20\xb9\xb6\x33\x4c\x7d\xa3\xd7\xb1\x23\x72\xc3\x4b\x63\xbe\xf7\x5b\x74\x64\x77\xcc\xd3\x85\xde\x1a\x31\x97\xa2\x8b\xfc\x10\x5f\xdc\xd5\xb0\xbd\x55\xc1\xe7\xc\x50\x43\x39\x71\x52\xe5\xaf\x8a\x60\x92\x2d\xd8\x3\xf5\x28\xca\xef\xd0\xc2\x53\x91\xa6\x73\x56\xa5\xf1\x57\x42\xf4\xd4\x36\x8d\xbc\xe9\x7e\x2\x76\x18\xb\x84\x5a\xe2\xbf\x68\x95\x29\x98\xad\x88\x1f\x81\x67\xa1\x3a\xa7\x22\xf8\x1\xa0\xce\x7a\xda\x30\xc4\xe4\xee\x7c\x3b\x4d\x3d\xe3\xfa\x6a\x7f\x99\x0\x93\xe\xff\x90\xa\x2a\x5d\x96\x8\x6b\x83\xba\x1e\x44\x87\x45\x9f\xc9\x94" }, + { 0x541588, "\x11\x2b\xc0\x60\xd2\xf5\x1f\x42\xf7\x8e\x13\x8c\x68\x7b\x90\x26\xd1\x28\xa3\x9d\xd\xb6\x9a\x1b\xb5\xa0\xba\x7d\xa8\xd5\xe\x88\x93\xa6\xbe\x98\xd6\xe4\x50\xa1\x3e\xb7\x8d\x94\x46\x4a\xbc\xd7\xd4\xf1\x59\x97\x2a\x66\x2\xe1\x3d\xf\x1e\xe5\xc5\x49\xe9\xa4\x99\x6f\x6\x37\x96\xdb\x58\xd0\xfe\x2c\xe8\x21\x38\x71\x62\xb4\xda\x12\xac\x79\x17\x5b\xc8\x82\xeb\xf0\xe2\x3\x80\xaa\x9e\xb\xe3\x5a\xc1\x91\x35\x75\xea\xfa\x20\xdd\x23\x84\x31\x9b\x5d\x78\x7a\xc\x27\xa7\xf3\xa2\xa9\x87\x52\xb8\xf9\x5e\x9\x6e\x64\xc9\x18\xd8\xee\x86\x2f\x30\x7f\xb2\x3a\x47\xb3\x74\xde\xe7\x4b\x2e\x41\x29\x5\x33\x15\xfd\x7e\x22\xf6\x70\xbb\x67\x34\xf4\xab\x92\x1a\xe6\xa5\x7\x65\x3f\x39\x95\xef\xb1\x24\x85\xfc\x53\xf2\x1c\x8f\x81\x48\x5f\x25\x76\xdc\x19\x56\xcd\x2d\xff\x43\xbf\x4e\xb0\x1\x0\x9f\x51\xc7\x57\xad\x73\x72\xc4\x8\xbd\xa\x7c\x1d\x40\x77\x61\xb9\x89\x9c\x3b\x8a\x16\xc6\xcb\xce\x4f\x63\xd9\x6d\xcf\x3c\x6b\x54\xdf\x4c\x10\x8b\x69\x32\xe0\x45\xaf\x4d\x83\x5c\xec\xc3\x14\xf8\xed\xc2\x6c\xca\x55\x44\x6a\xcc\xfb\x36\xae\x4\xd3" }, + { 0x541688, "\x6b\x1d\x53\x81\xa\x82\x7\x16\x41\x54\xa0\xbd\x87\x3\x20\x2d\xf7\xb5\x4\x59\x1b\xdf\x8c\x22\xe2\x10\x9\x55\x9e\xef\xa6\x57\x65\x7f\x3a\x35\x9c\x3e\xfe\x40\xfd\x17\xc0\x26\x33\x38\x7b\x6a\x5c\xd1\x50\x14\xec\x49\xfb\xa9\xe5\x1e\xf3\xea\xde\xdd\x44\x75\x46\xc9\x2b\xcb\xbb\x27\xab\x15\xe7\xed\x91\xda\x25\x4e\x5b\xb7\xee\x77\x58\xb8\xe4\x48\x63\x47\xd9\x0\xb0\xfa\xe1\xff\xb3\x72\x32\x3f\x29\x19\x68\x1\x23\xcc\x93\x8d\xd3\x31\xf9\xcf\xf6\x73\x8a\x4f\x11\xe6\xca\xa8\x18\x97\xc2\xd\x92\x62\x84\x85\x3b\x52\x6f\x9b\x6e\x5f\xe3\x9a\xce\xdb\x3d\x70\x95\xb\xdc\xc1\x2\xae\xc5\x56\x7e\x8b\x2a\xf5\x86\x28\xe0\xf1\x42\x83\xd5\xc8\xc7\x8\x4a\x5e\xf\xf8\x78\x5a\x1a\x66\x36\xfc\xd7\x34\x2c\xc3\x76\xbf\xe8\x21\x8e\x2f\x69\x7d\xa3\x98\x67\xa4\x8f\xe\xf2\xaf\x61\x4d\x24\xba\xaa\x7a\x6d\x5\xb9\x89\xbc\x2e\x30\x4b\xb4\x6c\x80\x1c\x9d\xc6\x3c\xb1\xd0\x88\xb6\xa1\xcd\xb2\xc\xbe\x79\xa2\xd8\x99\x4c\xd2\x74\x37\x51\x71\x9f\x13\x6\x90\xeb\xc4\xa7\xf0\xa5\xd6\x12\x45\xac\x64\xf4\x1f\xe9\x43\x96\x7c\x5d\x39\xd4\xad\x60\x94" }, + { 0x541988, "\x4b\x8e\xb4\x43\x5a\xcc\x15\xc0\xa0\x22\x21\x58\xec\xad\xde\x42\x4a\x70\xd4\x26\xc6\xeb\x3a\x61\xbd\x99\x20\x92\xfe\x9d\x68\xae\x1f\x11\x5c\xcb\x8\x66\x49\xe1\x2e\x96\xf2\xca\xdd\xb0\x37\xfd\x86\xa1\x7d\x7b\xbe\xf5\xd9\x60\x6d\x63\xe0\xe8\x84\xf8\x75\x44\x6b\xab\x81\xe5\xa5\xe4\xd6\x3e\x10\x3\x97\xd8\xbc\x5\x98\x1a\xa\xd\x5d\xf1\x8a\x2c\x82\x34\xc8\x4e\x2b\xfa\x7\x4c\x2d\x6c\xc1\x5e\x46\x29\x9a\xc7\xb8\xb9\x56\xa2\x7f\x1d\x3d\x1e\x9c\x80\x6e\xb5\xe\x7a\xcf\xfc\x30\xd5\x95\xa3\xb2\x1b\xf4\xe2\x89\x28\x12\xc5\x3f\xf9\x2f\xc9\x4d\xed\x40\x1\x59\xb6\x85\x50\x77\xe7\xf7\x2a\x76\x51\x78\xc2\x8f\x94\x87\xe6\x8b\x9\x93\x8d\x57\xda\x79\x2\x71\x55\x19\xb3\x5f\x69\xdc\x25\x18\xd2\xf3\x4f\xba\xea\x9e\xaf\x31\xee\xa9\x0\x35\x90\xff\x6\x1c\x4\x13\xce\x14\x39\x5b\xdb\x38\x36\x24\x27\xfb\xac\x52\xd0\x6a\x74\xf0\x62\x45\x72\xbf\x65\x9b\x91\x48\xd1\xb\x32\xb7\xdf\x88\xf6\x41\xa6\x9f\xd3\xc\x7e\x6f\xaa\x73\xd7\xc4\xa4\xe9\x17\xcd\xb1\x3b\x64\x8c\xf\xef\x54\x83\x7c\xa8\x23\xe3\x16\xc3\x47\x3c\xa7\x33\x67\x53\xbb" }, + { 0x541b30, "\xc9\x4d\x8e\xe5\xaf\x88\xa5\x73\xeb\x9e\x4e\xdc\x6b\x68\x28\x79\x7b\xad\x2c\xe\x51\xe1\xc6\x1f\x71\xb2\x61\x7\x42\x49\x35\x1a\xf2\x80\xd2\xd7\x82\xc3\x2b\xa2\xb6\x8b\xec\xa0\x2a\x29\xe7\x8a\x1c\x4b\xdf\xf7\xba\xb1\xdb\xee\x43\x7e\x87\xa7\xfa\x19\xb5\xf1\x95\x4f\xce\x66\xd9\xae\x11\x46\xa\xb8\x40\xf6\xe3\xbc\x77\xf8\xb3\x78\xf3\x5a\xac\xb0\x63\x8d\xcd\x64\x39\xa1\xa4\x9a\x4a\x69\x41\xed\x98\x37\xfb\x3f\xd0\xaa\x6\x7c\x7d\x3d\x94\xa6\x5f\x24\x12\x8\x9d\x32\xc4\x3b\xda\xa3\x10\x34\x8c\xd8\x5c\xcb\x20\x5b\x70\x86\x14\x27\x36\x1\xe9\x3\xc5\xa9\x67\xfd\x9b\x57\x6c\x0\x2e\x4\x84\xf\x26\x72\x92\x58\x17\x83\x2d\xdd\x6f\x62\xc7\xc\x55\x6d\xd5\x13\x3c\x5d\xb4\x5e\xea\x47\xc8\x25\xca\x59\xe0\x97\x21\x9c\x96\x93\x2f\x1e\x8f\x7a\xbf\xcc\xde\xf9\x16\x22\xf0\x81\x75\x3e\xd\x4c\xfe\x23\xbe\xa8\x76\x1b\xf5\x56\x18\x2\xe2\x33\xd3\xf4\xab\xb9\x6e\xc0\xff\xb\x1d\x60\x85\x30\x3a\xe6\x65\xd1\x52\x53\x54\xb7\x9f\x48\x89\xc2\x15\x74\xcf\x9\xc1\x38\x7f\x44\x99\xbb\x45\x31\x90\xd4\x5\xbd\x91\xfc\xef\x50\xe8\x6a\xd6\xe4" }, + { 0x541c30, "\x76\xad\x9\x82\xbd\xb\x69\x6a\xe0\xac\xd4\x34\x31\xd2\x83\xe2\xe7\x28\x70\xe8\xc1\xdf\xa\x2d\xbe\xd5\xe9\xe3\xfb\x79\x7c\xff\xf0\xe6\x85\x43\x47\xb2\x64\x92\x81\x80\xb4\x6d\xf7\xee\x1\x1f\x60\x48\x8e\xa4\x54\x74\x50\x4a\x2a\x5e\x39\x5f\x8f\x46\xb1\x8\x12\xf3\xde\xbf\xcb\x2\xdd\xa2\x9e\xd6\x6f\x9a\x9c\x3d\x93\x77\x2f\x21\xf1\x19\x9f\xcd\x2c\xeb\x30\x13\x89\x88\xa1\x71\x17\x7\x73\x32\x16\xc6\x4d\x3a\xb5\xa3\xa7\x1e\x10\x65\x23\x7b\x5c\xd7\xcc\x15\xca\xae\x6b\x91\xef\x1c\xe\x8c\xda\x72\x4c\x6\x0\xdb\x8d\xbb\xb7\x26\xd\x6c\x37\x8a\x84\x2b\xf2\xd3\x41\xaa\x6e\x7d\xc2\xfc\x3e\xd1\x4\x45\x68\xb9\x27\xe4\x58\xb0\x1b\x44\x40\xba\x53\xd8\x66\x14\xe1\x67\x5\x5d\xc\x96\xf8\x4e\x98\x7e\xf4\x3\x99\x52\x51\x4f\x11\xa8\x1a\x9d\x86\x97\xc5\xf\x25\x75\xc8\x94\xa5\xb8\xec\xa6\xa0\x38\xab\xc9\x36\x24\x35\xc0\xc7\x90\xd0\x55\xfa\x95\xaf\x49\xfd\x7f\x42\x87\x7a\x3f\x56\xf5\x3c\x62\xc3\x59\xb3\x33\xa9\x2e\x1d\xea\xbc\x63\x18\xed\xd9\x3b\xf9\xc4\x78\x22\x5a\x29\xfe\x9b\x61\xe5\x5b\x8b\xce\x4b\x57\xcf\x20\xdc\xf6\xb6" }, + { 0x541db8, "\xf\x3\xdb\xb5\x48\x8b\xe2\xbd\x4a\xc7\xdc\x63\xe9\x71\x94\x3d\xf7\xf9\x1c\xfa\x77\x1e\xea\x97\x9e\x57\x43\x91\xf8\xae\x4f\x55\x9b\xd1\x32\x67\xcf\x90\x2b\xac\x3a\xb4\x6\x85\x98\xc\xc1\x2c\xec\x40\xbf\x9\x59\xde\xcb\x6b\xa1\xad\x47\xbb\xd2\x22\x64\xa4\xb\xe5\xce\xd0\xff\xd4\x41\x45\x51\x65\xb9\xdd\x5\x38\xb6\xc2\x35\x21\xab\xc4\x1d\x1f\xa2\x74\x0\x5e\x93\xa\xe\x68\xda\x95\xf5\x6a\x1\xbc\xfe\x16\x12\xfc\x62\x2a\xf3\xf6\x7c\x5a\x46\x1a\xcd\xc3\x7b\x42\x27\x8f\x25\xa6\xca\x6c\xa7\xf2\x23\x5d\xd5\x54\xe4\xc5\x20\x50\x56\x3e\x69\x70\x52\xed\x7\x17\x66\x8a\xb1\x82\x37\xef\x3b\xfb\xd9\x7e\x36\x2e\x9a\x1b\x2f\x29\xe7\xa9\x83\xe3\xa3\x8c\xf1\x2d\x49\xd7\x31\x10\x78\x8e\xb2\x87\xd8\xe8\x5f\xb0\x76\x9d\x79\xc9\x4e\xe1\xe0\xee\xf4\x13\x9f\x14\xbe\x73\xb8\x88\x3c\x86\x7a\xa5\xba\x58\x7d\x6e\xa0\xc8\x11\x30\x61\x81\x33\xd6\x4c\x9c\x18\xf0\xfd\x99\x3f\xc0\x80\x28\x5b\x72\x4d\x6f\x92\xeb\x24\x75\x89\x8d\x15\xcc\x60\xaa\x4\x26\xd3\xdf\x8\x2\x5c\xa8\xe6\x44\x7f\xb7\x96\x39\xc6\x19\x34\xaf\xd\x53\x6d\x4b\xb3\x84" }, + { 0x541fe0, "\x30\x7a\x4b\x48\x47\x3f\xc8\x2e\xde\xb1\x5f\x96\xe3\x40\xb3\xdf\x70\x73\x67\x87\x78\xdd\xa\x6b\xb5\x2f\xf0\x13\xc5\x1c\x7f\xa1\x8b\xb4\x8e\xeb\x63\xd5\x89\x9d\x0\x68\xab\x9\xfe\x76\x71\xb7\x5d\x92\xc1\xdc\x46\x79\x8c\x16\xf3\x1a\xc9\xd\x3b\xf6\xad\xe7\xa5\x45\x3\xee\xd1\x5c\xb6\xbc\x52\xc3\x3a\x94\x1f\xe2\x6f\x14\xca\x29\x69\x4a\xe5\x51\x31\xff\xaf\x50\x9a\xcc\xf4\x39\x7\x86\x82\xfa\xac\x20\x26\x83\x9f\x54\x11\xa3\x1e\x81\x43\x2c\x8\x8d\x5a\x85\xa2\xcb\x2a\x35\xb2\xda\x2d\xfd\xc4\x37\xa7\x3e\x7e\x75\x65\xa8\x66\x1\x25\x32\xd4\x4f\xa0\x1b\x6\xae\x28\x15\x9b\xba\x2b\x34\x77\x8f\xec\x99\x7c\xc0\xb9\xf9\x88\xce\xe9\x84\x93\xb0\x22\xcf\xed\xf\x7d\x74\xe0\x61\x2\xa6\xbf\x58\xea\xf2\x95\xfc\x6c\x56\x91\x4c\xe4\x80\x49\xbb\x18\xd0\xa9\xa4\xaa\x5e\x8a\xb\x33\x38\xd6\x53\xdb\xf7\x60\x44\xc\xc6\x62\x55\xd7\xbd\xfb\xcd\x5\x42\xef\x57\x24\x12\x90\xd9\x19\x27\x5b\x6a\xd2\x98\x23\xbe\x36\x4\xc2\x7b\xf8\x6e\xe\xc7\x6d\xd3\xf1\x97\xe1\xe6\xd8\x10\x9e\xe8\xf5\x59\x9c\x4d\x64\x3d\x21\x1d\x72\x41\x17\x4e\x3c\xb8" }, + { 0x5420e0, "\xd8\x40\x46\x1c\x9c\xba\x77\xfd\x1d\xe0\xc0\x42\x92\xf0\xff\xa8\x78\x9e\x3f\xcd\x60\xea\xc7\x3c\x2f\x5f\x72\x74\xb3\x2c\xee\x94\x47\x80\xe8\xf5\x67\x8f\x53\x43\xd\xb9\xe9\xaf\x7e\x7a\xe\x63\xb6\xd2\xd4\x27\xc4\x7\x76\xad\x4e\x3\x5d\x2\xd6\xaa\x56\x6b\x12\x21\x37\xa0\xd1\xab\x3a\x11\x51\x90\x48\x23\x26\x6a\x6\x97\xc1\x9d\x35\xec\xa3\x24\x10\xfb\xf8\x41\x65\x1\x1f\x6d\x5\x8e\x7b\xb1\xfc\x44\xbc\x6e\x89\xa9\xc3\x2d\xb2\x18\xde\x71\xbe\xfe\xc5\x54\x73\x2b\x0\xa7\x5c\xae\xd3\x57\x95\xfa\xf1\x7c\xdf\xc\x31\xa6\x3d\x4a\x58\x79\x66\x87\xb8\x19\xf6\xf7\x8d\xbf\xcb\x45\x33\x6f\xb5\x91\x32\x5a\xbb\xdc\x62\x55\xa1\x4\x70\xa5\x8c\x16\x3e\x49\x64\x82\xf9\xdb\x59\x28\xcc\x50\x96\xb7\x38\xc6\x7d\x69\x29\xb4\x1b\xe7\x2e\xc2\xbd\x84\x85\x4d\xe1\x3b\xf4\xac\xd7\xe3\x8b\x4f\x30\x9f\x7f\x5b\xb\x20\xb0\x86\x88\xeb\xa2\xca\x34\x15\x81\x83\x13\xd9\x5e\x25\xf\xc8\xda\x4b\x99\xe5\x9\xf2\x93\xdd\x52\x6c\x2a\xc9\xef\x14\x9b\xf3\x68\xa4\x22\xce\x1a\x1e\xe4\xd5\x8\xe6\x9a\x98\xed\x61\x17\xa\x39\xcf\xe2\x4c\xd0\x8a\x36\x75" }, + { 0x542220, "\xee\xa9\x92\x52\x24\x57\x44\x8e\xa0\xb9\x95\x20\x5b\x70\xbd\xc3\xa7\x17\x4d\x1d\x12\x9a\x0\xd0\xfc\x9d\x41\x6\xf4\x86\x50\x74\xe1\x5d\xa2\xdf\xa1\xa3\xf\xd5\x1b\x62\x28\x7c\x10\x79\x9b\xe2\x13\x7d\xce\x97\xd7\xb\x56\xf0\x63\x3c\x68\xdc\x21\xed\x7\x3d\x7a\xb6\xb5\x23\xe6\x3f\x29\xeb\xd6\x67\x89\xb3\x87\xf2\xfb\x71\x90\x5a\xc6\x42\x2f\x32\x77\xd4\x15\xde\x84\xff\x7b\xd3\x47\xa5\xb8\xc4\x8b\x55\x6c\xc2\x5\x54\x1a\x65\xfe\xcf\x6a\xb7\xa6\x4\xc9\xaf\xf8\xf7\x40\x8d\x16\xae\x3e\x99\x6f\x4b\xac\x26\x3\xb4\x2e\xf3\x69\x34\xb0\x8f\x45\xcc\xd9\x2d\xcd\x4c\x9e\x5f\x85\xe5\xca\x58\xe\x9c\xf5\xfa\x38\xc1\x30\xd\x94\x36\x6b\xc8\xe4\xad\x39\x3b\x22\x46\x96\xc7\xbc\x5c\xe9\x80\xa\x73\x33\xfd\xd8\x88\x2a\x4e\xef\x4f\x5e\xc0\x1e\xc5\x27\xec\x18\xf1\xd2\xc\xba\x8c\xa8\x59\x98\xe8\x9f\x43\x51\x49\x72\x19\xbf\x2\x1f\xbe\x64\xda\x53\x4a\xab\x82\xf6\x3a\xbb\x91\xaa\x6d\x78\x81\x66\x7f\x75\x76\x1\x25\x35\xb2\x8a\xcb\x11\x48\xdb\x61\xe3\x6e\x93\x60\x14\x37\xf9\x9\x1c\x2c\xd1\x2b\x8\xa4\x7e\xea\xdd\x31\x83\xe7\xe0\xb1" }, + { 0x53ab20, "\xa5\xff\x5f\x5c\x76\xd0\x2c\x5d\x56\x88\x78\x11\x5\xaa\x2d\x3\x25\x2f\x32\x44\xae\x7d\xd4\xc\x38\xda\x6b\xde\xb1\x9f\xb5\x2b\xd1\xa8\x30\xf8\x1e\x73\xb6\x95\x55\x4\xaf\xf6\x48\x7c\xb3\x3f\x4b\xe2\x8b\xcd\x3e\xe0\x9c\x67\xc9\xf1\xfe\xea\xd6\x42\x63\xcb\x82\x94\x28\xc6\x54\x2e\x81\x52\x46\x41\x1\xe\x12\x43\x9\xf7\x3c\x2\x8c\xc7\x74\xd3\x45\x37\xbf\x58\x59\x6c\xfd\x7\xb0\x16\x39\x64\x23\xf9\x6a\x7a\x14\xd9\xb7\x86\x50\x19\x8\x57\x4e\x97\xac\x22\x7e\xbb\xad\x79\x4f\x85\x27\xc2\x61\x71\xe9\x1c\xc8\xc1\x93\x36\x70\x24\xc3\x3d\x1b\xf2\x6d\x15\x51\xfa\xbe\x87\xc4\xc0\x96\xb\xca\xa4\x75\xd8\x77\x1d\x53\x62\xe6\x2a\xb2\x4a\x8e\xd5\xdc\xf5\x35\x72\x5e\x34\xa1\x33\xc5\x69\x18\xa\xb4\x7b\x83\x31\xab\xa0\x9b\x21\xbc\x84\xfb\xd7\x89\x0\xd2\x3a\xfc\x13\x1a\xcf\xf3\xdd\x10\x90\x3b\xe4\x26\xf4\x4d\xa7\xf\x40\x7f\xe5\x29\x17\x8f\x20\xeb\xbd\x80\x99\x65\xa6\x6f\x4c\x47\xdb\x60\x1f\xec\x98\xe8\xa2\xb8\xb9\x5b\x91\xed\xf0\x9d\x68\x8d\x6\x5a\xba\x66\xdf\xa9\xe7\xe1\xef\x9e\x8a\xcc\x9a\xee\xd\x6e\xa3\xe3\x49\xce\x92" }, + { 0x542738, "\xa5\xc3\x4\xb9\x92\x3d\x8a\x86\xe9\x67\x74\xd8\x9b\xcc\xe6\xd\xc6\x23\xf\xa1\xac\x42\x28\x93\xf8\x9c\x8d\xc7\xb7\x3\x8c\x69\x3c\xd1\x81\xf9\xa0\xfd\xba\x0\x75\x49\xc4\xb\xfc\x68\x65\xb0\x80\x64\xa\xda\x83\xf5\x58\x14\xec\x46\x1f\x61\x13\x27\x6b\xce\x1d\xbe\x96\x19\xc2\x9\xef\x37\x2f\xe2\x47\xf1\x7e\x21\x30\x90\xf7\x2b\xf4\x3b\x7\x1a\x56\xd3\x72\x5b\x4b\x85\xe\xd5\x8\x6f\x5d\xc0\x79\x59\x26\x98\xfe\x7d\x6\x4d\x10\xbf\xf3\xee\x2e\xe0\xe7\xd7\xd2\x9f\x60\x88\x25\xde\x7f\x4e\xe1\xae\xdf\xe4\x38\xb8\xe5\x8f\xa2\xd9\xcd\xa4\x73\xdb\x84\xb5\xca\x17\xa7\x54\xab\x97\x91\xfa\x66\x1c\x2d\xea\x31\x35\xe3\x77\xa9\x36\x5c\xc\x76\x95\x5a\x7c\x1b\xbd\x8e\x94\xff\xf2\xbc\xc1\xb4\x87\x2c\x44\xb6\xaa\xc8\x33\xf6\xa8\x45\x48\xa6\x6c\x1\x63\x55\x6a\xd6\x9a\x57\x40\x15\xad\xb3\x3a\x5\x43\x51\xfb\x71\x9d\x22\x1e\xed\x53\xd0\xc5\x8b\xeb\x18\x6d\x20\x3e\xcb\x89\x34\xf0\x3f\x2a\xcf\x39\x16\x4a\xaf\x9e\x29\xb1\x6e\x62\x11\x82\x5f\x7a\xbb\x52\x12\xc9\x99\xa3\xdd\xdc\x4c\x5e\x24\x50\xd4\x78\x70\x4f\xe8\x32\xb2\x2\x7b\x41" }, + { 0x542df8, "\x94\x3b\xd0\xd7\xba\xb3\x84\xc4\x36\xdc\x30\xa9\xdd\xc7\xb1\x75\xe6\xa4\x71\xc2\x60\xbf\xf3\xea\x51\x49\x2f\x4e\xa5\x1\xa2\x44\x2\xfe\x85\xf0\x4\xcf\xac\xb7\x2c\x35\x5f\xa6\x18\x6a\x7a\xae\x9\xd3\x3c\x1a\xd1\x12\xcd\xaf\xcb\xb6\xe2\xef\x73\x7d\x47\x2d\xe0\x4b\xf5\x89\xbd\x79\x4c\xdf\x29\x19\x7\xbc\x66\x5c\xed\x62\x68\x3f\x81\x1b\xb4\x11\xc5\x93\xd\xc\x16\x52\x23\xff\xf1\x37\x83\x6d\x58\xab\x77\x59\x65\x46\x97\x56\x6e\xbe\xa1\xf9\x7c\x34\xc3\x76\xf\xb5\x96\x24\x10\xce\x82\x1d\x45\x1f\x67\xd4\xaa\x53\xad\xeb\xe5\x3\xa0\x64\x27\x38\xc8\x8b\x9f\xc1\x8c\x2b\xe9\x2a\xf6\xd8\x4f\xfa\x41\xe4\x7e\x8e\xe8\x90\x63\x9b\xb0\x72\x4a\x40\x57\xde\x61\xfc\x48\x1c\x17\x13\x14\x95\x99\x39\x28\xc0\x31\xe1\x98\x50\x5e\x0\x78\x3d\xfb\xf7\xda\xd5\x70\xca\x8f\x88\x6\xf4\xc9\xb8\xa7\x15\x5d\x6b\xbb\x8\x74\x1e\xcc\xd9\x21\x3a\x20\x3e\x92\x2e\x33\x54\x8d\x4d\x80\xf2\x5b\x91\xee\x42\xa8\xd2\xb9\x7b\xe\x9c\xf8\x9d\x86\x25\xa3\x22\xec\x5\xc6\x87\x32\x9e\xb2\xe7\x5a\x55\xa\xdb\x43\x8a\xb\x6c\x9a\xe3\x26\x69\x7f\x6f\xfd\xd6" }, + { 0x5430b8, "\x18\xde\x60\xb0\x52\x81\xc0\x13\xd9\xf6\x7f\x69\x1b\xa4\x27\x73\xa1\xe9\xad\x2a\x9b\x45\xc5\xa5\x2d\x16\xb6\x33\x5e\xc7\x3e\xd5\xbe\x5\x98\xa7\x82\x5c\xec\x29\xd1\x6b\x5b\x85\xf5\x89\xf1\x1c\xf9\x4b\x58\xa9\xac\x23\x2e\xe2\x7c\x36\x8c\x63\x2\x3b\x61\x39\x17\xe0\x32\xc1\xab\x4\x3d\x8f\x26\xd4\xef\xc9\x35\x2f\xe7\xd7\xa6\xcc\x9f\x44\xe4\xc2\xdc\x3f\x4d\x7e\x4a\xf7\x66\x38\x12\x3c\x96\x64\x5f\xf8\xcd\x7d\xb\x70\x76\x99\xba\xdf\xf\xa8\xff\xd2\x56\xeb\x94\xae\xbd\x78\xdb\xf4\xb5\x3\x7b\x80\xfe\xd0\xc6\x41\x0\xc\x86\x8e\x6d\x54\xb3\x4e\x8b\xb2\xb7\xe3\x43\xfd\x53\x11\xd6\xd3\x77\xed\x21\x14\x9a\x6\x9\x1a\x87\x9d\xcf\x37\xc4\x49\x6c\xe1\x10\x5d\x6f\x72\x19\x2b\x51\x15\x4f\x2c\x57\x55\x84\x92\x30\xd\x8d\x25\x24\x8a\xe6\xe\xf0\x22\xc3\x9e\xe8\x28\xbc\x1f\x65\xb1\x1\x20\xa\x46\x67\xfc\x31\x91\xe5\x5a\xca\x71\x90\xbb\xfb\x34\xea\xa0\x79\xee\xa3\xa2\xb9\xdd\x62\x7\xbf\x47\xce\x50\x88\x1d\xf2\x1e\xaa\xda\x9c\xd8\xf3\xcb\xb4\x48\x42\xfa\x4c\xb8\x6a\x68\x6e\x83\x7a\x97\x59\x93\xc8\x40\xaf\x75\x8\x74\x3a\x95" }, + { 0x543220, "\xbd\x7f\xc8\xb9\x77\x27\x36\x86\xbf\x96\xfe\xcd\xd\x93\xe0\xae\xec\x69\xee\x90\x3b\x91\x5a\xc0\xcb\x8\xfb\x5d\xa8\xe8\x26\x4c\x22\xf0\xa5\x5e\xff\xd5\x58\xc5\x89\x51\xf9\xfd\xfc\xce\xac\x74\x80\xa6\xde\x2e\x75\xd7\x61\x67\x3d\x35\xf6\x84\xdf\x3f\x5\xd8\x32\xc9\x54\x5b\x24\xc6\x6c\x11\x82\x9e\x2c\x99\x37\x9d\x1d\xd0\xbe\x6d\x6e\x92\xc7\x60\xe9\xaa\x47\x7e\x39\x2f\x97\x2\xad\x9a\xdc\xb3\x34\xca\xdd\x2d\xf5\x18\x81\xa4\x3c\x15\x40\x17\x63\xbc\xef\xcf\x1a\x52\xd2\x41\x55\x4a\x62\x8c\xf3\x68\x57\xe5\x9\xd6\x78\x59\xda\x7d\xe7\x50\x73\xba\x4f\xe1\x2a\xb0\xaf\x1e\x1b\xab\xcc\x9c\x0\x7\xe3\x46\x1f\x13\x85\x64\xe\x12\x45\x38\xdb\x79\x72\x70\xc2\x43\xb\xed\x44\xeb\xf2\x48\x30\x87\x8e\x31\x88\xb6\x49\x8f\xe2\x14\x7c\x76\xc3\xd9\xfa\x71\xa1\x6a\x25\x20\x98\x5c\x10\xf\x66\x94\xe6\xa7\x6b\xb4\xa0\xd4\x5f\x1c\x6\xd1\x7b\x8b\xb1\x4e\x28\x56\xb8\xf1\xc1\x16\x1\xea\xf8\x4\xbb\x19\x9b\x8d\x33\x42\xb7\x3a\x4d\xc\x7a\xe4\xf4\x83\x23\x9f\x3e\xc4\xd3\xb5\x3\x53\xb2\x95\x21\xa3\xa2\x8a\x29\x65\x4b\xf7\x2b\xa9\x6f\xa" }, + { 0x543580, "\xb3\xd\xc5\xef\x7f\x75\x36\xd3\xbb\x73\x87\x24\x17\x6b\xeb\x25\x53\x5c\xfb\xf9\x13\x67\x77\xe7\x1c\xcf\x8\x79\xba\xab\xa7\xc8\xc7\x98\x74\x2d\x34\xf\xaa\xf6\x97\x69\x9f\xc0\x8c\xd9\x51\xcc\xa0\xb1\xf3\xd4\x4d\xe8\x88\xd2\x90\xe2\xbd\x52\xf7\x72\x57\xb0\x4a\x96\x81\xd0\x1f\xbf\xf5\x6d\x10\xea\xb4\x4e\x85\xf8\xde\x56\x5\x4c\xa9\x38\x41\x8d\x4b\x0\xae\x84\x80\xc4\xb2\x15\x3f\x7e\xee\xfc\x7d\x27\xbc\xdc\x70\x6c\x2c\x78\x39\x40\x9b\xbe\x68\xe6\xdd\x5e\xc9\xf1\x2a\x2f\xa1\xe4\xa8\xa\xce\x18\xd8\x22\xa3\x4f\x1e\xe3\xe1\x11\x92\x46\xc\x99\x28\x54\x47\x5d\x7c\x3d\xb8\x5f\x6a\xad\xfe\xfd\x63\x60\x43\x59\xb\x91\x71\xcd\x48\x35\xd5\x2e\x61\x9\x65\x33\x3c\xe9\x1d\x26\x89\x1a\xf4\xb5\x9a\x7b\xa4\x37\x93\x94\x14\x8a\x6\x8f\xe0\xd1\x30\x4\xa2\xdb\x7\xc3\xd7\x8b\xaf\xdf\x82\x50\x3b\x23\x49\xfa\x3e\x42\xa6\xc6\x5b\x9e\x9d\x12\x62\x32\xb7\xed\x55\xca\x8e\xcb\xe\x45\xc2\x19\x6e\x64\x31\x86\x2b\xda\xd6\xc1\xe5\x3a\x7a\x3\x95\x5a\xf2\x21\x1\x9c\x29\xb6\xa5\x16\xec\xb9\x2\x66\xac\x1b\x44\xff\x20\x58\x6f\x83\xf0\x76" }, + { 0x543680, "\x82\x70\x6d\x44\x64\xe7\xe0\xb\x73\xf7\x12\x60\x5\x13\x9e\xe\x1a\xb8\xe1\xa0\x37\xe8\x61\xde\x55\xe3\x29\x25\x3e\xb6\x92\xcd\x6\x96\x56\x31\xa3\xe4\xcf\xe2\x7c\x23\x53\x84\xfd\xc\x62\x7f\xdd\xb0\x75\x15\x9b\xdf\xf3\x2a\x68\x87\x7\x5c\xd4\xfc\x6e\x80\x38\x5e\xd5\x3a\x50\xd0\x3b\x9\x9c\x4c\x8e\x40\xc2\x91\x58\x22\xae\xb3\x7e\xa6\x54\x90\x5a\x45\x7b\x2f\x18\xf8\x35\x3d\x48\xd\xc6\x20\x51\xfb\x3c\xf5\x2b\xa5\x32\xc3\xd7\x36\x6c\x74\xe6\x85\x1c\x88\xd3\x0\x6a\xa1\xac\xec\x97\xf1\x52\xf0\xf6\x1e\xeb\xfa\xd8\x27\x3f\xa9\x83\x9f\x86\x41\x5d\xaf\xdc\x8b\x8d\xa\x8a\x4b\x4a\xef\x99\xea\x7a\x77\x28\x21\x6b\x8\xc4\x2c\x81\xce\xd9\x14\xf2\xab\x69\x8f\xa2\x1b\xa7\xb7\xc1\x79\x72\x63\x6f\x33\x59\xaa\xb1\x42\x8c\x95\x10\x94\x76\x3\x7d\x16\x1d\xff\x24\xb9\x67\xbf\x66\x47\x4d\x9a\x4f\xc8\xbc\xd1\xed\xdb\xf4\x43\x49\x89\xbd\x1f\x5b\xb2\xc0\x98\x57\x4e\xe9\xc9\xba\x71\x39\xd6\x11\x19\x4\xa4\xfe\xb4\xcb\x26\xc7\x34\xee\x5f\xe5\xbb\x2d\xc5\x93\x46\x1\x78\xca\xad\xf\xcc\x17\xa8\xbe\x65\xda\xb5\x30\x2e\x2\xf9\x9d\xd2" }, + { 0x543848, "\x5c\x7c\xa2\x4a\x63\x12\x58\x19\xbb\xc7\x60\xfa\x18\xc3\x49\x84\xc8\x5d\x61\xa\xbc\x55\xb3\xf3\x57\xb\xc4\x5f\x56\xc9\x4c\xd0\xe\x90\x9d\x2d\x4\x54\x93\x8\x17\x52\x79\x3c\xb9\x2c\x51\x4d\xb4\xb8\x3b\xfe\x6b\x3f\xd4\x86\x38\xa7\x92\xa8\xea\x30\xcc\xa3\xd6\x8d\xdd\xeb\xbe\x82\xe5\x1a\x98\x77\x1c\xef\x7b\xe1\x41\x22\xc1\x36\x3d\xe0\x9e\x31\xd7\xe3\xc6\x59\x46\x73\xe2\xae\xcd\x1b\x42\x11\xa4\xdc\x9f\x9\xce\x35\x67\x8f\x96\x4e\x83\x5b\xf2\x10\x80\x81\x4f\x2f\x37\xed\xfc\x64\x0\x24\xf0\x99\x78\x9b\x7d\x7\xc0\x6e\xdb\x7a\x39\x76\x75\xbf\x25\x4b\xa5\xc2\x7e\x1d\xd3\x2e\xc5\x6f\x34\xb1\xee\x8b\x68\x21\x2\xab\xd1\x14\xf4\xd\x5e\x23\xf1\x1\xca\xb7\xf5\x95\xa1\x44\x9c\xc\xb5\x6a\xad\xe4\x29\x8c\xd8\xf\x7f\x3a\xec\x32\x6c\x5\x13\x5a\x70\xda\xcf\x53\xa9\xe8\xd9\x74\xa6\x27\x89\x47\x1e\x8a\xd2\xb0\x50\xa0\x9a\x94\x3\x87\x71\xbd\xb6\x62\x65\xd5\xe9\xb2\xaf\xf7\x26\xac\x66\xfb\x85\xaa\xe7\x33\x88\x20\xdf\xfd\x15\xff\x69\x1f\xcb\x3e\xf9\xe6\x16\x45\xde\x6\x40\x8e\x43\x97\x72\xf8\x48\x2b\x91\xf6\xba\x28\x6d\x2a" }, + { 0x543990, "\x43\x8a\x90\x7d\xc9\xb4\x33\x62\x2a\xc8\xdc\xcc\xe5\xd8\x8\x20\x5f\x53\x67\x18\xe0\x23\xad\xae\x93\x69\x59\x6d\x10\xd4\xef\xab\x5\xcf\xa1\xd7\x85\x97\x28\x98\x5e\x4a\xe1\xf\x13\x21\xc5\x86\x76\x22\x57\x2e\xc4\x77\xbe\x1d\x82\xb1\xd1\xf9\x6e\xb8\x81\xc6\xca\x4d\x26\x17\xe8\x12\xdd\xeb\xc0\xa\xe\xf2\x68\x9a\xf4\x61\xde\xa3\x3d\x2b\xe9\xe6\x48\x5d\x16\xa4\xb9\x45\xed\xe2\x55\x51\x4f\x99\xda\x24\x42\xea\x60\x5c\x9f\x37\x46\xbb\xb0\xb6\x7f\x3b\xe4\x8e\x73\xe7\x5b\xec\xe3\xce\xfb\x9d\xf5\x36\xa0\x6b\x40\x27\x3a\x4\xd\x15\x83\x88\x38\x63\x70\x2c\xd5\x5a\x58\x4c\x72\xac\xb3\x75\x29\x0\xd9\x35\x74\xa6\x6c\xc3\x66\x78\x56\xbc\x92\xb5\x50\x1f\xf1\x34\xa9\x1c\xcd\x3e\xb2\x8c\xbf\x44\xfc\x41\xc1\x7a\xdf\xee\x30\x65\xfa\xa2\x32\x91\x25\x80\xba\x3c\x39\x96\x54\x1\xf8\x71\x2d\x84\xa8\x6a\xfe\xaf\xa7\xf6\x4b\xc7\xd3\x8b\xf7\x3f\x8f\x9b\xfd\xbd\x19\x94\xdb\xc2\x52\x2f\x31\x2\x9\xff\xf3\x11\xb7\x95\x6\xaa\x7c\x9e\x7\x49\x4e\xd6\xa5\x1b\x1e\x1a\x64\x6f\xf0\x47\x79\x87\x7b\xc\x14\x9c\x3\x8d\xb\xcb\xd0\x7e\xd2\x89" }, + { 0x543bf8, "\x19\xf2\xd0\x35\x72\xe6\xde\xe8\x38\x97\xfe\xd4\x0\xa9\x94\x77\x50\x74\xb9\xc\x15\xce\x54\x71\x45\x65\xba\xa8\x6d\xff\xd2\x63\x86\x5b\x93\xc8\x8a\xb6\x46\x20\x73\xa3\xe2\xae\xfd\x17\x16\x9c\x7\x5\x6b\x4d\x2e\xfc\xaf\x56\xb5\x95\xd7\x42\xb8\x18\x23\xa\x34\xf0\xcd\xfa\x3c\x9d\x9e\x8e\x59\x6f\x67\x92\x68\x5f\xcc\xe3\xe0\x41\x5a\x26\xdb\xe7\x33\x1e\x53\x37\x55\xb2\xf\xdc\x28\x10\x75\xb1\x12\xf7\x6c\xda\x2b\x8c\x89\xf5\xd9\xec\xc1\xb3\xee\xdd\xa2\x4f\xef\x9f\xa1\xbf\xdf\xb7\xca\xc3\x9b\xf4\x8\xb\x83\x3f\x32\xc2\x62\x1a\x2d\x2\x69\x4\x7e\x79\x61\x4c\x44\x84\x3d\x47\x39\xd\x8f\x5c\x81\xe9\x76\x8d\xad\xc5\x80\xd8\xcf\xc6\x7d\x1c\xd6\x7a\x51\x82\xc9\x31\x4b\x6\xb4\x85\x3b\x58\xf6\x6e\xa4\x3e\xe4\xa7\x2f\x25\x7b\x30\x66\x14\xc7\x57\xc0\x64\x21\x4e\x22\x2c\x99\xbc\xbb\x52\x49\x36\x1f\x7c\xf8\xf3\x3\x90\x3a\xc4\xa0\x4a\x91\x87\xcb\xd3\x78\xfb\x11\x70\xd1\xea\xf9\x96\x9a\x9\x5e\x1\xa5\x2a\x1b\xab\xf1\xd5\x43\xed\x13\xeb\x5d\xe\x8b\xe1\x98\x48\x29\xb0\x6a\xe5\xaa\xa6\xbd\x88\x60\xac\x40\x24\xbe\x27\x7f\x1d" }, + { 0x543d08, "\x98\x9c\xb6\x1c\x91\xe3\x4d\x7\x3c\x42\xeb\x71\xda\x6c\x45\x61\x99\xd6\xb1\x14\x51\x28\x64\x3\x1e\xcf\x15\x10\xa\x75\x1b\xba\x73\x89\xc7\x69\xab\x3b\x8\x7b\x52\x82\xa9\xa0\x39\xa4\xf8\x6f\xa6\xad\x22\x9e\x50\xfc\xbf\x6\xe9\x5c\x2f\x8b\x1\x8d\xf0\x8c\xe2\xa5\xe\xe5\x4b\xf7\xaa\x66\x60\x4e\x7c\x4f\x34\xa2\xb4\x5d\xaf\xcb\x8a\xd4\xb7\x30\x88\x1d\xfe\xbb\x9a\x74\x9b\x37\xe1\x44\x3d\x38\x3a\xfb\x80\xc8\x41\x65\xc6\x4a\xd7\xf5\x70\x62\x2c\xc2\xb0\xf4\xae\x57\x21\xf6\x4\x54\x5\x2b\x83\x95\xdc\xb\x24\x94\x7f\xd0\x31\x84\x5f\xdd\xe8\x87\xce\xb8\xc5\x40\xc1\xa8\xd2\xc0\xd9\x53\xa3\x3f\x55\x6b\xa7\xf1\x1f\x13\xed\xf9\x3e\xc9\xc\x2e\x67\x96\xd1\x27\x77\xbd\x32\xde\xee\x48\xf\xc3\x76\x36\xcd\x2a\xe4\xea\xdb\x46\x6d\x25\x78\xef\x18\x11\xd8\xe7\xb5\xca\x4c\xbc\xff\xac\x5b\x97\x8e\xf2\xe0\x43\x20\x35\x93\x5e\x81\x63\x2d\x79\x68\x19\x92\x56\x12\x5a\x0\x47\xb9\xd5\xb3\x90\xf3\x1a\x33\x2\x26\xd3\x6a\x85\xcc\x7d\xa1\x23\xec\x9f\x7a\xfd\xe6\xfa\xbe\x29\xb2\x72\x7e\x49\x58\x6e\xd\x86\xc4\x16\x8f\xdf\x9\x17\x59\x9d" }, + { 0x544130, "\xc9\x1c\x8\x44\xea\x55\xb5\x3e\x8a\x54\xeb\xd3\x86\xbb\x3b\x6e\x31\x3f\x22\xbc\xe4\xfc\x81\x4b\xd7\x8c\x1e\xb7\xb4\xb\xc8\x7c\xbe\x69\x1d\x9a\xfe\x18\x2b\xde\x4f\x6c\xcb\x52\x35\xe9\xed\xad\x79\x56\xb2\x41\xe2\xf7\xdb\xff\x6b\x71\x15\xf8\x5c\xcf\x48\xa7\x3c\x92\x60\x4a\x9f\x1f\x80\x4e\x8b\x43\x90\xab\x39\xee\x5\xd9\x6a\x40\x66\xf5\xb1\x29\x65\x9b\xf1\x84\x1a\x0\x64\x5f\xe\x76\x6d\x7\xc5\x67\x5b\x4c\x73\xd1\x7a\xf\x82\x7b\x47\x85\x74\xe6\xa1\x21\x42\xd8\x8e\x95\x98\xe3\xaa\x27\xb6\xb8\x26\xc\x6\xe8\x5e\x37\xbd\x6f\xca\xc1\x14\x4d\x10\x50\x3d\xb9\xf9\x19\x97\x1b\x7e\x20\xaf\xd5\x51\x2\xa\x8f\xa3\xd6\xc3\x62\xb0\xf4\x32\x12\x94\x8d\xc0\x78\x61\xc2\xe7\x3\x30\x63\xa8\xdc\x77\x9\x89\xa0\x46\x7f\x58\xd\xac\xa2\xe5\x88\x9e\xe0\xc4\x57\x68\xf0\x36\x38\x24\x1\xec\x91\x25\xef\xfa\xd2\x13\xce\xd4\xbf\x3a\xcc\xba\x93\xf6\xfd\x5a\x45\xcd\x72\x87\x49\xa6\x2d\x53\x28\x99\x2c\xb3\x5d\xd0\x4\x34\x96\x23\x9c\xe1\xc7\x16\xf3\x2f\x17\x75\xa5\xfb\x11\xdd\x2a\xae\xa9\xda\x70\xa4\x7d\x59\xc6\xdf\xf2\x9d\x33\x83\x2e" }, + { 0x544298, "\x84\x6d\x8e\x4a\x54\x44\x86\xb1\x7b\x8f\xa3\xfe\xf2\x6f\x9b\x2a\xa\xdd\xd5\x4e\x94\xc6\x7e\x99\x46\x56\x1b\x62\xad\x9a\x1d\x5c\xb6\x11\x15\x7f\xa8\xb\x45\xe8\x18\x41\xf5\x19\x9f\x16\x31\x3e\xc7\x51\x6b\x5\xfd\x70\x10\x93\xd1\x32\x2f\xf4\x89\x64\xf7\x3b\x60\xca\x96\x4c\x90\xbd\xbf\xab\xb7\x68\xb3\xdf\x42\xd4\xa1\xcc\x21\x59\x72\xe4\xdc\x73\x9e\x79\x14\x3\xec\xda\xd7\x92\xf1\xb2\xb5\x39\x81\x4d\x5b\x1f\xf0\x67\x74\x7c\x1e\x57\x6e\xe1\xac\x30\xea\x6c\x13\x37\x3d\x98\x22\xc4\xbb\x20\x50\xc1\x27\xf6\x53\xb8\x87\xcb\xf\xd3\x48\xcd\xc3\x47\x12\x75\x2\xfa\x5d\x4f\x80\x1a\x5f\x8a\x8d\x83\x58\xa0\x52\xbe\x43\x36\x61\x8\x82\x6a\xce\xaa\xb9\xa4\xdb\x76\x3c\x8b\xc\x3a\xde\xef\x24\x2e\x4\x95\x55\xaf\xfb\xf8\xf3\xa2\xa6\x3f\x40\x66\x63\x77\xff\x65\x35\x69\x91\x85\x71\xc9\x2c\xd\xed\x97\x2b\x4b\x33\xba\x23\xf9\xe7\xc2\xc0\xe3\xeb\x5a\x9d\x78\x8c\x7a\x34\x9\x26\xd6\x5e\xe2\x1c\xc8\xb0\xa7\x28\x9c\xe6\x49\xd8\x25\x7d\xe9\x29\xe0\xd9\x6\xcf\xfc\x17\xbc\xd2\x7\xa5\xa9\xae\xc5\x38\xb4\xe5\xe\xee\x1\x2d\xd0\x0\x88" }, + { 0x546d50, "\xab\x73\xec\xa\xdc\x52\x12\x6b\xc5\x5c\x71\x5e\x44\x8f\x41\x90\x8b\xe\x83\xba\x9e\xe4\x62\x42\x20\x38\xf3\x75\xb\x1b\x17\xf5\xd4\xcb\xaa\x81\xb1\x6c\x70\xc3\x11\x76\xd1\x69\x47\xf4\x9f\xe9\x95\xf\x4c\xe3\xd8\x92\xc2\x60\x5a\xe8\xf0\xb2\x0\x7b\x18\x4e\x85\x43\x97\x16\xce\x7a\xa7\x2e\xb8\xd2\x30\x2a\x66\xc7\x5f\xdf\xdb\xd0\xb0\xbb\xe1\x96\x3e\xfe\xc0\x26\xf7\x61\xee\xcc\x48\x3d\xfb\x3c\x2b\xae\x32\x55\xb9\x36\x7e\x68\xe5\xe2\xad\xac\x2f\xb3\xf1\xa1\xc9\x1d\x29\x72\x82\x67\x79\x51\x4\x50\xed\x1\x4b\x57\x5b\x1a\xbe\x7\x8a\x4a\x56\x9a\x9b\xca\x99\x2d\xb4\x8c\xb5\xdd\x25\x1f\xa6\xf2\x35\x2c\x89\xcd\x53\x77\x7d\x1c\x19\x84\xd\x6e\xea\x4d\x88\xc1\x24\x40\xa8\x8e\xbf\xa0\x3a\x54\x22\x58\x28\x6a\x3\x94\x64\xa2\x34\xff\xd6\x93\xa3\x23\x37\x9c\x8\xa4\xc6\xfc\x6d\xb7\x45\xde\x49\x31\xa9\xe6\x9d\xd7\xfa\xe0\x4f\x3f\xfd\x78\x98\x39\x6\x91\x21\xbd\xb6\xc8\x3b\x9\xe7\xa5\x7c\xbc\xf8\xc4\xd9\xeb\xf9\x87\x7f\xda\x1e\x86\x63\x46\x5d\xd3\xc\x2\xd5\xf6\x10\x15\xcf\x14\x33\x65\x27\xaf\x59\x13\xef\x80\x5\x8d\x6f\x74" }, + { 0x544548, "\x1f\xf4\xd5\xe\x5c\x98\xdc\xdd\x53\x5a\xf0\x9c\x1b\x3b\xcb\xae\x3d\xa9\x99\x45\x97\x6b\x5b\x8\xb9\x44\xe8\x89\x6a\x92\xa0\xb3\xad\x8c\x5e\xd4\x77\x8b\x30\x72\x4e\x8f\xe0\x31\xec\xfb\x1d\xc0\xe1\xca\xab\x20\xb4\x73\x6e\xc9\xfc\x42\x35\xde\x93\x64\xaa\x85\xda\x14\xa5\x46\xa\xd0\xf6\xff\x2b\x6d\x33\x91\xa7\x59\xf1\xeb\xb2\x48\x62\xd9\x39\xf7\xfa\x75\x68\x4\xf8\xc4\x74\x6f\xe7\x41\x58\x15\x63\x55\xf5\x3\x1c\x9b\xe3\x52\xaf\xb0\x1e\x2d\xed\xe5\xa4\x5f\xd\x60\x82\xa2\x49\xbd\x7c\xcc\xb\xc3\x4b\x4a\xd8\x23\x28\x86\x51\xce\x7\x40\x7d\xd2\xe6\x4f\xa8\xfe\x9e\x65\x9a\xc1\x17\xee\x3a\x4d\x7e\xfd\x88\x12\x5\x9f\x78\x7f\xcf\x18\xea\x0\x61\xe4\x96\xdb\x6c\x26\x56\xbf\x1a\x16\x9\x80\xa3\x79\x36\xa1\x2f\x32\xf\xcd\xc5\x3c\xd6\x2c\x70\xd3\xf2\x84\xd7\xc6\xa6\x47\xf9\x34\x22\xf3\x66\x10\x38\x37\x6\x2\x54\x13\xb8\xe9\x29\xbe\x5d\x7b\xac\xb1\x67\x2a\x57\x3e\x7a\x83\x1\xb6\xc7\x9d\x94\x2e\x43\x76\x8d\x69\x8e\x24\x50\x8a\x25\xb7\x19\xd1\x87\xb5\x11\xef\xe2\xc2\xba\x21\x71\x27\x3f\x95\xdf\x81\xbb\x4c\x90\xbc\xc8\xc" }, + { 0x544700, "\x78\x6c\xc5\xc\x2d\xa7\x97\x9c\x22\x76\x3e\x81\x51\x47\x59\x71\xb1\xa2\x4a\x3c\xb5\x16\x6\x95\xb9\x1\xe6\x91\x96\x1c\x1b\xad\x61\x64\xb2\xe7\x29\x19\x52\x3b\xfa\xaf\x30\xdb\xd4\xb\xfe\x75\x1f\xbe\xcb\xf6\xea\x31\xf8\xd8\xa3\x82\x73\x1d\x99\xf0\xcc\xb6\x46\x26\xaa\x8c\x87\x90\x24\x8f\x7a\x13\xee\xd1\xa9\x5\xb3\xf7\x2\x7c\x4c\x1e\xff\xe5\x77\xab\xd6\x98\x20\x4d\xc4\x23\xf4\xa4\x85\x9a\x8e\x1a\xe\xf5\x15\x60\x38\x72\xe9\xf1\xc3\x68\xf2\x93\xd3\x2a\x48\x74\xc2\x57\xa1\x7d\x94\x37\x92\x5c\xe1\x41\x83\xd5\x65\x14\xa6\xdc\x44\x27\xef\xd7\x25\x10\x2c\x7f\x40\xa5\x55\xbd\x2b\xd\xd0\xfc\xdf\xa0\x4\x0\x62\xb4\x5a\xeb\x6b\x84\x7e\x6a\xde\xed\x66\x3\xfb\x2e\x4f\x4e\xbb\x36\x5b\x18\xe3\x69\x3f\xec\xe4\xd2\xa\x34\x63\xcf\xa8\xf9\x9b\x7b\x6f\xe8\x49\xc1\x9\x54\xf3\x50\x67\x79\xc0\x9f\x8d\x5f\x17\x70\x11\xc8\xbc\xc6\xe0\x35\x39\xc7\x6e\x21\xbf\xda\x6d\x28\xf\xdd\x33\xac\x8a\x12\xc9\xcd\xb8\x45\xae\x32\xce\xe2\x56\xfd\x42\x89\x86\xca\x4b\x3d\x5e\xba\x8b\x5d\xb0\xb7\xd9\x58\x2f\x8\x43\x3a\x53\x9e\x80\x88\x7\x9d" }, + { 0x5448a8, "\x8f\xf2\xa0\xf3\x5c\x91\xbb\xc7\xcf\x42\x8a\x62\xf4\x67\xb0\xd4\xad\x2f\xc8\x64\xe8\x6e\x40\xc5\x5d\x82\x85\xa\x24\x2a\x41\x74\x7e\xcd\xdc\x26\xea\xe7\x96\xfd\x57\x6f\x35\xa7\x29\x4a\xe4\x4e\x43\xe5\xd8\x79\xe1\xeb\x95\xc1\xa4\xed\x80\xa8\x31\x6\x44\x10\x6b\xbf\x3b\x25\x9e\x94\xee\x83\x81\x6d\x1c\x19\x78\xa5\x5\x56\x4d\x0\x93\xb2\x84\x77\xaf\x2e\x18\x7b\xd2\xf1\xd1\x23\x69\x32\x98\x73\x8c\x5b\x70\xac\x8d\x6a\xb\x30\x3e\xd3\xd9\xe6\xf6\xf0\xd\xf9\x20\x72\x50\x68\xd5\x5e\x99\xf7\xa1\xbe\x89\xca\xa9\xcc\x33\x92\x87\xc9\xb1\x9\x1f\x48\x11\xba\x8\x12\xc6\x22\x53\x71\x90\xb3\x7d\x1b\xb8\x45\x4c\xc2\x9a\x15\xdd\x7c\xb4\x55\xdb\xdf\xfc\x60\x3f\xef\x9d\x3c\x4b\x65\xc3\x13\x51\x4\xb9\xbc\x7\xd0\x97\x66\x8e\xec\x46\x54\xbd\xce\xe3\xe\x88\x8b\x16\x2c\xb5\xd6\xa3\xfe\x3a\xa2\x52\x5f\xe0\x9b\x36\x27\x3\xf5\xe9\xf8\xc\xd7\x28\xe2\xc0\xae\x86\xc4\x6c\xaa\xa6\xcb\x58\x61\x39\x1a\x7a\xab\x9f\x47\x34\x38\x2b\xde\xb6\x1\x2d\x1e\xff\x7f\x5a\x59\x4f\x76\x63\x2\x17\x21\xb7\xf\x14\x37\xfb\x49\x75\xda\x3d\xfa\x9c\x1d" }, + { 0x544a28, "\x5d\x70\xed\x8d\xab\x3e\xdb\x57\xbc\xf6\x88\xde\xd5\xa1\x80\x2e\xb0\x29\xf1\x41\x9f\x27\xc2\x5b\x1a\xd8\x61\x97\x2a\xcf\xa\x17\xf3\x18\x77\x8\x42\xbb\x2f\x94\x21\x25\x1f\xc\xb8\x3d\xa8\x87\xa7\x71\x0\xd7\x45\x36\x7a\x4a\xca\xf5\xad\x60\x9d\x83\x40\x84\x56\xe\x4\xd1\x2\x96\x73\xe6\xaf\x35\xbe\x95\xc7\x1\x81\xeb\xb5\x7f\x51\x43\x52\xaa\x50\x22\xb9\xda\x54\xea\xd\xa0\xcb\x6f\x4c\x6e\xa5\x31\xdc\xce\xd9\x7b\xb4\x7c\xb\x85\x8b\xae\x12\x2c\x4f\x34\xdd\x6b\x2d\x6a\xfe\x63\xd3\xfc\x3\x20\x6d\xf0\xe5\xc3\x19\x62\x72\x1c\xb3\xc4\x65\x9c\xee\xd6\xfd\x76\xe9\x11\xa9\xe7\x2b\x46\xbd\x78\x89\x13\x9b\xcd\x15\x99\x9a\x69\x3f\x7\x6\xcc\x37\xf4\x98\x9e\x30\x47\x6c\x3a\x23\xe4\x66\xe8\x79\x3c\x5e\x14\x91\xb7\x8c\xfb\x8f\xc0\x3b\x7d\xe0\xa4\xfa\xc6\x4d\x90\x82\x44\x5\x67\x7e\xd2\x49\x64\xc8\x74\x8e\x32\xf9\x10\xff\x5a\x48\x5c\xc9\x92\xac\x16\x68\xd0\xef\x1e\xf\x24\x58\xbf\xb2\x55\x1d\x59\xe2\x33\xb1\xa6\x86\x4e\x4b\xc1\xe1\x39\xa2\x9\xba\x75\x5f\x38\xf8\xec\xdf\x53\xb6\xe3\xc5\x26\xa3\x1b\xd4\x93\x28\x8a\xf7\xf2" }, + { 0x547670, "\x41\x55\xc1\xa3\xdf\xde\xf4\x5c\x1\x2e\xa8\xf0\x1f\x4e\x38\xf6\x9d\x24\x1a\xb3\xcc\xcf\x7e\x9a\x60\xd2\xed\xe1\x42\x92\xe\x6b\x39\x57\x8f\xad\xfa\x5f\xfd\x48\x8a\x4c\x73\x64\x7f\xf9\xbc\x77\x6a\xd0\xe7\x47\xd6\xa6\x13\xf7\xd1\xb2\x3b\x49\xbb\xbf\x19\x3e\xb9\x58\x6c\xcb\x32\x5b\xd9\x8\x2b\x86\x90\xa0\x2f\x36\xe8\xbe\x6f\xa\x44\xfb\x8d\xeb\x9f\x4\x75\x82\x72\xb6\xaf\x3\x2c\xfe\xae\xf8\x27\x4b\xf5\xcd\xb0\x4a\x35\x3d\x5d\x2\x7c\x10\xba\x2d\x76\x74\x4d\x21\x65\xdd\x98\x17\xca\x33\xd\x88\xc2\x96\xdb\x84\x53\x1e\x80\x1b\x7b\x5e\xb8\xb4\x3f\xd8\x1d\x56\x99\xec\x52\xc7\x70\xc3\x7a\xc\x34\x25\x5\xa5\xda\x16\x26\x54\xf3\xe0\xd4\x85\xbd\x9c\x68\xac\x8e\xe6\xd3\x87\xa2\x8b\xa1\x15\xb5\x78\xb\x0\x66\xea\x50\x79\x59\xaa\x22\x2a\x29\xc4\x7\x12\xee\x69\xf\xf2\x3c\xc6\x7d\x28\x9e\x6d\xc9\xe3\x20\xa9\x40\x94\x63\x71\x46\xff\x23\x4f\x14\xd5\xc5\xa7\xf1\x31\x67\x95\xe4\x93\x89\x11\x6\x91\xef\x8c\x6e\x62\xab\x51\x9\x5a\xdc\x83\x1c\xb1\xe5\xe2\x9b\xd7\x61\xb7\xc8\x3a\x43\xc0\xe9\x97\x81\x18\xce\x45\x30\xfc\xa4\x37" }, + { 0x5480c8, "\xa0\xee\x48\xc3\x70\x1d\x44\x7f\xad\x27\x74\x5c\xe0\x71\x7a\x1a\x5a\x6c\x9d\xef\x28\x88\xa4\x89\xed\x75\x67\x22\x79\xd1\x6d\x1\xc6\x25\x7c\x31\x43\xa2\x66\x10\xac\x4b\x9\x1b\xcc\x3c\x32\xb\x8e\xe4\x60\x73\xf2\x8f\xfb\x47\x9a\x4e\xc0\x55\xd5\x91\x46\x59\xfa\x7\xa3\xbd\x78\xb7\xf\xec\xcd\xa7\xc8\xd4\xe5\x64\x12\x8d\xbb\x7b\xf6\x1e\x9c\xa9\xcb\xbf\x30\x11\x2a\x83\x37\x3a\xc4\x87\x5b\xb9\x6f\xf5\xae\x40\x50\x39\x7e\xb2\xe3\x5\x8c\xf4\xff\x92\x5e\xeb\x57\x77\xb5\x96\xe2\xfd\xba\xb1\x29\x6b\x4c\x51\xf0\x81\x0\x13\xf8\x14\x65\xf7\x3e\xc1\xa1\x5d\x2d\xaf\x69\x35\x3f\xd3\x24\xdf\x1c\x23\xe1\xfe\xf3\xdd\x16\xe6\xd\xb8\xa5\x9b\x9e\x63\x8\x8b\xa\x2f\xf9\x2e\x6e\xb0\x94\xb4\x80\xd8\x4f\x4\x56\xb6\x97\x21\xcf\x93\x3d\x26\x7d\x2\xaa\xd0\x76\xe8\xde\x17\xdb\x86\xb3\xca\xd9\x84\x99\x4d\xc5\xea\x3b\xdc\xab\xbe\x18\xc7\x2c\x3\x6\x68\x4a\x2b\xc9\x62\x95\x82\x85\x33\xf1\x42\xe7\x15\x20\xce\xd2\x58\x49\x98\x45\x41\x5f\xd6\x34\xa8\xda\x8a\x54\x38\xfc\x1f\x19\xd7\xc2\xe9\x61\xa6\xc\x72\x52\x9f\x6a\xbc\xe\x36\x53\x90" }, + { 0x546af0, "\x15\x4f\x74\xa6\x26\xb3\xce\x55\x94\x77\xb4\x93\xba\xbc\x7d\xd4\xec\x2a\x79\xa2\x70\xbf\x14\x4c\x35\x4\xd7\x85\x6c\x0\x11\xf6\x69\xb8\x2\xa7\xc4\x6a\x58\x92\x39\x25\xe6\x9d\xa5\xa\xc7\xaa\xda\x36\xb5\x2d\xeb\x86\xa0\x12\x99\xb1\x9c\x34\xcc\xb7\x59\x62\xf0\xcd\x9f\x17\x8a\xca\xc3\xa3\x7\xf3\x57\x41\xe5\x88\xfb\x97\xde\xd1\x1\x24\x43\x68\x90\xa8\x4b\x72\xee\x80\xfa\x52\xf2\xe7\xf\x6f\x22\x5f\x37\x2c\x98\x73\xb2\x3a\xf8\xc9\xd0\x1c\x87\x66\xab\x5d\xf9\x9b\xb0\x32\x61\xa1\xe0\x29\x9\x31\x45\x2f\x2b\x30\x8d\x5b\x5e\xa4\xc5\x3\x51\x16\x1a\xe4\x4a\xc\x18\x1b\x6\x4d\x7c\x82\xef\x19\xb\x8c\x3f\xb9\x13\x53\xd2\x6d\xb6\x81\x64\xc1\xdd\x95\xdb\xc2\xe8\x46\x60\x8\xe1\xaf\x50\x1f\x1d\xea\xd5\xdc\xcb\xd\xdf\x83\x49\x8e\x2e\x44\x67\xff\x8f\x76\x63\xf7\xe9\x3e\x10\x47\x1e\xd6\x21\xf1\xa9\xac\x33\x89\x7b\x23\xbb\xf4\x20\xd9\xfd\xcf\x42\xc0\x3c\xc6\xe\x40\x5\x7e\x56\x7a\x38\x28\xf5\x48\xe2\x4e\x71\xbd\xc8\x5c\xed\x6e\x96\xae\x8b\x9e\xfc\x3d\x9a\x78\x5a\xfe\x91\xad\x65\xbe\x27\x84\x3b\x6b\xe3\x7f\x54\xd8\xd3\x75" }, + { 0x546bf0, "\xc5\xb4\xfe\x62\x85\x73\x6d\xa3\x55\x60\x8\x7\xa4\x84\x2f\xcd\xaa\x5a\x36\xd6\x8a\xc\x89\x9c\xa6\x43\xc2\x13\xec\x9\x2c\x16\x52\x63\x81\xf\xed\x1b\x42\xf4\x66\xb6\xfc\xdb\xe7\x1e\xd8\xd5\x29\x5e\xe1\x57\xb0\xb5\xb\x70\xe8\x1\x3b\xde\xd4\x3\x1c\xbf\x5b\x27\x24\x34\xd\xbb\x5d\x39\xbc\xf8\x5c\x4\x3d\x47\x2\xe5\xf2\xdf\xe6\xc4\x95\x7a\x77\x3c\xa0\xff\x6b\x32\x38\x8b\x1a\x7e\x14\x26\x67\xc0\x58\x50\x64\x35\x18\xe2\xd7\x3e\x74\x2d\x41\xb7\x8e\x17\x11\xca\xc7\xd1\xdd\xcb\xd0\x90\xee\xeb\x72\x4e\x53\x80\x68\x4f\x56\xbd\x86\x76\xb2\x6f\x3f\x10\xe4\xba\xfb\x44\xc6\x5\x75\x48\x30\x9a\x19\x8d\x4d\xbe\x7f\xa1\xfd\xab\x9b\xa8\xaf\xf3\x9f\x4c\xad\xef\x8f\x2b\xf0\x31\xe3\x0\x21\xa\x2a\xf5\xc9\x23\xc8\x22\x79\x12\x78\xae\xac\x9d\x3a\x40\xf1\x93\x7b\xa9\x54\x20\x88\xe9\x45\x92\xea\x99\x7d\x6c\xd2\xcf\x6e\xc3\x82\xda\xb1\xd9\xe\x6\x94\x8c\x96\x46\x5f\xd3\x7c\x98\x9e\xb9\xf7\x69\x87\xce\x6a\x83\x28\xa5\xfa\xcc\x4a\x59\xa2\x1d\x61\xf9\x65\x37\xb3\x25\xa7\x91\x71\x1f\xf6\x2e\xb8\xc1\x4b\xdc\x15\x33\x97\x51\xe0\x49" }, + { 0x544d20, "\xaf\x3a\xa1\x82\xc\x76\x4d\xed\x6a\x13\x70\xc9\xc0\x32\x7a\x63\xd\x6f\xca\xb5\xdd\x69\x8b\x83\x59\x62\x2b\x98\xa9\x60\x51\x34\xa0\x75\x8f\xef\x1e\x44\xab\x54\x9f\xbc\x4\xb7\xf1\x9a\x68\xf2\x28\x3f\xfd\x87\xfc\xb2\x10\x55\x11\x17\x47\x26\x48\x52\x4f\x25\xaa\x5c\x6c\x1c\x39\x8\xa6\x1d\xb3\xfa\xd4\xe7\x37\xa5\x8c\x22\x58\x24\x8d\x23\xad\x31\xe5\xbd\x1a\x53\xa2\x79\x71\xbf\x7\x67\xc7\xcd\x3e\xdf\x14\x21\x7b\x6b\xea\x4c\x49\x9b\x1b\xe4\x7f\xff\x29\x4b\x5d\xe9\xa8\x65\x77\xf3\xa\x6e\xd1\xe2\x89\x96\x38\xf4\x80\x3c\x6d\x2e\xc5\xc1\xf7\x92\x2c\x1f\x20\x41\x36\x2d\x12\x42\x78\x43\xce\xcf\xf\x7d\x90\x0\x5a\x30\xc6\x81\xd9\xf8\x4e\xeb\xd0\xbb\xa4\xae\xd2\xde\xe8\x5f\x9d\xd8\x27\xe6\x19\x9c\xec\x2\x74\x35\xba\x84\xe1\xb\x3b\x5\xfe\x4a\xfb\xb0\xcb\x97\xf0\x64\x86\x99\x91\x3\xbe\x45\xa3\xda\xb6\x95\x2f\xd6\xf6\xc8\x73\x33\x56\xf5\x15\xa7\xc3\x18\xd5\x8e\x93\xee\xc2\x50\xf9\x46\x7c\x6\xe3\xdc\xd7\xb4\xd3\xcc\xdb\xb9\xb1\x57\x94\x66\x85\xb8\x5b\x3d\x72\xe\x88\x40\x7e\x9\x1\x5e\x9e\x2a\x16\x61\xe0\xac\xc4\x8a" }, + { 0x544e20, "\xd7\x3b\xe0\x11\x7a\x3\xca\xc9\xdb\x34\x4a\xc8\x24\x45\x7b\xc\x61\xf9\xcb\xc4\xad\x3d\xea\xaf\x7e\x63\x8f\x66\x2a\x21\x2c\x94\xb5\x72\xb2\xc0\x30\x77\x2f\x51\x91\x6\xf8\x25\x49\x1c\x74\xff\xdf\xbd\x71\x80\x81\x2b\xe1\x0\x4d\xda\x67\x35\x29\xf3\xc1\x89\x46\x32\x7c\x69\x3e\x1b\xf0\xab\x42\x9d\x26\xc5\x20\xb8\x6e\x12\x90\xd\xa\x5f\x23\xf5\xb9\x5e\x8b\x2\xe6\xe3\xf\x6c\x13\x65\xc3\x1f\xd9\x92\xde\x16\xc7\xd8\x75\x2d\x76\x3f\x6b\xc6\x70\xa1\xee\xa0\xed\x47\x4b\xef\xe\xbb\x9c\x9e\x31\x55\x6d\x8c\x79\x60\xa5\x2e\xe9\x37\x83\x40\xcd\x36\x84\xfd\xce\xb6\x57\xa3\x14\xf2\xeb\xdc\x4c\x28\xcc\x15\xd2\x4f\x1a\x5b\x1\x6a\x50\xcf\x8d\xfe\xb0\xbe\x5d\x44\xb\x59\xd5\xd3\x33\x3c\x5a\x27\x6f\x58\xa9\x96\xb7\xd1\xf7\x5c\x68\x8e\x19\x88\x86\xa6\x1e\x7\xa7\x53\xa2\x4\x10\x54\x7f\xf1\xbf\xbc\x3a\xac\x62\x4e\x8\x99\xd0\xe4\x48\x5\xe5\xfc\x98\x9\xf6\xa4\x1d\x9b\xa8\x56\xdd\x41\xb4\xb1\xfa\x97\x52\x9a\xe2\xfb\x95\x85\xc2\x38\xd6\x8a\xaa\x39\x43\xba\x87\xe8\xf4\x22\xae\x17\xd4\x93\x82\x73\x18\xec\x78\x64\x9f\xb3\x7d\xe7" }, + { 0x546fd8, "\x40\x2d\xc5\x23\xcb\xf8\x99\x7b\x3b\xae\x91\xa6\xb8\x0\xb0\xe8\x50\x9d\xd\xaf\xd8\x1b\xd1\xe9\x9c\xc0\xc\xcc\x10\xc3\x53\xe0\xd0\x8a\x9\x2b\xb1\x47\x2\xb9\xce\xc4\x3c\xa5\x36\x1\x86\x94\x7f\x72\x7e\x2e\x17\x78\x62\xc8\x3a\x6\xd7\x32\x64\xea\xbb\x18\x8c\x1d\x66\xa9\x58\x8e\x84\x7c\x75\xcd\x45\xc9\x9b\xbf\x4d\x76\x1e\x1c\x49\x44\x3d\xef\x39\xa2\x3\x37\xdb\xbd\x5e\xbe\xf2\x6d\x67\x6c\xd5\x6b\xf\xf5\xd9\x33\x54\x2a\x82\xf6\xbc\xfd\xda\x13\x92\x68\x16\xed\x70\x9f\x5d\xeb\xec\xfc\xfb\xa3\x6e\x90\x5b\x98\x5f\x8f\xe4\xe\x15\xf4\xb5\x3f\x63\x35\x59\x85\x8d\x9e\x5\xb\xa8\x65\x60\xad\x8b\xb6\x8\x41\x12\x80\x1f\x93\xe5\x7d\x88\xa4\x4b\x89\x6f\x25\xdd\xe2\x30\x57\xf0\xac\xe1\x28\xa7\x97\xde\xee\x6a\xc1\xf7\xc7\x55\xd4\x61\x24\x51\xf9\xca\x2f\xe7\x4c\xb7\x4\xe6\x96\xe3\x11\xdf\x43\xcf\x42\xab\xb2\x83\x79\xc6\x52\xdc\xaa\xb4\x7a\x34\x4e\x26\x20\x5c\x19\xa1\xd6\xba\x48\x56\x2c\x9a\xf1\x4a\x46\x74\x5a\x95\x77\xf3\xb3\x71\x27\xd2\x73\xfa\x87\x7\xa\xd3\xa0\x29\x3e\x81\xff\x1a\x38\xc2\xfe\x14\x69\x21\x22\x4f\x31" }, + { 0x5470d8, "\x13\x32\xf2\xee\xb5\x4b\x96\xd\x64\xb2\xc\xb0\x2f\xc0\x73\x53\xbe\x4d\x4c\xbc\x6f\xd8\x95\x4f\xe0\x6b\x24\x39\x63\xbb\x2b\xc7\xb3\xf4\xf7\x86\x7c\xa6\x23\x2c\x70\x52\xbd\x8b\x48\x80\x98\xb8\xf0\x56\xed\x91\x35\x65\xc3\xd3\x62\x60\xb9\x88\x31\xe1\x37\x1b\xac\x6e\x9e\x55\x1\xea\x4a\x42\xe8\xd9\x2a\x99\x61\x3f\xe2\x68\x58\xcd\x6\xa5\xa7\xd1\x1a\xae\x20\xca\x81\x5\xc5\x3e\xad\x66\x7b\xdc\x12\xa0\xa3\x74\x0\xa8\xb\x19\xfd\xb7\xdb\xb4\xcc\x9d\x3d\xf3\x5f\x5b\x72\xaf\x87\x92\x44\xff\xd4\xc8\x76\x8e\x5d\xd5\x3b\x22\xa9\x36\x47\xf9\x18\x15\x25\x4\x83\xc9\xda\xd7\x4e\xe5\xe4\xfe\x33\xd0\xa2\x5a\x7f\xc1\xf\x1d\x2e\x8a\x8f\x50\x27\x9f\x57\x1e\xeb\x6d\xf6\x54\x59\x49\x9c\x7e\xcf\x28\x93\x45\xec\xab\xaa\xbf\xa\xd6\x78\x41\x7d\x77\x26\x46\xb6\x2\xe3\x3a\xfb\xe\x8\xcb\x51\x82\x9a\x40\x84\x9\x5e\xfc\x7\xef\x21\x14\x2d\x71\xf5\x67\x85\x29\xb1\x30\x7a\xde\x90\x1f\x3\xf1\x3c\x75\xe6\x79\x11\x94\xc2\x16\xba\x97\xa4\x10\xdd\x1c\x69\xc6\xa1\x8d\x5c\x6a\xf8\xe9\x43\x34\x6c\x17\x8c\xfa\xc4\x38\x89\xce\x9b\xdf\xd2\xe7" }, + { 0x546970, "\xe1\x9a\x3f\x1a\x1e\x5d\x57\x52\x34\xd5\x1d\x93\x35\x76\x92\xf7\xea\xb9\x5c\x3a\xe3\x1f\x70\x9b\xc\xf\xd2\x8e\x30\x4c\x4f\xb0\xb7\x8b\xfb\xaf\xd3\x58\x8\x38\x36\xa5\x0\x2c\x45\x3e\xa7\x4a\x32\x37\x2b\x56\xfe\x90\x51\xc1\x7\x6e\x23\x3b\xbc\x95\x15\x86\x16\x5a\xd0\x2e\x4e\xdd\xd8\xe5\x6b\x7d\xfa\x75\x18\x29\x7c\x48\x68\xb3\xf1\xd4\x8d\x63\x20\xba\x98\xad\xa9\x6\xfc\xb5\x84\x67\xc4\x4d\x9c\x7b\x17\xb6\xfd\x91\xcb\xe\xbb\x60\xe9\x99\x49\x83\x5\x8a\xdc\x66\x24\x21\xcc\x54\x28\x78\xd7\x7f\x2d\xcf\xca\x97\xed\x5b\xc5\x59\x94\xbd\x47\x40\x25\xde\x6d\x3d\xe4\x44\xe2\x6c\x1b\xce\x22\xb\x43\xc0\x7a\x2a\x73\x53\x31\x39\x11\x14\x3\xe7\xb2\xef\x2f\x77\x74\x88\xb1\x8c\x4\x72\x7e\x10\xee\xa4\xf5\xf8\xb4\x85\xe0\x41\x87\x9e\xeb\xc9\x50\x96\xd6\x13\x9\x26\x12\x80\x5f\xa8\x3c\xf3\x89\x46\x4b\xf4\xae\x27\xc8\xc7\x61\x82\xb8\xa3\xa1\xe6\x69\x5e\x2\xec\xab\xc3\xd1\xda\xbe\x79\xe8\x9d\xd9\xaa\xdf\xf6\xa0\x62\x8f\xac\x6f\xa6\x71\x81\xa2\xf0\x33\xa\x1\xf2\xc6\xdb\xf9\xcd\xff\x9f\xd\xc2\x64\x65\x55\x42\x1c\x19\x6a\xbf" }, + { 0x5467d8, "\xf0\x36\x69\x25\x6b\x37\xee\x56\x5d\x85\xc4\x8b\xc6\x2\x62\xe4\x70\x48\x41\x91\x9d\x38\xff\x55\xfa\x3c\x89\xe6\x73\x30\xa8\x2d\x59\x3e\xec\xf1\x2b\xc9\x9e\x87\x84\x78\x9\x3b\xcd\xb0\xe2\xd9\x31\xf\xfc\x82\xc0\xce\x50\xe3\xbc\x79\x3\x67\x72\x9b\x32\xc1\x7a\xd\xa3\x65\xf2\xd6\x97\x6d\x93\x6f\x83\xab\x11\x74\xc3\xbf\x1f\x6c\xb1\xd8\x64\xb5\x19\xdc\x2c\xac\xe\x8\xb8\x76\xcf\x26\xbb\x6e\x51\x99\xa4\x9c\x53\x4\x88\x3d\xa1\xaf\x9f\x47\x7e\xe5\xd1\x52\xf7\x18\xd7\x15\xf3\x95\xd5\x1a\x86\x68\x8f\xba\x77\xc2\xf9\x5a\x90\x46\xe0\x61\x60\x2a\xef\xdf\x12\x1d\x5c\x7\x21\x34\x9a\xb3\x57\xb4\xe7\x1c\x4c\x35\xa2\xf5\x7b\x5b\x1\x8d\xda\x42\x71\xad\xc8\xf4\x13\x4d\x63\xb6\xfb\xbd\xed\x4f\x8e\x75\x16\x20\x28\xd4\x3a\x8a\xdd\x49\x14\x10\xa0\xde\x4e\x96\xdb\xb\x40\x7f\xcb\x80\x4b\xc\x5\x1e\x24\xfd\x44\x5e\xc7\x17\xae\x7c\xb2\x22\xd3\x92\x8c\x98\x81\x0\xb9\x27\xa7\x58\xb7\xa5\x29\x54\x4a\x6\x45\x1b\x6a\x3f\x23\xf8\xe9\xaa\xca\x66\xc5\x2e\x43\xcc\xfe\xd2\x33\x2f\xa9\xe1\xe8\x7d\x5f\xa\xbe\xf6\xd0\xea\x94\xeb\xa6\x39" }, + { 0x546690, "\x34\xa1\x39\xaf\x83\xdd\x8b\xb9\xe3\xd3\x61\x77\xc\x52\x66\x5d\x31\x4\x9d\xb7\x6e\xeb\xb\x9b\x19\x2a\xb3\x7c\xe6\x53\xfc\x48\x1d\x68\x69\xed\xf8\xcb\xf1\x17\xb8\x84\xc5\x9c\x6c\x49\x97\x78\xa6\x18\xf7\xdc\x7a\x2d\x65\xd\x26\x56\xb4\xa2\x3\x93\xe9\x1c\x82\x14\x6f\xee\xd2\x74\xac\x62\xc0\x7b\x8f\xd7\x20\x35\x21\xe1\xa0\xcf\xcc\xc3\x67\x80\x55\xfe\x70\x4e\x58\xc8\x27\x0\x36\x5\xe0\x1f\x6d\x51\xd8\x25\x89\x2\x2c\x85\xde\x76\x81\x4d\x11\x9e\x2b\xe5\xcd\xda\x3b\xbd\x92\xc4\xdb\xf6\x46\xbb\xba\x75\xb6\x71\x7e\x79\x1b\xfa\xea\x64\xc1\xa9\x8c\x59\x5f\xe7\x90\x63\xb5\x5c\x98\x6b\x9f\xae\x5e\x7d\xad\xc6\x7f\x8d\x15\x6\xc2\x38\x43\x5b\x73\xa3\x96\xec\x3e\xe2\x99\x94\x1\x54\xca\xf9\x8\x24\xd0\x4f\xef\xf\x3a\x13\x72\xe8\xe4\xb0\x3d\xfd\x4c\x44\x5a\xf0\x60\xa5\xa7\x40\x88\x8a\xf4\xaa\x9\x4b\xf2\xd4\xbc\x12\x1e\x47\x41\x6a\x86\x45\xd6\x2f\x37\x50\xbe\xab\x91\xf3\x22\x8e\x95\xb1\x28\x87\xb2\x7\x3f\xdf\x16\xa4\x4a\x57\x33\x30\x23\xbf\x3c\xd9\x42\xc7\xff\xa\xf5\x29\xd1\x2e\x1a\x32\xfb\x9a\xc9\xe\xce\xa8\xd5\x10" }, + { 0x546548, "\xab\x48\xd1\x4b\xbe\x95\x99\x9\x10\x36\x91\xe\x4c\xe7\x14\xb\x96\x16\xb4\xdf\x75\x20\x80\x7f\x74\xb3\x47\x12\xf6\xb2\x4\xca\x44\xe8\x42\x9c\xd5\x86\x30\xe0\x1d\x1e\x28\xe2\x81\xde\x2a\xa2\x45\xf0\xaa\xcc\x5f\xe6\x63\x64\xd9\x1f\x70\x49\xe1\x85\x7c\xf2\xc5\x88\x9e\xb7\xba\x9b\x17\x6e\x82\xd3\x69\x3d\x6\x1\x68\x11\x71\xf7\xd8\x24\xb6\xc7\x67\x50\x7e\x9f\xfc\xe4\xf5\xbb\x55\x7\xeb\x3c\x13\xc\x4d\xd4\x25\x23\x56\xa0\x6d\x5e\xc8\x84\x61\x8f\xdc\x2\xbd\xbc\x6f\xcd\xf3\x6c\x92\xfd\x3e\x21\xed\x1c\x6b\x79\x59\xec\x41\xac\x2c\x58\x8d\x89\x35\xaf\xda\xb0\xd6\x22\x5d\xc3\xd0\xa\x1a\x2e\x43\xe9\x7d\x52\x5c\x34\xa9\xd7\x60\xb9\x53\xee\x39\x3b\xc9\xe3\xae\xdd\x4e\x57\x8e\xf8\x19\x46\xa6\x3f\xb8\x90\x8a\xc1\x33\x4f\xea\xff\x51\x2f\x66\xc6\xf\xef\xa7\x7a\x9a\xdb\x94\xd2\xfa\xa5\xd\x8c\x18\x77\xad\x87\xc0\x54\x32\x31\xa3\x38\x62\x37\xf4\x93\x98\xf9\x83\x40\xce\x15\x1b\x3a\xfe\x3\xfb\x6a\x8b\x27\xf1\x9d\x73\x5b\x65\xe5\x7b\xb5\x4a\x8\xc2\x72\xbf\xa8\xc4\x76\x29\x26\xa1\x2b\xb1\xa4\x0\x78\xcf\xcb\x5a\x5\x2d\x97" }, + { 0x545c58, "\x6\x15\x2e\xa6\xed\x8\xdb\x7b\x2a\x85\xcb\x50\x31\xf5\xb4\x63\x53\xc2\x6e\x91\x92\xe6\xaf\x68\x41\x61\x74\xf3\xbb\x23\xe4\x6a\xf8\xbc\xfe\xee\x93\x90\x6f\x5f\x8a\xf9\x81\xae\xe7\xad\xd0\x59\xcd\x57\x5b\xa5\xbe\x30\xc8\x39\x79\x35\x64\x3a\x6c\x73\x29\x13\x1c\x3c\x2d\xfa\x32\xa7\x71\xe5\x6d\x4d\xa1\x99\x51\x1d\xea\xaa\x67\x96\xe8\x98\xe0\x58\x5d\x8f\x49\x9e\x20\xb\xc6\xeb\xb5\xe\x7a\x4\xc5\x34\xc1\x1b\x77\xf6\xb3\x18\xd4\x47\x9a\x87\xca\x3d\x37\x21\x5\x3\xf2\x83\xa9\xce\x8c\xac\xd3\x9\x8d\xba\xe3\xd8\x4f\x24\x72\x36\x86\xb2\xcc\x69\xfc\x75\x9b\xd5\xd\x4c\xc3\x56\x25\x9c\x5e\x6b\x2b\xb1\x22\x60\x7\xd1\xdc\x8e\xf0\x4b\xb0\x97\x1e\x88\x27\x7c\xd7\xa0\xdf\x43\x1f\x5a\x54\xcf\xa\xa3\xd6\x78\x28\x66\x26\x89\xbd\xb6\x94\xc9\x2c\x95\x1a\x5c\xd2\xb7\xb9\x48\x17\x44\x70\xc7\x80\x52\x40\x11\xc4\x4e\xab\xda\xf\x45\x7e\x3e\x7f\xde\xbf\x1\xa2\x7d\xc\x55\xc0\x84\xa8\x65\x3b\x46\x2f\x62\x82\xef\x33\x76\x10\x14\xe2\x9f\x38\xf4\x42\xe1\xa4\xfb\xff\xfd\xec\x3f\xf1\xd9\xe9\x4a\x8b\xdd\x2\x9d\xb8\x0\x19\x16\x12\xf7" }, + { 0x545aa0, "\x93\x1a\x38\x7a\xa7\x8c\x82\x3b\x40\x4d\x17\x1\x33\x4b\x7c\xe9\x7f\x41\xcc\x62\xc4\xf2\x70\x2f\x2\xe8\x86\x81\xce\xfe\xab\xdc\xad\x30\x4\x6e\x55\xff\x59\xbd\xf5\x23\x2d\x5b\x98\x13\x52\xc7\x7e\xaa\x1e\x4c\xfb\x95\xa8\xf0\x47\xf6\xea\xa2\x1c\xfa\x1d\xe3\xcf\xd9\x12\x57\xc0\x49\x0\xbb\x68\x7d\x3d\x3\xfc\xc1\xd7\xd2\x3c\x91\xae\xa5\xbe\xb2\x51\x69\xd8\xee\xb5\xdd\xf4\x6b\xd3\x4a\x65\x8b\xaf\xde\xe2\x36\x66\xd4\xa9\xc5\x94\x46\xc3\x6\xd0\x73\x87\x27\x9a\xb6\xdb\xb3\xa6\xe0\xe6\xc9\xd\x28\x21\x60\x97\xf8\x71\x2a\x2e\x3a\xfd\xcd\x67\x63\x72\x54\x9f\xf7\x9c\xef\x9\xca\x32\x5\x37\xac\x8a\x96\xe7\x7b\x2c\x4e\xa3\x29\xdf\x31\x84\x20\x8f\xc2\x44\xf\xb7\x39\x76\x6d\x5e\xd6\xbc\x74\x9e\x5f\x78\x64\x99\x92\x6f\x42\x43\xf3\x77\x6c\x79\xb1\xa\xbf\xa1\x9b\xf1\x15\x34\xeb\x88\x50\xc\xe4\xb4\xec\x19\x7\x18\xba\x75\x6a\x48\x22\x3f\x8d\xb\x8e\x89\x5d\xc8\x11\xc6\x61\xda\x5a\xd1\xa4\x8\x10\xf9\xb8\xe\x85\x9d\x45\x56\xe1\x26\xd5\xcb\x1b\x5c\x24\x2b\x25\xb0\x83\x16\x53\xb9\x90\x80\xed\x35\x3e\x1f\x4f\x58\xe5\xa0\x14" }, + { 0x545d78, "\x28\x45\x39\x3a\x7e\x23\xae\x4c\xe5\x44\x3\x6c\x9a\xe3\xf8\x6d\x29\x79\x12\x48\xaf\x84\x19\x33\xf2\x94\x40\x9\x8\x56\x64\xa\x1\x5e\x34\x30\x95\xd5\x5d\x2b\x7b\xa1\xcd\x75\xf6\x61\xb4\xc6\x99\xe9\x1c\xde\x59\xb6\xe\xd3\xe7\xa9\xce\x5b\x15\xc8\xe8\xc5\x71\x42\x26\xa8\xb\x68\x3c\x70\x87\xc0\x5c\x20\xa3\x1d\xed\xd2\x91\xbc\x4a\x53\xfc\xb1\xbf\xc9\x37\x74\xb3\x69\x36\x5a\x32\x6e\xa6\xc4\x96\x10\x6b\x82\xbb\xe0\x93\x51\x3b\xe2\xd9\x98\x88\x47\x57\x63\xba\x1e\x4d\x8d\xb0\xa0\x22\x9d\xff\x3f\xab\x2\x9e\x41\xf\xf9\x8a\x76\xfb\x6\x6f\x14\xcb\x24\x90\xaa\xb8\xdc\x81\xfe\xb5\x83\x2c\x4\xc7\x55\xfa\xa2\xee\xc\xef\xbd\x5\x5f\x2f\x2e\xa4\xc2\x11\xf4\xe4\xf0\xcc\xf5\x4f\x92\x43\x4b\x54\xca\x3d\x8f\xb9\x66\x3e\x7a\x13\x46\xdf\xad\x7d\x72\xd1\x65\xdb\x35\xd6\x17\x31\xa5\xf7\x97\xc3\x1f\x73\x38\xe6\x89\x0\x50\xa7\x2a\x8c\xea\xec\x77\xc1\xeb\x8e\x67\xd7\xd0\xb2\x9c\x21\x7\xfd\xd\xbe\x85\x78\xcf\x2d\x86\xf3\x1a\x27\x6a\x80\xac\xf1\xd8\x58\x9f\xb7\x18\x25\xd4\x62\x4e\x1b\xe1\x49\x8b\x52\x7c\x60\xdd\xda\x16\x7f\x9b" }, + { 0x545e78, "\xa2\xb4\xa\xde\x9f\x7f\x85\x5d\xea\x41\x31\x7a\xae\x71\xd0\x1d\x56\x14\xd9\x61\xc7\x59\x69\xbf\x47\xe7\x8c\x29\xd7\xf4\x86\xb5\x2\x93\x22\x8f\x60\x11\xc1\x95\x4f\x3d\x6b\xcc\xd2\xd\x3f\x3a\xdb\xf9\xf0\x8\xb9\x4e\xb\x65\x43\x5a\xce\x4d\x91\x49\x2e\x5b\x99\x8d\xd5\x3e\xe1\x4a\x9c\x38\x78\x77\x7d\xbe\x4b\xfc\x3\x35\x33\x5\xe9\x45\xb6\x1c\xf\x2d\xaf\x53\x57\x54\xc0\xab\xfd\xa9\xcd\x12\x81\x39\x70\xc3\xff\x94\x0\x98\x96\xf5\x79\x20\x6d\xf7\x7e\x88\xf3\x5f\x75\x73\x15\xc5\xb2\x52\xda\x9e\xa5\xc4\x36\x25\xc\x7c\x42\xee\x1e\x6a\x66\x8a\x8e\xbc\xd6\x44\x74\xe8\x10\xa0\x5c\x26\x1\x68\xd4\xa7\xe3\xbd\x3c\xbb\x28\x24\xdd\xf1\x18\x27\x30\x6f\x4c\xdf\x9a\x8b\xa1\x46\xe4\xcf\x4\x67\xd1\xac\xdc\x76\xf6\x34\xa4\x80\x89\xe0\xa6\x55\x19\xb3\xad\x3b\xfe\x5e\xc8\x7\x6\x87\xd3\xfb\x6c\xe2\xf8\x6e\x48\xd8\x2b\xef\x2a\xe6\xc9\x63\xa8\x62\xb0\x2f\xc2\x16\x82\xec\x90\x1b\x23\x51\x97\x9\xf2\x7b\xcb\xe\xb1\xaa\xc6\x9d\xfa\x64\xed\xe5\x32\x50\x92\x72\xb8\x9b\x17\x58\x2c\x83\xeb\x84\x13\x40\x1a\x37\xb7\xca\xba\x21\xa3\x1f" }, + { 0x545ff8, "\xd3\x15\xec\xfd\x78\x34\xa2\x0\xbb\x4f\x7e\x3e\x16\x5e\x2f\x2e\x58\x3c\xd9\xcc\x49\x74\x1\xc\x84\xab\xfe\x2c\x93\xc7\x19\xea\x92\x36\x37\x47\x8c\xc6\x2d\x33\x6f\xf9\x5a\xd5\x56\xf\xef\xd1\xbf\xfb\xf6\x11\x7a\xbe\x6c\x57\xd2\x68\x6\xb2\x86\xf4\x89\x4e\x5d\xa\x9f\xb9\x42\x3a\x72\x65\xce\x7\xa8\xd6\x3b\x69\x64\xcf\x9e\x55\x4a\xe7\x1c\x1b\x67\x25\x7f\x38\x1e\x17\xeb\x88\xa3\x26\xa4\x8d\x87\xb7\xbc\x32\xad\xaf\x8\xde\x5f\x3f\xe8\xa9\xf8\x4b\xa5\x61\x79\xc3\x41\xe4\x9c\x83\x3\x21\x75\xb6\x54\xdd\x43\x91\x27\xfa\x66\xd4\x53\xb\x9d\xf1\x5b\x94\x39\x8e\xaa\xc8\x20\xc2\xb8\xe0\xa1\x28\x1d\x4c\xa7\xcb\x90\x6a\xd7\x40\x6b\x29\x13\x5c\x4\x8f\xe1\x9a\x31\xb1\x7c\xe2\x62\x1f\xc9\x10\x1a\xa0\x9\xb3\xe6\xf3\xc1\x5\xba\x82\x71\xc0\xe9\x60\x9b\xf0\x18\x12\x46\x48\xbd\xe3\xb4\xac\x30\xdf\xc5\x8b\xfc\x77\x81\x44\x97\xf5\xf7\x59\x98\x24\x3d\x2\x76\x22\xed\x6e\x2b\xff\xd\xc4\x70\x8a\xe5\xb5\x73\x99\xf2\x23\x52\xd8\xdb\x14\x96\xda\xb0\xd0\x45\x51\xae\xa6\x7d\x50\x6d\x95\xee\x80\x4d\xe\xca\xdc\x85\x63\x2a\x7b\xcd\x35" }, + { 0x546190, "\x96\xef\xf6\x25\x2a\x8e\x6d\xc1\x11\x1d\xb8\x33\x85\xa7\x4c\xc8\x76\xad\x24\x29\xbe\x30\xbf\x54\x5b\x21\xb5\x2f\x51\xde\xca\x74\x9f\x80\xec\xc2\x37\xb9\xe6\xc5\x3a\xe0\xf2\xc4\xd3\x3\xaa\xed\xcb\xc6\xa3\xf4\xe4\xba\x49\xb\x18\x50\xac\xf3\x4e\x64\xe3\x4f\xe\x22\x38\xdf\x94\xc7\xd7\x17\x84\x6c\xb7\xc3\x13\x4b\x47\xb0\x6\xa1\x40\x5f\xa0\x89\xf9\x8a\x3e\xab\x81\x9c\x36\x5\x1a\x62\x8b\x5c\xe8\x7f\x23\xe1\x14\x32\x61\xea\x2\xf1\x5a\x0\x4\x19\xf8\x7e\x7\xa8\x9d\x69\x8f\x1e\x79\xb6\x2d\x59\x6f\xdc\xd4\x8d\x8\x75\x16\x63\x88\x26\x99\x42\xee\x55\x77\xbb\x1c\x1b\xf0\xaf\xbc\xfa\x98\x9e\xc0\xa2\xf\x60\xa\x52\xa9\x2e\x7a\x82\x86\x2b\xce\xf7\x73\x28\xe9\xd6\x4a\x90\x43\x2c\x5e\x8c\x10\x6a\x3b\xf5\xda\x68\x3c\xe2\x91\x56\xa5\x15\xae\xcc\x31\x95\x35\x39\x71\xd0\x7b\x78\xcf\x65\x53\x41\xa4\x6b\x7c\x67\xc\x57\x4d\xfc\xa6\xd\xd2\xc9\x9\xcd\x48\x12\x97\xb4\xfd\x3d\x83\xd8\xfb\xfe\xe5\xdd\x45\x92\x7d\x6e\x1\x5d\xe7\x20\x66\x58\xff\xb3\x3f\x27\xbd\x46\x34\x72\xd5\x1f\xb1\x70\xd9\xb2\xeb\x87\x9b\x9a\xd1\x93\x44\xdb" }, + { 0x546290, "\x35\x7e\xbe\xb8\x37\x3c\x49\x22\xfe\x94\x24\x93\x78\x2\xcf\xdd\xe3\xb0\xe1\x70\xd3\xc3\xaf\x68\x6\x31\xb4\x7\x3d\xeb\x75\x76\x62\x5e\x73\xe6\xbf\x32\xd8\x9e\xdb\xda\x1b\xca\x11\xbc\x2f\x47\x6b\xed\xdc\x86\x64\x90\x65\xd0\xf4\xe4\x39\xa7\x16\x43\x8b\x5d\x61\x8a\x0\xf\xc4\xe9\xb9\x53\xe7\x15\x92\x21\xe0\x6e\xcb\x4a\xfb\x91\x9c\x97\x28\xc8\xd7\xd2\x99\x74\xb7\x4d\x63\x8e\x80\xe\xd9\xa0\x95\x2e\xc9\x7b\x42\x3a\x58\xd\x1c\xce\x84\xc6\x1e\x67\xa8\xc5\x17\x33\xcd\xd1\xdf\x8f\x66\x9f\xc7\x1\x3e\x2a\x23\x5\xb\xf9\x51\x81\x40\xb5\xef\xab\xf2\x5f\x50\x30\x6c\x26\x82\xfc\x60\x83\x3\x3b\x56\xe8\xfd\x18\xb2\x98\xba\x72\x27\xf5\xa1\xaa\x36\xec\x69\x4c\x77\x34\x59\xf3\x38\x9b\x7d\xc0\xa6\x48\xae\x20\xfa\xcc\xd5\xde\xb3\x14\xa4\xa\x5c\xad\x25\x7a\x4e\xe5\x46\x6f\xff\x52\x4b\x1d\xea\x8c\x79\xf1\x9a\x8d\xa2\xc2\xac\x89\x6a\x41\x44\xf8\x57\x9d\x9\x13\x7f\x10\x12\x2d\x45\xee\xa9\xe2\xc1\x3f\x1a\xbd\x29\x19\x54\xf7\xa5\x71\xd4\x96\x7c\x5b\x1f\x87\x4f\x4\xf0\x5a\xb6\x6d\xa3\xd6\xb1\x2b\xbb\x55\x8\x88\xf6\x85\xc\x2c" }, + { 0x546398, "\x2f\x62\x9b\xe4\xee\xdb\x3f\x8d\xd3\xd7\x9c\x32\xd6\x4a\xca\x50\xe1\x8e\x6e\xf9\x99\xc5\x4e\xdf\x46\x5d\xd5\xb7\x6d\xb1\xb9\x7e\xf\xad\x44\x96\x13\x6c\x97\x26\xa8\x9f\x85\xde\xed\x56\xce\xda\xb0\xb\x1c\xb8\x3d\x5a\x1f\xdd\x84\xf3\xcd\x9e\x73\x28\x61\x8c\xbb\x69\x64\x4f\x0\x49\x3c\x75\xc3\x29\x8a\xe2\x4d\xc7\xcb\x10\xd\xe9\x7f\xc4\x60\x1b\x5f\xd1\x45\x42\x93\x59\xe8\x74\xff\x7a\x72\xea\xd4\xa\x3e\x7d\xc1\x31\xa4\x66\x92\xfd\xf6\x6b\x3b\xba\xbc\x19\x6a\x54\x4b\x38\x47\x43\x33\x91\x8b\xe\xae\x4\x76\x4c\xab\xc6\xbe\x36\xd0\xa0\x67\x90\x87\xf5\x9a\x77\xe6\xcf\xb2\x12\x22\x8\x37\x30\xaf\x16\x3\x58\xf1\xaa\x1e\x25\xeb\xf4\x21\xa9\xfe\x27\x83\xdc\x6\x2a\x48\x78\x68\xb4\xa7\x79\x9\x80\x81\xc8\x52\x17\xcc\x2d\x15\x94\x8f\xa1\x14\x98\xe7\xd9\x7b\xb6\x82\x5\xbf\x39\x88\xac\x86\xa2\xf8\xef\x23\x2e\x95\xd2\xa6\xf2\x2c\x3a\x2b\x65\x55\x18\xc9\x35\x57\x24\xd8\xec\xf7\xf0\xb3\x5b\x6f\xfb\x20\xbd\x5c\xfa\x71\x63\xc0\x1d\xe0\x53\x2\xa5\x7c\x51\x11\xb5\xfc\x1a\x5e\x9d\x40\x34\x1\x7\x89\xa3\xc\x70\xe5\xe3\x41\xc2" }, + }; + +struct buffer_t type_four_list[NUM_TYPE_FOURS]={ + { 0x55f320, "\x39\x25\x29\x3c\x2b\x3a\x32\x23\x26\x24\x2d\x3d\x35\x2e\x3b\x38\x20\x27\x28\x22\x33\x3f\x2c\x3e\x36\x2a\x30\x2f\x21\x34\x31\x37\x00" }, + { 0x55f340, "\x5f\x4b\x40\x5e\x43\x4e\x55\x41\x5a\x57\x5d\x5b\x51\x4f\x4a\x52\x53\x58\x42\x44\x49\x46\x4d\x47\x48\x45\x50\x59\x4c\x54\x56\x5c\x00" }, + { 0x55f360, "\x7a\x7c\x6f\x6c\x60\x62\x73\x69\x71\x65\x6d\x72\x78\x6b\x64\x70\x74\x7b\x7e\x76\x67\x68\x63\x77\x79\x7f\x61\x6e\x75\x66\x6a\x7d\x00" }, + { 0x55f604, "\x17\xc\x1a\x19\x13\x12\x3\x1b\xa\x7\x1e\x1d\x5\x16\x15\x14\xd\x8\xb\x10\xf\x1\x4\x0\x18\x1c\xe\x11\x6\x1f\x2\x9\x00" }, + { 0x5628c4, "\xd9\xd6\xd5\xc9\xda\xdd\xd2\xdf\xdc\xd7\xc3\xd3\xc8\xc6\xc4\xd1\xca\xcc\xc1\xc5\xd4\xc2\xc0\xcb\xdb\xde\xcf\xcd\xce\xd0\xd8\xc7\x00" }, + { 0x5628e4, "\xf0\xff\xfc\xe4\xfb\xf1\xf3\xe3\xf5\xfe\xea\xf7\xf6\xe2\xe5\xe7\xf8\xe8\xef\xf9\xf4\xeb\xed\xfd\xe9\xfa\xe0\xe1\xec\xf2\xee\xe6\x00" }, + { 0x5628a4, "\xa0\xb0\xb7\xb1\xbe\xbf\xab\xb2\xa6\xa9\xa8\xa2\xb4\xb3\xa5\xaf\xba\xac\xb8\xbc\xbd\xae\xbb\xa1\xb5\xad\xb9\xa3\xaa\xb6\xa7\xa4\x00" }, + { 0x55f6a4, "\xa9\xaf\xb5\xa6\xa1\xbf\xac\xb9\xa0\xb0\xa5\xad\xa4\xbd\xba\xb1\xbb\xae\xab\xb8\xb4\xb2\xa8\xa3\xb7\xbe\xa2\xb3\xaa\xb6\xbc\xa7\x00" }, + { 0x55f6c4, "\xcf\xd1\xd8\xc8\xc2\xce\xd9\xd2\xd6\xca\xc0\xd5\xdb\xcb\xc3\xc6\xd3\xd7\xdd\xdc\xc9\xd4\xde\xc1\xc7\xc4\xc5\xcc\xcd\xd0\xdf\xda\x00" }, + { 0x55f6e4, "\xee\xf5\xf3\xe7\xe1\xef\xfc\xf7\xed\xe6\xe4\xf8\xe8\xec\xff\xf0\xe2\xea\xe5\xe9\xf2\xfa\xf9\xfd\xeb\xfe\xf4\xe0\xf6\xf1\xe3\xfb\x00" }, + { 0x562928, "\x31\x3b\x33\x29\x34\x25\x24\x3d\x23\x28\x32\x27\x3a\x3e\x20\x22\x2b\x2e\x3c\x38\x30\x2c\x39\x35\x37\x2f\x3f\x2d\x2a\x26\x36\x21\x00" }, + { 0x55f744, "\x51\x41\x4c\x5d\x46\x5c\x5a\x43\x49\x48\x5e\x42\x53\x47\x54\x4d\x45\x55\x58\x40\x4b\x5b\x56\x4f\x5f\x57\x4e\x52\x4a\x44\x59\x50\x00" }, + { 0x562884, "\x84\x98\x8a\x88\x82\x92\x8d\x96\x85\x97\x8f\x90\x95\x8c\x80\x9c\x94\x9f\x91\x87\x86\x9d\x9e\x93\x9a\x9b\x8b\x83\x89\x81\x99\x8e\x00" }, + { 0x55f784, "\x96\x9c\x8a\x8c\x92\x81\x82\x84\x95\x93\x91\x9f\x90\x85\x9b\x9d\x80\x89\x8e\x8b\x94\x83\x99\x87\x8f\x97\x88\x8d\x9a\x86\x9e\x98\x00" }, + { 0x55f7a4, "\xb2\xa6\xa2\xaa\xa9\xb8\xac\xae\xab\xb7\xaf\xbc\xa3\xa0\xb0\xa5\xbf\xa1\xb3\xba\xb5\xbe\xb4\xbb\xb6\xbd\xb9\xa7\xa8\xa4\xad\xb1\x00" }, + { 0x55f7c4, "\xd7\xdc\xc0\xdb\xd9\xd5\xc7\xc4\xd4\xd6\xc2\xce\xd8\xc3\xd1\xca\xcc\xc1\xc8\xcd\xc5\xc6\xd2\xcf\xde\xd3\xd0\xda\xc9\xcb\xdd\xdf\x00" }, + { 0x55f7e4, "\xe4\xec\xf1\xf9\xe1\xfc\xe2\xe3\xfb\xe5\xef\xe7\xfd\xf7\xe6\xf8\xf3\xf5\xea\xfa\xe8\xeb\xed\xfe\xff\xf2\xf4\xe9\xee\xf0\xf6\xe0\x00" }, + { 0x55f804, "\x1e\xa\xe\x13\x1b\xc\x14\x10\x8\xb\xd\x18\x2\x1c\x1a\x16\x11\x4\x15\x17\x9\x5\xf\x7\x12\x1d\x1\x19\x6\x3\x0\x1f\x00" }, + { 0x55f824, "\x3c\x39\x32\x34\x35\x20\x3a\x2c\x3d\x2a\x2b\x26\x30\x38\x23\x33\x29\x2d\x36\x3e\x21\x25\x2f\x2e\x37\x31\x28\x24\x22\x3b\x27\x3f\x00" }, + { 0x55f844, "\x57\x4c\x51\x45\x53\x54\x4b\x5b\x59\x49\x56\x47\x42\x4e\x58\x5d\x5e\x40\x5f\x46\x52\x5a\x55\x44\x50\x4d\x48\x5c\x41\x43\x4a\x4f\x00" }, + { 0x55f864, "\x7b\x6b\x7d\x63\x7c\x61\x7a\x79\x71\x6c\x73\x74\x6e\x6a\x68\x7f\x66\x77\x67\x69\x60\x7e\x62\x6d\x76\x78\x6f\x72\x70\x65\x75\x64\x00" }, + { 0x55f884, "\x92\x9c\x98\x8a\x96\x84\x80\x9f\x9b\x97\x93\x8e\x9a\x87\x88\x85\x8b\x94\x86\x8c\x90\x8d\x9d\x91\x82\x89\x8f\x99\x81\x83\x95\x9e\x00" }, + { 0x55f8a4, "\xb8\xa9\xbf\xa3\xb3\xaa\xa2\xa5\xb6\xbd\xa7\xaf\xb4\xac\xa4\xba\xae\xa0\xbe\xb9\xa8\xbc\xa6\xb7\xab\xb5\xa1\xad\xb1\xb2\xbb\xb0\x00" }, + { 0x55f91c, "\x1d\x1e\x1\xc\x12\xd\x14\x8\xe\x15\x9\xb\xa\x18\x1a\x7\x1b\x6\x4\xf\x16\x2\x0\x3\x10\x17\x11\x19\x13\x1c\x5\x1f\x00" }, + { 0x55f93c, "\x3d\x2e\x2f\x35\x37\x25\x3f\x32\x3e\x23\x21\x27\x22\x2d\x3a\x39\x3c\x2a\x3b\x30\x29\x31\x26\x34\x24\x2c\x33\x2b\x20\x36\x38\x28\x00" }, + { 0x55f9d0, "\xcc\xd6\xce\xc0\xcd\xd5\xd0\xde\xdc\xd2\xc1\xc9\xc5\xc8\xc6\xd7\xcf\xdb\xc4\xd1\xdf\xd9\xdd\xc3\xd3\xd8\xc2\xd4\xcb\xda\xc7\xca\x00" }, + { 0x560280, "\x83\x85\x8d\x89\x9a\x96\x88\x90\x86\x9e\x9c\x95\x82\x84\x97\x8c\x98\x8b\x99\x91\x9b\x94\x93\x8a\x8e\x80\x9d\x9f\x81\x8f\x87\x92\x00" }, + { 0x56034c, "\x4d\x46\x52\x58\x5c\x51\x41\x5b\x42\x40\x43\x5e\x48\x56\x49\x4e\x44\x50\x45\x53\x47\x5f\x55\x57\x5d\x4c\x5a\x4a\x4f\x54\x59\x4b\x00" }, + { 0x56036c, "\x70\x74\x60\x65\x69\x6f\x79\x7e\x61\x6e\x64\x62\x75\x6b\x7f\x7b\x72\x71\x73\x7d\x6a\x66\x67\x78\x63\x7c\x6d\x77\x6c\x68\x76\x7a\x00" }, + { 0x5605b0, "\xa7\xa3\xbe\xaa\xbd\xa8\xa9\xa0\xa4\xa1\xa6\xb5\xb4\xb0\xa2\xba\xb2\xb7\xb3\xbb\xb9\xaf\xac\xbf\xbc\xb6\xab\xb8\xad\xb1\xa5\xae\x00" }, + { 0x560bcc, "\xd0\xc1\xd2\xcd\xca\xda\xd4\xdb\xc7\xd3\xc8\xc3\xcc\xd5\xc4\xc6\xdd\xcf\xc9\xcb\xc5\xc0\xd9\xd8\xd6\xde\xdf\xc2\xd1\xdc\xce\xd7\x00" }, + { 0x560bec, "\xe2\xee\xfb\xfe\xf2\xe5\xf9\xef\xed\xe7\xe3\xfd\xfc\xe6\xfa\xea\xeb\xec\xf0\xf1\xf3\xe0\xf4\xe8\xff\xe1\xf7\xe4\xf5\xf8\xe9\xf6\x00" }, + { 0x560c10, "\x2\x1b\x1\x11\x17\x1e\xa\x1d\xe\x8\x4\xf\x1a\x7\x9\xb\x10\x0\x1c\x18\x3\x12\x1f\xd\x19\x16\x14\x6\x5\xc\x15\x13\x00" }, + { 0x560d34, "\x37\x36\x29\x3a\x3d\x2e\x38\x25\x28\x39\x3c\x26\x2d\x24\x30\x23\x21\x31\x3e\x34\x27\x22\x2f\x2c\x2a\x3f\x3b\x35\x33\x20\x2b\x32\x00" }, + { 0x560e38, "\x23\x32\x27\x39\x28\x30\x36\x20\x3e\x3c\x38\x24\x34\x21\x35\x2e\x3a\x3b\x31\x3f\x2b\x37\x3d\x2a\x2f\x26\x22\x25\x33\x29\x2c\x2d\x00" }, + { 0x561014, "\x16\xe\x19\x1\x15\x2\xa\x14\x1c\xf\x10\x4\x8\xc\xd\x0\x18\x5\x1f\x1a\x17\x1e\x13\x6\x9\x3\x7\x12\x1b\x11\x1d\xb\x00" }, + { 0x561074, "\x65\x73\x7b\x7e\x6d\x69\x7f\x7d\x68\x6a\x60\x72\x78\x62\x67\x70\x61\x6c\x74\x79\x66\x71\x7c\x76\x64\x6e\x6b\x75\x63\x7a\x77\x6f\x00" }, + { 0x561094, "\x83\x9a\x89\x87\x9f\x8d\x97\x92\x9d\x95\x99\x81\x88\x82\x8c\x8f\x85\x84\x94\x8a\x8b\x9c\x86\x9b\x96\x90\x93\x8e\x80\x9e\x98\x91\x00" }, + { 0x5610b4, "\xbd\xbc\xa3\xa4\xbe\xb3\xa8\xab\xb0\xba\xb5\xb8\xb9\xaf\xb7\xa1\xb6\xaa\xac\xad\xbb\xb2\xae\xbf\xb1\xa5\xa0\xb4\xa2\xa9\xa6\xa7\x00" }, + { 0x5610d4, "\xc1\xc8\xc9\xc0\xdb\xce\xd1\xd6\xd3\xdd\xd2\xdc\xcb\xd4\xc4\xc7\xd9\xd7\xd8\xcc\xda\xc2\xcf\xca\xc6\xd0\xc5\xde\xd5\xdf\xc3\xcd\x00" }, + { 0x561190, "\x93\x94\x9c\x88\x80\x9d\x83\x8b\x8f\x97\x81\x87\x8c\x8d\x95\x96\x9a\x82\x92\x8a\x9b\x91\x9e\x98\x84\x86\x90\x85\x89\x99\x9f\x8e\x00" }, + { 0x5611b0, "\xae\xa0\xb1\xb7\xa1\xa6\xa5\xa7\xaf\xa4\xbc\xac\xb6\xb3\xb0\xa8\xb8\xbe\xb2\xab\xb9\xbd\xa9\xb5\xbf\xa2\xbb\xa3\xba\xb4\xad\xaa\x00" }, + { 0x5611d0, "\xcc\xd7\xd5\xca\xc0\xcd\xc4\xc2\xd8\xdf\xdc\xd1\xd4\xcb\xc6\xda\xc1\xd2\xcf\xc3\xdd\xce\xc7\xd6\xde\xd9\xc5\xc9\xd3\xc8\xd0\xdb\x00" }, + { 0x562968, "\x7a\x78\x79\x7d\x6b\x62\x7c\x6d\x75\x6f\x7f\x65\x61\x60\x73\x77\x63\x6e\x71\x66\x70\x6c\x68\x6a\x76\x74\x69\x64\x72\x67\x7b\x7e\x00" }, + { 0x55f214, "\xd\x14\x4\xc\x1d\x5\x7\x9\x1c\xe\x16\x11\x17\x3\x6\x15\xb\x0\x12\x13\x1\x19\x1b\x1f\x1a\x2\xa\x10\xf\x1e\x18\x8\x00" }, + { 0x55f380, "\x98\x88\x94\x97\x83\x90\x99\x84\x8d\x9c\x86\x9d\x9e\x92\x91\x8b\x8f\x82\x8e\x9b\x93\x85\x87\x96\x95\x8a\x8c\x9a\x80\x81\x9f\x89\x00" } + }; + +struct buffer_t type_five_list[NUM_TYPE_FIVES]={ + { 0x55f3f8, "\xef\xe7\xf6\xfd\xeb\xf4\xec\xe2\xf7\xf9\xea\xe4\xf8\xff\xf5\xfa\xe8\xee\xfc\xe9\xe5\xfb\xe6\xe0\xfe\xed\xf2\xe1\xf1\xf0\xe3\xf3\x00" }, + { 0x562948, "\x47\x41\x56\x59\x45\x40\x58\x48\x49\x57\x55\x54\x5a\x4c\x4f\x4d\x51\x5c\x53\x4a\x52\x5d\x5f\x5e\x50\x43\x42\x5b\x44\x46\x4b\x4e\x00" }, + { 0x561258, "\x5b\x49\x5f\x43\x57\x4c\x54\x59\x5c\x5a\x51\x52\x5d\x4a\x5e\x47\x44\x56\x55\x4d\x40\x50\x58\x48\x46\x45\x4f\x41\x4b\x4e\x53\x42\x00" }, + { 0x561278, "\x6b\x63\x7e\x69\x64\x7f\x70\x76\x68\x7d\x71\x60\x7c\x6d\x66\x77\x67\x6a\x7a\x78\x6f\x61\x62\x75\x7b\x74\x72\x65\x6c\x79\x6e\x73\x00" }, + { 0x561298, "\x91\x97\x98\x8d\x8a\x8f\x82\x95\x84\x93\x99\x92\x9d\x86\x85\x94\x83\x90\x81\x80\x8c\x9f\x96\x9b\x88\x8e\x89\x87\x9c\x9e\x9a\x8b\x00" }, + { 0x5613a0, "\xb1\xb0\xa4\xbd\xa8\xb5\xba\xbb\xb4\xb8\xaf\xb7\xb6\xa7\xbe\xae\xb2\xaa\xb3\xab\xac\xa0\xa6\xa2\xbf\xb9\xa9\xbc\xa1\xad\xa3\xa5\x00" }, + { 0x5613c0, "\xc0\xc5\xd0\xdc\xcc\xda\xc4\xdb\xca\xcd\xd4\xcb\xc7\xc3\xd2\xde\xc6\xd1\xc1\xc8\xd5\xc9\xdf\xcf\xd9\xd8\xd6\xc2\xd3\xce\xd7\xdd\x00" }, + { 0x5613e4, "\xf0\xee\xf8\xe4\xe8\xfb\xfa\xef\xf6\xf9\xf3\xec\xe3\xe0\xed\xf4\xe7\xff\xea\xfe\xe1\xe9\xf5\xf1\xfc\xe6\xe2\xe5\xfd\xf2\xf7\xeb\x00" }, + { 0x561404, "\x1a\x16\x2\x19\x11\x1b\x17\xf\x14\x9\x18\x5\xe\xa\x6\x1d\x0\x1e\x7\x15\x4\x12\x8\x13\x10\xc\x1c\x1\xd\xb\x1f\x3\x00" }, + { 0x5615a0, "\xba\xb8\xb2\xb5\xa0\xbc\xa1\xab\xb9\xbb\xbf\xb1\xa7\xb0\xbe\xa6\xb7\xa4\xaa\xae\xad\xac\xb6\xa8\xa2\xa3\xb3\xb4\xa9\xbd\xa5\xaf\x00" }, + { 0x561628, "\x34\x35\x2f\x3a\x30\x32\x31\x21\x27\x3c\x37\x23\x3b\x2c\x26\x36\x24\x25\x29\x3f\x33\x3e\x22\x2d\x3d\x38\x39\x20\x28\x2b\x2e\x2a\x00" }, + { 0x561748, "\x52\x54\x41\x5f\x53\x43\x5e\x56\x5c\x44\x5a\x46\x4d\x4b\x57\x5d\x51\x45\x58\x5b\x42\x49\x48\x59\x4a\x40\x47\x50\x4f\x4c\x55\x4e\x00" }, + { 0x561768, "\x6f\x6b\x7d\x63\x6a\x79\x7f\x7c\x6d\x78\x62\x67\x69\x74\x75\x66\x7a\x6e\x70\x7e\x72\x61\x7b\x71\x73\x68\x60\x65\x64\x76\x6c\x77\x00" }, + { 0x5617f0, "\xed\xe3\xeb\xe0\xf7\xf3\xfa\xf2\xf0\xfc\xfe\xfb\xfd\xe8\xe2\xef\xea\xf4\xe5\xe1\xee\xf8\xec\xe4\xe9\xf5\xff\xe7\xf6\xf1\xf9\xe6\x00" }, + { 0x561ea0, "\xa9\xaf\xb0\xac\xa3\xb5\xa7\xb7\xae\xab\xbd\xa8\xb9\xb1\xa0\xaa\xa1\xa6\xb8\xb6\xad\xb3\xb4\xb2\xa2\xbb\xba\xa4\xa5\xbf\xbc\xbe\x00" }, + { 0x561f38, "\x37\x31\x3a\x3e\x20\x33\x26\x3d\x29\x25\x2e\x39\x2b\x28\x36\x22\x23\x38\x35\x30\x2d\x2c\x21\x2f\x3b\x27\x32\x2a\x34\x3f\x3c\x24\x00" }, + { 0x561f58, "\x55\x44\x47\x4d\x57\x4c\x43\x4a\x51\x53\x41\x5f\x49\x4e\x54\x5c\x4b\x5d\x45\x5b\x56\x52\x50\x46\x59\x5e\x40\x4f\x48\x42\x5a\x58\x00" }, + { 0x561f7c, "\x79\x69\x61\x7e\x73\x7f\x6b\x66\x76\x7c\x63\x6e\x72\x6d\x67\x6f\x77\x71\x75\x64\x62\x74\x68\x7b\x70\x78\x6a\x65\x60\x7a\x6c\x7d\x00" }, + { 0x561f9c, "\x9a\x82\x90\x8d\x8f\x94\x89\x9d\x81\x9f\x93\x85\x84\x98\x9c\x88\x8e\x86\x97\x92\x9e\x87\x9b\x99\x83\x8b\x95\x96\x91\x8a\x8c\x80\x00" }, + { 0x562198, "\x96\x8e\x80\x89\x94\x99\x8a\x87\x90\x8d\x92\x9e\x84\x86\x9a\x82\x8f\x9b\x9f\x8b\x9d\x81\x88\x97\x95\x8c\x91\x93\x83\x98\x85\x9c\x00" }, + { 0x5622f0, "\xf0\xeb\xe7\xe9\xed\xe1\xfd\xea\xe3\xf3\xee\xf9\xe0\xfe\xe5\xf5\xfb\xec\xef\xf8\xfa\xf6\xf1\xff\xe6\xe4\xf2\xf4\xf7\xe8\xe2\xfc\x00" }, + { 0x562864, "\x73\x63\x69\x72\x64\x7f\x7b\x6d\x74\x75\x70\x6e\x66\x62\x77\x68\x6c\x7a\x6b\x76\x61\x71\x7d\x65\x78\x7e\x67\x7c\x60\x6f\x79\x6a\x00" }, + { 0x56238c, "\x97\x87\x80\x8a\x93\x9b\x88\x96\x92\x8e\x83\x9a\x82\x85\x9c\x8d\x9f\x95\x9d\x8c\x86\x89\x8f\x90\x94\x91\x98\x81\x8b\x84\x99\x9e\x00" }, + { 0x5623ac, "\xae\xb6\xbb\xb1\xad\xaf\xbf\xb2\xa9\xb4\xaa\xa6\xa0\xa8\xb7\xac\xb0\xa5\xb3\xba\xab\xa3\xa7\xa2\xb8\xbe\xa1\xbc\xb5\xbd\xa4\xb9\x00" }, + { 0x5623cc, "\xc2\xd8\xde\xd2\xd0\xce\xca\xda\xd4\xc1\xdb\xc0\xd1\xdd\xc4\xd5\xcb\xc3\xdf\xc8\xcf\xd7\xc7\xd3\xd6\xc6\xc9\xdc\xcc\xcd\xd9\xc5\x00" }, + { 0x5623ec, "\xec\xe1\xef\xee\xfd\xe8\xf4\xe7\xf8\xf1\xf0\xff\xf7\xfb\xfc\xf9\xed\xf5\xeb\xe5\xf6\xfa\xfe\xf2\xe4\xea\xe0\xe2\xf3\xe3\xe6\xe9\x00" }, + { 0x562908, "\x13\x1c\x1a\x1d\x19\x15\x1f\x11\x18\x1\x0\xe\x12\x1e\xf\x1b\x17\x3\x14\xd\x6\x8\x10\x2\xc\x9\xb\x4\x5\x16\xa\x7\x00" }, + { 0x56249c, "\x89\x9c\x8c\x97\x81\x96\x9a\x80\x91\x83\x8b\x93\x9f\x88\x8f\x8e\x87\x84\x94\x82\x8a\x95\x86\x98\x9e\x90\x92\x9d\x9b\x85\x8d\x99\x00" }, + { 0x562544, "\x43\x42\x55\x4c\x48\x5b\x5d\x46\x50\x40\x49\x5c\x5e\x41\x53\x57\x58\x5f\x51\x47\x45\x4b\x52\x5a\x59\x54\x44\x56\x4f\x4a\x4d\x4e\x00" }, + { 0x562564, "\x75\x65\x7b\x62\x7e\x60\x66\x6d\x61\x69\x6f\x7c\x6a\x76\x7f\x73\x63\x6c\x79\x7a\x70\x7d\x72\x71\x67\x68\x64\x74\x6e\x78\x6b\x77\x00" }, + { 0x5625a0, "\xbf\xab\xb3\xa0\xb6\xb5\xb4\xaa\xbd\xa5\xbe\xba\xaf\xa4\xae\xa1\xb9\xa7\xa2\xb2\xac\xb7\xa8\xa9\xa3\xb1\xb8\xb0\xbc\xbb\xa6\xad\x00" }, + { 0x5625c0, "\xc2\xdb\xcc\xd7\xdf\xc5\xd5\xde\xd6\xc9\xda\xd2\xcf\xdc\xd8\xca\xd9\xd0\xcd\xd3\xc4\xd1\xc8\xd4\xdd\xce\xc6\xc0\xc1\xc7\xcb\xc3\x00" }, + { 0x5625e0, "\xe0\xe6\xeb\xe8\xec\xe4\xfa\xfc\xe5\xfe\xf4\xe3\xea\xf8\xf2\xfd\xf6\xff\xe7\xe9\xef\xee\xf7\xf3\xf1\xf9\xf0\xed\xfb\xe2\xe1\xf5\x00" }, + { 0x562600, "\x12\x3\x1a\x15\x4\x19\xb\x1b\x17\x1e\xd\x5\x11\x14\x1c\x0\x18\x10\xa\x6\xe\x8\x2\x7\x13\x9\x16\x1d\xf\xc\x1\x1f\x00" }, + { 0x562620, "\x3e\x3b\x31\x27\x28\x26\x38\x37\x2d\x2f\x32\x23\x3d\x24\x2a\x3a\x2c\x33\x34\x3f\x2b\x39\x30\x21\x36\x25\x3c\x2e\x22\x20\x29\x35\x00" }, + { 0x562640, "\x4f\x5d\x57\x56\x4d\x45\x53\x5f\x5b\x49\x5c\x5e\x55\x41\x46\x48\x4c\x50\x4b\x42\x44\x4a\x47\x5a\x58\x4e\x43\x51\x52\x54\x59\x40\x00" }, + { 0x562660, "\x6f\x64\x7d\x7b\x75\x70\x61\x6b\x60\x77\x73\x67\x7e\x7f\x68\x6a\x79\x69\x65\x66\x6c\x7a\x74\x76\x6e\x78\x63\x7c\x72\x71\x6d\x62\x00" } + }; + +static unsigned int yahoo_auth_fibonacci(unsigned int challenge, int divisor, int outer_loop, int inner_loop); + +static unsigned int yahoo_auth_typeone(unsigned int challenge, int divisor, int outer_loop, int inner_loop, int type_one_variable) +{ + return yahoo_auth_fibonacci(challenge ^ type_one_variable, divisor, outer_loop, inner_loop); +} + +static unsigned int yahoo_auth_typetwo(unsigned int challenge, int divisor, int outer_loop, int inner_loop, int type_two_variable, int type_two_variable2) +{ + return yahoo_auth_fibonacci((challenge * type_two_variable) + type_two_variable2, divisor, outer_loop, inner_loop); +} + +static unsigned char yahoo_auth_read3(unsigned int buffer, int offset) +{ + int i; + if (offset > 256) + return 0; + for (i = 0; i < NUM_TYPE_THREES; i++) { + if (type_three_list[i].buffer_start == buffer) + return type_three_list[i].buffer[offset] ^ (buffer & 0xff); + } + return 0; +} + +static unsigned int yahoo_auth_typethree(unsigned int challenge, int divisor, int outer_loop, int inner_loop, int offset) +{ + int new_challenge = yahoo_auth_read3(offset, (challenge & 0xff000000) >> 0x18) << 0x18; + new_challenge |= yahoo_auth_read3(offset, (challenge & 0x00ff0000) >> 0x10) << 0x10; + new_challenge |= yahoo_auth_read3(offset, (challenge & 0x0000ff00) >> 0x8) << 0x8; + new_challenge |= yahoo_auth_read3(offset, (challenge & 0x000000ff)); + return yahoo_auth_fibonacci(new_challenge, divisor, outer_loop, inner_loop); +} + +static unsigned char yahoo_auth_read45(unsigned int buffer, int offset) +{ + int i; + if (offset > 32) + return 0; + for (i = 0; i < NUM_TYPE_FOURS; i++) { + if (type_four_list[i].buffer_start == buffer) + return type_four_list[i].buffer[offset] ^ (buffer & 0xff); + } + for (i = 0; i < NUM_TYPE_FIVES; i++) { + if (type_five_list[i].buffer_start == buffer) + return type_five_list[i].buffer[offset] ^ (buffer & 0xff); + } + return 0; +} + +static unsigned int yahoo_auth_typefourfive(unsigned int challenge, int divisor, int outer_loop, int inner_loop, int initial) +{ + unsigned int final_value = 0; + int i; + for (i = 0; i < 32; i++) + { + unsigned char buffer = yahoo_auth_read45(initial, i); /* Find the location in the challenge to put the 1/0 bit */ + int mask = ~(1 << buffer); /* so that we can do a replace of our current value. */ + int new_value = (challenge >> i) & 1; /* Is this bit 1 or 0? */ + final_value = (final_value & mask) | (new_value << buffer); + } + return yahoo_auth_fibonacci(final_value, divisor, outer_loop, inner_loop); +} + +static unsigned int yahoo_auth_fibonacci(unsigned int challenge, int divisor, int outer_loop, int inner_loop) +{ + unsigned int hash = (challenge & 0xff) * 0x9e3779b1; + + hash ^= (challenge & 0xff00) >> 0x8; + hash *= 0x9e3779b1; + hash ^= (challenge & 0xff0000) >> 0x10; + hash *= 0x9e3779b1; + hash ^= (challenge & 0xff000000) >> 0x18; + hash *= 0x9e3779b1; + + if (outer_loop > 1) { + auth_function_t *ft; + int remainder; + hash = ((((hash ^ (hash >> 0x8)) >> 0x10) ^ hash) ^ (hash >> 0x8)) & 0xff; + remainder = hash % divisor; + outer_loop--; + challenge *= 0x10dcd; + ft = &main_function_list[inner_loop][remainder]; + if (ft) { + switch (ft->type) { + case 0: + return challenge; + case 1: + return yahoo_auth_typeone(challenge, divisor, outer_loop, inner_loop, ft->var1); + case 2: + return yahoo_auth_typetwo(challenge, divisor, outer_loop, inner_loop, ft->var1, ft->var2); + case 3: + return yahoo_auth_typethree(challenge, divisor, outer_loop, inner_loop, ft->var1); + case 4: + case 5: + return yahoo_auth_typefourfive(challenge, divisor, outer_loop, inner_loop, ft->var1); + default: + break; + } + } + } + return challenge; +} + +unsigned int yahoo_auth_finalCountdown(unsigned int challenge, int divisor, int inner_loop, int outer_loop) +{ + auth_function_t *ft; + int remainder = challenge % divisor; + ft = &main_function_list[inner_loop][remainder]; + if (ft) { + switch(ft->type) { + case 0: + break; + case 1: + challenge = yahoo_auth_typeone(challenge, divisor, outer_loop, inner_loop, ft->var1); + break; + case 2: + challenge = yahoo_auth_typetwo(challenge, divisor, outer_loop, inner_loop, ft->var1, ft->var2); + break; + case 3: + challenge = yahoo_auth_typethree(challenge, divisor, outer_loop, inner_loop, ft->var1); + break; + case 4: + case 5: + challenge = yahoo_auth_typefourfive(challenge, divisor, outer_loop, inner_loop, ft->var1); + break; + } + } + return challenge; +} + +void YahooClient::process_auth(const char *method, const char *seed, const char *sn) +{ + if (!method || !seed || !sn){ + socket()->error_state("Bad auth packet"); + return; + } + if (atol(method) != 1){ + socket()->error_state("Unknown auth method"); + return; + } + QByteArray password = getPassword().toAscii(); + const char *pass = password.data(); + + unsigned char result[16]; + MD5state_st ctx; + + SHA_CTX ctx1; + SHA_CTX ctx2; + + const char *alphabet1 = "FBZDWAGHrJTLMNOPpRSKUVEXYChImkwQ"; + const char *alphabet2 = "F0E1D2C3B4A59687abcdefghijklmnop"; + + const char *challenge_lookup = "qzec2tb3um1olpar8whx4dfgijknsvy5"; + const char *operand_lookup = "+|&%/*^-"; + const char *delimit_lookup = ",;"; + + char *password_hash = (char *)malloc(25); + char *crypt_hash = (char *)malloc(25); + char *crypt_result = NULL; + + char pass_hash_xor1[64]; + char pass_hash_xor2[64]; + char crypt_hash_xor1[64]; + char crypt_hash_xor2[64]; + char resp_6[100]; + char resp_96[100]; + + unsigned char digest1[20]; + unsigned char digest2[20]; + unsigned char comparison_src[20]; + unsigned char magic_key_char[4]; + const unsigned char *magic_ptr; + + unsigned int magic[64]; + unsigned int magic_work = 0; + unsigned int magic_4 = 0; + + int x; + int y = 0; + int cnt = 0; + int magic_cnt = 0; + int magic_len; + + memset(password_hash, 0, 25); + memset(crypt_hash, 0, 25); + memset(&pass_hash_xor1, 0, 64); + memset(&pass_hash_xor2, 0, 64); + memset(&crypt_hash_xor1, 0, 64); + memset(&crypt_hash_xor2, 0, 64); + memset(&digest1, 0, 20); + memset(&digest2, 0, 20); + memset(&magic, 0, 64); + memset(&resp_6, 0, 100); + memset(&resp_96, 0, 100); + memset(&magic_key_char, 0, 4); + memset(&comparison_src, 0, 20); + + /* + * Magic: Phase 1. Generate what seems to be a 30 byte value (could change if base64 + * ends up differently? I don't remember and I'm tired, so use a 64 byte buffer. + */ + + magic_ptr = (unsigned char*)seed; + + while (*magic_ptr != 0) { + char *loc; + + /* Ignore parentheses. + */ + + if (*magic_ptr == '(' || *magic_ptr == ')') { + magic_ptr++; + continue; + } + + /* Characters and digits verify against the challenge lookup. + */ + + if (isalpha(*magic_ptr) || isdigit(*magic_ptr)) { + loc = (char *)strchr(challenge_lookup, *magic_ptr); + if (!loc) { + /* SME XXX Error - disconnect here */ + } + + /* Get offset into lookup table and shl 3. + */ + + magic_work = loc - challenge_lookup; + magic_work <<= 3; + + magic_ptr++; + continue; + } else { + unsigned int local_store; + + loc = (char *)strchr(operand_lookup, *magic_ptr); + if (!loc) { + /* SME XXX Disconnect */ + } + + local_store = loc - operand_lookup; + + /* Oops; how did this happen? + */ + + if (magic_cnt >= 64) + break; + + magic[magic_cnt++] = magic_work | local_store; + magic_ptr++; + continue; + } + } + + magic_len = magic_cnt; + magic_cnt = 0; + + /* Magic: Phase 2. Take generated magic value and sprinkle fairy dust on the values. + */ + + for (magic_cnt = magic_len-2; magic_cnt >= 0; magic_cnt--) { + unsigned char byte1; + unsigned char byte2; + + /* Bad. Abort. + */ + + if ((magic_cnt + 1 > magic_len) || (magic_cnt > magic_len)) + break; + + byte1 = magic[magic_cnt]; + byte2 = magic[magic_cnt+1]; + + byte1 *= 0xcd; + byte1 ^= byte2; + + magic[magic_cnt+1] = byte1; + } + + /* + * Magic: Phase 3. This computes 20 bytes. The first 4 bytes are used as our magic + * key (and may be changed later); the next 16 bytes are an MD5 sum of the magic key + * plus 3 bytes. The 3 bytes are found by looping, and they represent the offsets + * into particular functions we'll later call to potentially alter the magic key. + * + * %-) + */ + + magic_cnt = 1; + x = 0; + + do { + unsigned int bl = 0; + unsigned int cl = magic[magic_cnt++]; + + if (magic_cnt >= magic_len) + break; + + if (cl > 0x7F) { + if (cl < 0xe0) + bl = cl = (cl & 0x1f) << 6; + else { + bl = magic[magic_cnt++]; + cl = (cl & 0x0f) << 6; + bl = ((bl & 0x3f) + cl) << 6; + } + + cl = magic[magic_cnt++]; + bl = (cl & 0x3f) + bl; + } else + bl = cl; + + comparison_src[x++] = (bl & 0xff00) >> 8; + comparison_src[x++] = bl & 0xff; + } while (x < 20); + + /* First four bytes are magic key. + */ + + memcpy(&magic_key_char[0], comparison_src, 4); + magic_4 = magic_key_char[0] | (magic_key_char[1]<<8) | (magic_key_char[2]<<16) | (magic_key_char[3]<<24); + + /* + * Magic: Phase 4. Determine what function to use later by getting outside/inside + * loop values until we match our previous buffer. + */ + + for (x = 0; x < 65535; x++) { + int leave = 0; + + for (y = 0; y < 5; y++) { + unsigned char result[16]; + MD5state_st ctx; + + unsigned char test[3]; + + memset(&result, 0, 16); + memset(&test, 0, 3); + + /* Calculate buffer. + */ + + test[0] = x; + test[1] = x >> 8; + test[2] = y; + + MD5_Init(&ctx); + MD5_Update(&ctx, magic_key_char, 4); + MD5_Update(&ctx, test, 3); + MD5_Final(result, &ctx); + + if (!memcmp(result, comparison_src+4, 16)) { + leave = 1; + break; + } + } + + if (leave == 1) + break; + } + + /* If y != 0, we need some help. + */ + + if (y != 0) { + unsigned int updated_key; + + /* Update magic stuff. Call it twice because Yahoo's encryption is super bad ass. + */ + + updated_key = yahoo_auth_finalCountdown(magic_4, 0x60, y, x); + updated_key = yahoo_auth_finalCountdown(updated_key, 0x60, y, x); + + magic_key_char[0] = updated_key & 0xff; + magic_key_char[1] = (updated_key >> 8) & 0xff; + magic_key_char[2] = (updated_key >> 16) & 0xff; + magic_key_char[3] = (updated_key >> 24) & 0xff; + } + + /* Get password and crypt hashes as per usual. + */ + + MD5_Init(&ctx); + MD5_Update(&ctx, (unsigned char*)pass, strlen(pass)); + MD5_Final(result, &ctx); + to_y64((unsigned char*)password_hash, result, 16); + + MD5_Init(&ctx); + crypt_result = yahoo_crypt(pass, "$1$_2S43d5f$"); + MD5_Update(&ctx, (unsigned char*)crypt_result, strlen(crypt_result)); + MD5_Final(result, &ctx); + to_y64((unsigned char*)crypt_hash, result, 16); + + /* Our first authentication response is based off of the password hash. + */ + + for (x = 0; x < (int)strlen(password_hash); x++) + pass_hash_xor1[cnt++] = password_hash[x] ^ 0x36; + + if (cnt < 64) + memset(&(pass_hash_xor1[cnt]), 0x36, 64-cnt); + + cnt = 0; + + for (x = 0; x < (int)strlen(password_hash); x++) + pass_hash_xor2[cnt++] = password_hash[x] ^ 0x5c; + + if (cnt < 64) + memset(&(pass_hash_xor2[cnt]), 0x5c, 64-cnt); + + SHA1_Init(&ctx1); + SHA1_Init(&ctx2); + + /* + * The first context gets the password hash XORed with 0x36 plus a magic value + * which we previously extrapolated from our challenge. + */ + + SHA1_Update(&ctx1, (unsigned char*)pass_hash_xor1, 64); + if (y >= 3) + ctx1.Nl = 0x1ff; + SHA1_Update(&ctx1, magic_key_char, 4); + SHA1_Final(digest1, &ctx1); + + /* + * The second context gets the password hash XORed with 0x5c plus the SHA-1 digest + * of the first context. + */ + + SHA1_Update(&ctx2, (unsigned char*)pass_hash_xor2, 64); + SHA1_Update(&ctx2, digest1, 20); + SHA1_Final(digest2, &ctx2); + + /* + * Now that we have digest2, use it to fetch characters from an alphabet to construct + * our first authentication response. + */ + + for (x = 0; x < 20; x += 2) { + unsigned int val = 0; + unsigned int lookup = 0; + + char byte[6]; + + memset(&byte, 0, 6); + + /* First two bytes of digest stuffed together. + */ + + val = digest2[x]; + val <<= 8; + val += digest2[x+1]; + + lookup = (val >> 0x0b); + lookup &= 0x1f; + if (lookup >= strlen(alphabet1)) + break; + sprintf(byte, "%c", alphabet1[lookup]); + strcat(resp_6, byte); + strcat(resp_6, "="); + + lookup = (val >> 0x06); + lookup &= 0x1f; + if (lookup >= strlen(alphabet2)) + break; + sprintf(byte, "%c", alphabet2[lookup]); + strcat(resp_6, byte); + + lookup = (val >> 0x01); + lookup &= 0x1f; + if (lookup >= strlen(alphabet2)) + break; + sprintf(byte, "%c", alphabet2[lookup]); + strcat(resp_6, byte); + + lookup = (val & 0x01); + if (lookup >= strlen(delimit_lookup)) + break; + sprintf(byte, "%c", delimit_lookup[lookup]); + strcat(resp_6, byte); + } + + /* Our second authentication response is based off of the crypto hash. + */ + + cnt = 0; + memset(&digest1, 0, 20); + memset(&digest2, 0, 20); + + for (x = 0; x < (int)strlen(crypt_hash); x++) + crypt_hash_xor1[cnt++] = crypt_hash[x] ^ 0x36; + + if (cnt < 64) + memset(&(crypt_hash_xor1[cnt]), 0x36, 64-cnt); + + cnt = 0; + + for (x = 0; x < (int)strlen(crypt_hash); x++) + crypt_hash_xor2[cnt++] = crypt_hash[x] ^ 0x5c; + + if (cnt < 64) + memset(&(crypt_hash_xor2[cnt]), 0x5c, 64-cnt); + + SHA1_Init(&ctx1); + SHA1_Init(&ctx2); + + /* + * The first context gets the password hash XORed with 0x36 plus a magic value + * which we previously extrapolated from our challenge. + */ + + SHA1_Update(&ctx1, (unsigned char*)crypt_hash_xor1, 64); + if (y >= 3) + ctx1.Nl = 0x1ff; + SHA1_Update(&ctx1, magic_key_char, 4); + SHA1_Final(digest1, &ctx1); + + /* + * The second context gets the password hash XORed with 0x5c plus the SHA-1 digest + * of the first context. + */ + + SHA1_Update(&ctx2, (unsigned char*)crypt_hash_xor2, 64); + SHA1_Update(&ctx2, digest1, 20); + SHA1_Final(digest2, &ctx2); + + /* + * Now that we have digest2, use it to fetch characters from an alphabet to construct + * our first authentication response. + */ + + for (x = 0; x < 20; x += 2) { + unsigned int val = 0; + unsigned int lookup = 0; + + char byte[6]; + + memset(&byte, 0, 6); + + /* First two bytes of digest stuffed together. + */ + + val = digest2[x]; + val <<= 8; + val += digest2[x+1]; + + lookup = (val >> 0x0b); + lookup &= 0x1f; + if (lookup >= strlen(alphabet1)) + break; + sprintf(byte, "%c", alphabet1[lookup]); + strcat(resp_96, byte); + strcat(resp_96, "="); + + lookup = (val >> 0x06); + lookup &= 0x1f; + if (lookup >= strlen(alphabet2)) + break; + sprintf(byte, "%c", alphabet2[lookup]); + strcat(resp_96, byte); + + lookup = (val >> 0x01); + lookup &= 0x1f; + if (lookup >= strlen(alphabet2)) + break; + sprintf(byte, "%c", alphabet2[lookup]); + strcat(resp_96, byte); + + lookup = (val & 0x01); + if (lookup >= strlen(delimit_lookup)) + break; + sprintf(byte, "%c", delimit_lookup[lookup]); + strcat(resp_96, byte); + } + addParam(0, sn); + addParam(6, resp_6); + addParam(96, resp_96); + addParam(1, sn); + sendPacket(YAHOO_SERVICE_AUTHRESP); +} diff --git a/plugins/yahoo/yahoocfg.cpp b/plugins/yahoo/yahoocfg.cpp new file mode 100644 index 0000000..71c3314 --- /dev/null +++ b/plugins/yahoo/yahoocfg.cpp @@ -0,0 +1,91 @@ +/*************************************************************************** + yahoocfg.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#include +#include +#include +#include +#include + +#include "simgui/linklabel.h" +#include "misc.h" + +#include "yahoocfg.h" +#include "yahooclient.h" + +YahooConfig::YahooConfig(QWidget *parent, YahooClient *client, bool bConfig) : QWidget(parent) +{ + setupUi(this); + m_client = client; + m_bConfig = bConfig; + if (m_bConfig) + tabCfg->removeTab(tabCfg->indexOf(tabYahoo)); + QTimer::singleShot(0, this, SLOT(changed())); + edtLogin->setText(m_client->getLogin()); + edtPassword->setText(m_client->getPassword()); + edtServer->setText(m_client->getServer()); + edtPort->setValue(m_client->getPort()); + edtMinPort->setValue(m_client->getMinPort()); + edtMaxPort->setValue(m_client->getMaxPort()); + connect(edtLogin, SIGNAL(textChanged(const QString&)), this, SLOT(changed(const QString&))); + connect(edtPassword, SIGNAL(textChanged(const QString&)), this, SLOT(changed(const QString&))); + connect(edtServer, SIGNAL(textChanged(const QString&)), this, SLOT(changed(const QString&))); + connect(edtPort, SIGNAL(valueChanged(const QString&)), this, SLOT(changed(const QString&))); + lnkReg->setText(i18n("Get a Yahoo! ID")); + lnkReg->setUrl("http://edit.yahoo.com/config/eval_register"); + chkHTTP->setChecked(m_client->getUseHTTP()); + chkAuto->setChecked(m_client->getAutoHTTP()); + connect(chkAuto, SIGNAL(toggled(bool)), this, SLOT(autoToggled(bool))); + autoToggled(m_client->getAutoHTTP()); +} + +void YahooConfig::apply(SIM::Client*, void*) +{ +} + +void YahooConfig::apply() +{ + if (!m_bConfig){ + m_client->setLogin(edtLogin->text()); + m_client->setPassword(edtPassword->text()); + } + m_client->setServer(edtServer->text()); + m_client->setPort(edtPort->text().toUShort()); + m_client->setMinPort(edtMinPort->text().toUShort()); + m_client->setMaxPort(edtMaxPort->text().toUShort()); + m_client->setUseHTTP(chkHTTP->isChecked()); + m_client->setAutoHTTP(chkAuto->isChecked()); +} + +void YahooConfig::autoToggled(bool bState) +{ + chkHTTP->setEnabled(!bState); +} + +void YahooConfig::changed(const QString&) +{ + changed(); +} + +void YahooConfig::changed() +{ + emit okEnabled(!edtLogin->text().isEmpty() && + !edtPassword->text().isEmpty() && + !edtServer->text().isEmpty() && + edtPort->text().toUShort()); +} + diff --git a/plugins/yahoo/yahoocfg.h b/plugins/yahoo/yahoocfg.h new file mode 100644 index 0000000..7075958 --- /dev/null +++ b/plugins/yahoo/yahoocfg.h @@ -0,0 +1,47 @@ +/*************************************************************************** + yahoocfg.h - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _YAHOOCFG_H +#define _YAHOOCFG_H + +#include "contacts.h" + +#include "ui_yahoocfgbase.h" + +class YahooClient; + +class YahooConfig : public QWidget, public Ui::YahooConfigBase +{ + Q_OBJECT +public: + YahooConfig(QWidget *parent, YahooClient *client, bool bConfig); +signals: + void okEnabled(bool); +public slots: + void apply(); + void apply(SIM::Client*, void*); +protected slots: + void changed(); + void changed(const QString&); + void autoToggled(bool); +protected: + bool m_bConfig; + YahooClient *m_client; +}; + +#endif + diff --git a/plugins/yahoo/yahoocfgbase.ui b/plugins/yahoo/yahoocfgbase.ui new file mode 100644 index 0000000..a559033 --- /dev/null +++ b/plugins/yahoo/yahoocfgbase.ui @@ -0,0 +1,362 @@ + + + + + YahooConfigBase + + + + 0 + 0 + 390 + 291 + + + + Form2 + + + + 11 + + + 6 + + + + + + &Yahoo! + + + + 11 + + + 6 + + + + + Login: + + + Qt::AlignVCenter|Qt::AlignRight + + + false + + + + + + + + + + Password: + + + Qt::AlignVCenter|Qt::AlignRight + + + false + + + + + + + QLineEdit::Password + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Vertical + + + + + + + + + + + &Network + + + + 11 + + + 6 + + + + + Server: + + + Qt::AlignVCenter|Qt::AlignRight + + + false + + + + + + + + + + 0 + + + 6 + + + + + 65535 + + + 1 + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Horizontal + + + + + + + + + Port: + + + Qt::AlignVCenter|Qt::AlignRight + + + false + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Vertical + + + + + + + + 5 + 1 + + + + Note: For HTTP-polling using proxy settings for HTTP + + + Qt::AlignVCenter|Qt::AlignLeft + + + false + + + + + + + &Automatically use HTTP polling if proxy required + + + + + + + Use &HTTP polling + + + + + + + QFrame::HLine + + + QFrame::Sunken + + + QFrame::HLine + + + + + + + 0 + + + 6 + + + + + 65534 + + + 1024 + + + + + + + - + + + false + + + + + + + 65534 + + + 1024 + + + + + + + + 20 + 20 + + + + QSizePolicy::Expanding + + + Qt::Horizontal + + + + + + + + + Port range for direct connections: + + + false + + + + + + + + + + + + QWidget + QWidget +
QWidget
+ + -1 + -1 + + 0 + + 5 + 5 + + image0 + + text + +
+ + LinkLabel + QWidget +
simgui/linklabel.h
+ + -1 + -1 + + 0 + + 1 + 1 + + image1 + + text + +
+
+ + tabCfg + edtLogin + edtPassword + edtServer + edtPort + edtMinPort + edtMaxPort + chkHTTP + chkAuto + + + + 789c6dd2c10ac2300c00d07bbf2234b7229d1be245fc04c5a3201e4615f430059d0711ff5ddb2e6bb236ec90eed134cb5a19d8ef36602af5ecdbfeeac05dda0798d3abebde87e3faa374d3807fa0d633a52d38d8de6f679fe33fc776e196f53cd010188256a3600a292882096246517815ca99884606e18044a3a40d91824820924265a7923a2e8bcd05f33db1173e002913175f2a6be6d3294871a2d95fa00e8a94ee017b69d339d90df1e77c57ea072ede6758 + + + 789c6dd2c10ac2300c00d07bbf2234b7229d1ddec44f503c0ae2a154410f53d0ed20e2bf6bdb656dd6861dd23d9a66591b0587fd1654235ebded6f0edcd53e419d87ae7b1f4f9b8f906d0bfe012317426a70b07bdc2f3ec77f8ed6b89559061a0343d06a124cc105596482585094bc0ae599b04646c9018926491b2205e140c485cace25755c175d0a967b622ff900b8cc9c7d29af594ea722d589167f813aa852ba07d94b9dce296e883fe7bb163f23896753 + + +
diff --git a/plugins/yahoo/yahooclient.cpp b/plugins/yahoo/yahooclient.cpp new file mode 100644 index 0000000..906454d --- /dev/null +++ b/plugins/yahoo/yahooclient.cpp @@ -0,0 +1,2155 @@ +/*************************************************************************** + yahooclient.cpp - description + ------------------- + begin : Sun Mar 17 2002 + copyright : (C) 2002 by Vladimir Shutoff + email : vovan@shutoff.ru + ***************************************************************************/ + +/*************************************************************************** + * Based on libyahoo2 + * + * Some code copyright (C) 2002-2004, Philip S Tellis + * + * Yahoo Search copyright (C) 2003, Konstantin Klyagin + * + * Much of this code was taken and adapted from the yahoo module for + * gaim released under the GNU GPL. This code is also released under the + * GNU GPL. + * + * This code is derivitive of Gaim + * copyright (C) 1998-1999, Mark Spencer + * 1998-1999, Adam Fritzler + * 1998-2002, Rob Flynn + * 2000-2002, Eric Warmenhoven + * 2001-2002, Brian Macke + * 2001, Anand Biligiri S + * 2001, Valdis Kletnieks + * 2002, Sean Egan + * 2002, Toby Gray + * + * * + * 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. * + * * + ***************************************************************************/ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "html.h" +#include "icons.h" +#include "log.h" +#include "unquot.h" +#include "core.h" +#include "socket/clientsocket.h" +#include "contacts/clientdataiterator.h" +#include "contacts/contact.h" +#include "contacts/group.h" + +#include "yahoo.h" +#include "yahooclient.h" +#include "yahoocfg.h" +#include "yahooinfo.h" +#include "yahoosearch.h" + +using namespace std; +using namespace SIM; + +const unsigned long MessageYahooFile = 0x700; + +static char YAHOO_PACKET_SIGN[] = "YMSG"; + +const unsigned PING_TIMEOUT = 60; + +const unsigned YAHOO_LOGIN_OK = 0; +const unsigned YAHOO_LOGIN_PASSWD = 13; +const unsigned YAHOO_LOGIN_LOCK = 14; +const unsigned YAHOO_LOGIN_DUPL = 99; + +static DataDef yahooUserData[] = + { + { "", DATA_ULONG, 1, DATA(9) }, // Sign + { "LastSend", DATA_ULONG, 1, 0 }, + { "Login", DATA_UTF, 1, 0 }, + { "Nick", DATA_UTF, 1, 0 }, + { "First", DATA_UTF, 1, 0 }, + { "Last", DATA_UTF, 1, 0 }, + { "EMail", DATA_UTF, 1, 0 }, + { "", DATA_ULONG, 1, DATA(-1) }, // Status + { "", DATA_BOOL, 1, 0 }, // bAway + { "", DATA_UTF, 1, 0 }, // AwayMessage + { "StatusTime", DATA_ULONG, 1, 0 }, + { "OnlineTime", DATA_ULONG, 1, 0 }, + { "Group", DATA_STRING, 1, 0 }, + { "", DATA_BOOL, 1, 0 }, // bChecked + { "", DATA_BOOL, 1, 0 }, // bTyping + { NULL, DATA_UNKNOWN, 0, 0 } + }; + +static DataDef yahooClientData[] = + { + { "Server", DATA_STRING, 1, "scs.msg.yahoo.com" }, + { "Port", DATA_ULONG, 1, DATA(5050) }, + { "MinPort", DATA_ULONG, 1, DATA(1024) }, + { "MaxPort", DATA_ULONG, 1, DATA(0xFFFE) }, + { "UseHTTP", DATA_BOOL, 1, 0 }, + { "AutoHTTP", DATA_BOOL, 1, DATA(1) }, + { "ListRequests", DATA_STRING, 1, 0 }, + { "", DATA_STRUCT, sizeof(YahooUserData) / sizeof(Data), DATA(yahooUserData) }, + { NULL, DATA_UNKNOWN, 0, 0 } + }; + +const DataDef *YahooProtocol::userDataDef() +{ + return yahooUserData; +} + +YahooClient::YahooClient(Protocol *protocol, Buffer *cfg) + : TCPClient(protocol, cfg) +{ + load_data(yahooClientData, &data, cfg); + m_status = STATUS_OFFLINE; + m_bFirstTry = false; + m_ft_id = 0; + QString requests = getListRequests(); + while (!requests.isEmpty()){ + QString request = getToken(requests, ';'); + ListRequest lr; + lr.type = getToken(request, ',').toUInt(); + lr.name = request; + m_requests.push_back(lr); + } + setListRequests(QString::null); +} + +YahooClient::~YahooClient() +{ + TCPClient::setStatus(STATUS_OFFLINE, false); + free_data(yahooClientData, &data); +} + +QByteArray YahooClient::getConfig() +{ + QByteArray res = TCPClient::getConfig(); + if (res.length()) + res += "\n"; + QString requests; + for (list::iterator it = m_requests.begin(); it != m_requests.end(); ++it){ + if (!requests.isEmpty()) + requests += ";"; + requests += QString::number(it->type); + requests += it->name; + } + setListRequests(requests); + res += save_data(yahooClientData, &data); + return res; +} + +bool YahooClient::send(Message *msg, void *_data) +{ + if ((getState() != Connected) || (_data == NULL)) + return false; + YahooUserData *data = toYahooUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + Message_ID msg_id; + switch (msg->type()){ + case MessageTypingStart: + sendTyping(data, true); + return true; + case MessageTypingStop: + sendTyping(data, false); + return true; + case MessageGeneric: + sendMessage(msg->getRichText(), msg, data); + return true; + case MessageUrl:{ + QString msgText = static_cast(msg)->getUrl(); + if (!msg->getPlainText().isEmpty()){ + msgText += "
"; + msgText += msg->getRichText(); + } + sendMessage(msgText, msg, data); + return true; + } + case MessageFile:{ + msg_id.id = 0; + msg_id.msg = msg; + m_waitMsg.push_back(msg_id); + YahooFileTransfer *ft = static_cast(static_cast(msg)->m_transfer); + if (ft == NULL) + ft = new YahooFileTransfer(static_cast(msg), data, this); + ft->listen(); + return true; + } + } + return false; +} + +bool YahooClient::canSend(unsigned type, void *_data) +{ + if ((_data == NULL) || (((clientData*)_data)->Sign.toULong() != YAHOO_SIGN)) + return false; + if (getState() != Connected) + return false; + switch (type){ + case MessageGeneric: + case MessageUrl: + case MessageFile: + return true; + } + return false; +} + +void YahooClient::packet_ready() +{ + if (m_bHeader){ + char header[4]; + socket()->readBuffer().unpack(header, 4); + if (memcmp(header, YAHOO_PACKET_SIGN, 4)){ + socket()->error_state("Bad packet sign"); + return; + } + socket()->readBuffer().incReadPos(4); + socket()->readBuffer() >> m_data_size >> m_service; + unsigned long session_id; + socket()->readBuffer() >> m_pkt_status >> session_id; + if (m_data_size){ + socket()->readBuffer().add(m_data_size); + m_bHeader = false; + return; + } + } + EventLog::log_packet(socket()->readBuffer(), false, YahooPlugin::YahooPacket); + scan_packet(); + socket()->readBuffer().init(20); + socket()->readBuffer().packetStart(); + m_bHeader = true; +} + +void YahooClient::sendPacket(unsigned short service, unsigned long status) +{ + if (m_bHTTP && !m_session_id.isEmpty()){ + addParam(0, getLogin()); + addParam(24, m_session_id); + } + unsigned short size = 0; + if (!m_values.empty()){ + for (list::iterator it = m_values.begin(); it != m_values.end(); ++it){ + size += 4; + size += it->second.length(); + size += QByteArray::number(it->first).length(); + } + } + socket()->writeBuffer().packetStart(); + socket()->writeBuffer().pack(YAHOO_PACKET_SIGN, 4); + socket()->writeBuffer() << 0x000C0000L << size << service << status << m_session; + if (size){ + for (list::iterator it = m_values.begin(); it != m_values.end(); ++it){ + socket()->writeBuffer() + << QByteArray::number(it->first).constData() + << (unsigned short)0xC080 + << it->second.constData() + << (unsigned short)0xC080; + } + } + m_values.clear(); + EventLog::log_packet(socket()->writeBuffer(), true, YahooPlugin::YahooPacket); + socket()->write(); +} + +void YahooClient::addParam(unsigned key, const char *value) +{ + m_values.push_back(PARAM(key, QByteArray(value))); +} + +void YahooClient::addParam(unsigned key, const QByteArray &value) +{ + m_values.push_back(PARAM(key, value)); +} + +void YahooClient::addParam(unsigned key, const QString &value) +{ + m_values.push_back(PARAM(key, value.toUtf8())); +} + +void YahooClient::connect_ready() +{ + m_bFirstTry = false; + socket()->readBuffer().init(20); + socket()->readBuffer().packetStart(); + m_session = rand(); + m_bHeader = true; + log(L_DEBUG, "Connect ready"); + TCPClient::connect_ready(); + if (m_bHTTP){ + addParam(1, getLogin()); + sendPacket(YAHOO_SERVICE_AUTH); + }else{ + sendPacket(YAHOO_SERVICE_VERIFY); + } +} + +const char *Params::operator [](unsigned id) +{ + for (iterator it = begin(); it != end(); ++it){ + if (it->first == id) + return it->second.data(); + } + return ""; +} + +void YahooClient::scan_packet() +{ + Params params; + int param7_cnt = 0; + + for (;;){ + QByteArray key; + QByteArray value; + if (!(socket()->readBuffer().scan("\xC0\x80", key) && + socket()->readBuffer().scan("\xC0\x80", value))) + break; + unsigned key_id = key.toUInt(); + log(L_DEBUG, "Param: %u %s", key_id, value.data()); + /* There can be multiple buddies in an YAHOO_SERVICE_IDDEACT and + YAHOO_SERVICE_LOGON paket ... */ + if ((key_id == 7) && ((m_service == YAHOO_SERVICE_IDDEACT) || + (m_service == YAHOO_SERVICE_LOGON))) { + if (param7_cnt) { + /* process the last buddie */ + process_packet(params); + params.clear(); + param7_cnt = 0; + } else { + param7_cnt = 1; + } + } + params.push_back(PARAM(key_id, value)); + } + process_packet(params); +} + +void YahooClient::process_packet(Params ¶ms) +{ + log(L_DEBUG,"Service type: %02X",m_service); + switch (m_service){ + case YAHOO_SERVICE_VERIFY: + if (m_pkt_status != 1){ + m_reconnect = NO_RECONNECT; + socket()->error_state(I18N_NOOP("Yahoo! login lock")); + return; + } + addParam(1, getLogin()); + sendPacket(YAHOO_SERVICE_AUTH); + break; + case YAHOO_SERVICE_AUTH: + process_auth(params[13], params[94], params[1]); + break; + case YAHOO_SERVICE_AUTHRESP: + m_pkt_status = 0; + if (params[66]) + m_pkt_status = atol(params[66]); + switch (m_pkt_status){ + case YAHOO_LOGIN_OK: + authOk(); + return; + case YAHOO_LOGIN_PASSWD: + m_reconnect = NO_RECONNECT; + socket()->error_state(I18N_NOOP("Wrong password"), AuthError); + return; + case YAHOO_LOGIN_LOCK: + m_reconnect = NO_RECONNECT; + socket()->error_state(I18N_NOOP("Your account has been locked"), AuthError); + return; + case YAHOO_LOGIN_DUPL: + m_reconnect = NO_RECONNECT; + socket()->error_state(I18N_NOOP("Your account is being used from another location")); + return; + default: + socket()->error_state(I18N_NOOP("Login failed")); + } + break; + case YAHOO_SERVICE_LIST: + authOk(); + loadList(params[87]); + break; + case YAHOO_SERVICE_LOGOFF: + if (m_pkt_status == (unsigned long)(-1)){ + m_reconnect = NO_RECONNECT; + socket()->error_state(I18N_NOOP("Your account is being used from another location")); + return; + } + case YAHOO_SERVICE_LOGON: + if (params[1]){ + if (params[24]) + m_session_id = QString::fromUtf8(params[24]); + authOk(); + } + case YAHOO_SERVICE_USERSTAT: + case YAHOO_SERVICE_ISAWAY: + case YAHOO_SERVICE_ISBACK: + case YAHOO_SERVICE_GAMELOGON: + case YAHOO_SERVICE_GAMELOGOFF: + case YAHOO_SERVICE_IDACT: + case YAHOO_SERVICE_IDDEACT: + if (params[7] && params[13]) + processStatus(m_service, params[7], params[10], params[19], params[47], params[137]); + break; + case YAHOO_SERVICE_IDLE: + case YAHOO_SERVICE_MAILSTAT: + case YAHOO_SERVICE_CHATINVITE: + case YAHOO_SERVICE_CALENDAR: + case YAHOO_SERVICE_NEWPERSONALMAIL: + case YAHOO_SERVICE_ADDIDENT: + case YAHOO_SERVICE_ADDIGNORE: + case YAHOO_SERVICE_PING: + case YAHOO_SERVICE_GOTGROUPRENAME: + case YAHOO_SERVICE_GROUPRENAME: + case YAHOO_SERVICE_PASSTHROUGH2: + case YAHOO_SERVICE_CHATLOGON: + case YAHOO_SERVICE_CHATLOGOFF: + case YAHOO_SERVICE_CHATMSG: + case YAHOO_SERVICE_REJECTCONTACT: + case YAHOO_SERVICE_PEERTOPEER: + break; + case YAHOO_SERVICE_MESSAGE: + if (params[4] && params[14]) + process_message(params[4], params[14], params[97]); + break; + case YAHOO_SERVICE_NOTIFY: + if (params[4] && params[49]) + notify(params[4], params[49], params[13]); + break; + case YAHOO_SERVICE_NEWCONTACT: + if (params[1]){ + contact_added(params[3], params[14]); + return; + } + if (params[7]){ + processStatus(m_service, params[7], params[10], params[14], params[47], params[137]); + return; + } + if (m_pkt_status == 7) + contact_rejected(params[3], params[14]); + break; + case YAHOO_SERVICE_P2PFILEXFER: + if ((params[49] == NULL) || strcmp(params[49], "FILEXFER")){ + log(L_WARN, "Unhandled p2p type %s", params[49]); + break; + } + if ((params[28] == NULL) && params[11]){ + unsigned id =atol(params[11]); + for (list::iterator it = m_waitMsg.begin(); it != m_waitMsg.end(); ++it){ + if (it->id == id){ + FileMessage *msg = static_cast(it->msg); + m_waitMsg.erase(it); + if (msg->m_transfer){ + static_cast(msg->m_transfer)->error_state(I18N_NOOP("Message declined"), 0); + break; + } + msg->setError(I18N_NOOP("Message declined")); + EventMessageSent(msg).process(); + delete msg; + break; + } + } + break; + } + case YAHOO_SERVICE_FILETRANSFER: + /* + + params[14] - can be empty when no message is send with the file... + params[20] - url - just for filetransfer through website + */ + if (params[4] && params[27] && params[28]) + process_file(params[4], params[27], params[28], params[14], params[20], params[11]); + else + /* file-url-message */ + process_fileurl(params[4],params[14],params[20]); + break; + case YAHOO_SERVICE_ADDBUDDY: + if (params[1] && params[7] && params[65]) + log(L_DEBUG,"%s added %s to group %s",params[1],params[7],params[65]); + else + log(L_DEBUG,"Please send paket to developer!"); + break; + case YAHOO_SERVICE_REMBUDDY: + if (params[1] && params[7] && params[65]) + log(L_DEBUG,"%s removed %s from group %s",params[1],params[7],params[65]); + else + log(L_DEBUG,"Please send paket to developer!"); + break; + case YAHOO_SERVICE_CONFINVITE: + log(L_WARN, "Conferencing currently not implemented!"); + default: + log(L_WARN, "Unknown service %02X", m_service); + } +} + +class TextParser +{ +public: + TextParser(YahooClient *client, Contact *contact); + QString parse(const char *msg); + + class Tag + { + public: + Tag(const QString &str); + bool operator == (const Tag &t) const; + QString open_tag() const; + QString close_tag() const; + protected: + QString m_tag; + }; + +class FaceSizeParser : public HTMLParser + { + public: + FaceSizeParser(const QString&); + QString face; + QString size; + protected: + virtual void text(const QString &text); + virtual void tag_start(const QString &tag, const list &options); + virtual void tag_end(const QString &tag); + }; + +protected: + void addText(const char *str, unsigned size); + unsigned m_state; + Contact *m_contact; + QString color; + QString face; + QString size; + bool m_bChanged; + stack m_tags; + void setState(unsigned code, bool bSet); + void clearState(unsigned code); + void put_color(unsigned color); + void put_style(); + void push_tag(const QString &tag); + void pop_tag(const QString &tag); + YahooClient *m_client; + QString m_text; +}; + +TextParser::FaceSizeParser::FaceSizeParser(const QString &str) +{ + parse(str); +} + +void TextParser::FaceSizeParser::text(const QString&) +{ +} + +void TextParser::FaceSizeParser::tag_start(const QString &tag, const list &options) +{ + if (tag != "font") + return; + for (list::const_iterator it = options.begin(); it != options.end(); ++it){ + QString key = *it; + ++it; + if (key == "face") + face = QString("font-family:") + *it; + if (key == "size") + size = QString("font-size:") + *it + "pt"; + } +} + +void TextParser::FaceSizeParser::tag_end(const QString&) +{ +} + +TextParser::Tag::Tag(const QString &tag) +{ + m_tag = tag; +} + +bool TextParser::Tag::operator == (const Tag &t) const +{ + return close_tag() == t.close_tag(); +} + +QString TextParser::Tag::open_tag() const +{ + QString res; + res += "<"; + res += m_tag; + res += ">"; + return res; +} + +QString TextParser::Tag::close_tag() const +{ + int n = m_tag.indexOf(' '); + QString res; + res += "= 0){ + res += m_tag.left(n); + }else{ + res += m_tag; + } + res += ">"; + return res; +} + +TextParser::TextParser(YahooClient *client, Contact *contact) +{ + m_contact = contact; + m_client = client; + m_bChanged = false; + m_state = 0; +} + +static unsigned esc_colors[] = + { + 0x000000, + 0x0000FF, + 0x008080, + 0x808080, + 0x008000, + 0xFF0080, + 0x800080, + 0xFF8000, + 0xFF0000, + 0x808000 + }; + +QString TextParser::parse(const char *msg) +{ + Buffer b; + b.pack(msg, strlen(msg)); + for (;;){ + QByteArray part; + if (!b.scan("\x1B\x5B", part)) + break; + addText(part, part.length()); + + if (!b.scan("m", part)) + break; + if (part.isEmpty()) + continue; + if (part[0] == 'x'){ + unsigned code = part.mid(1).toUInt(); + switch (code){ + case 1: + case 2: + case 4: + setState(code, false); + break; + } + continue; + } + if (part[0] == '#'){ + put_color(part.mid(1).toUInt()); + continue; + } + unsigned code = part.toUInt(); + switch (code){ + case 1: + case 2: + case 4: + setState(code, true); + break; + default: + if ((code >= 30) && (code < 40)) + put_color(esc_colors[code - 30]); + } + } + addText(b.data(b.readPos()), b.writePos() - b.readPos()); + while (!m_tags.empty()){ + m_text += m_tags.top().close_tag(); + m_tags.pop(); + } + return m_text; +} + +void TextParser::setState(unsigned code, bool bSet) +{ + if (bSet){ + if ((m_state & code) == code) + return; + m_state |= code; + }else{ + if ((m_state & code) == 0) + return; + m_state &= ~code; + } + QString tag; + switch (code){ + case 1: + tag = "b"; + break; + case 2: + tag = "i"; + break; + case 4: + tag = "u"; + break; + default: + return; + } + if (bSet){ + push_tag(tag); + }else{ + pop_tag(tag); + } +} + +void TextParser::put_color(unsigned _color) +{ + color.sprintf("color:#%06X", _color & 0xFFFFFF); + m_bChanged = true; +} + +void TextParser::put_style() +{ + if (!m_bChanged) + return; + m_bChanged = false; + QString style; + if (!color.isEmpty()) + style = color; + if (!face.isEmpty()){ + if (!style.isEmpty()) + style += ";"; + style += face; + } + if (!size.isEmpty()){ + if (!style.isEmpty()) + style += ";"; + style += size; + } + QString tag("span style=\""); + tag += style; + tag += "\""; + pop_tag(tag); + push_tag(tag); +} + +void TextParser::push_tag(const QString &tag) +{ + Tag t(tag); + m_tags.push(t); + m_text += t.open_tag(); +} + +void TextParser::pop_tag(const QString &tag) +{ + Tag t(tag); + stack tags; + bool bFound = false; + QString text; + while (!m_tags.empty()){ + Tag top = m_tags.top(); + m_tags.pop(); + text += top.close_tag(); + if (top == t){ + bFound = true; + break; + } + tags.push(top); + } + if (bFound) + m_text += text; + while (!tags.empty()){ + Tag top = tags.top(); + tags.pop(); + if (bFound) + m_text += top.open_tag(); + m_tags.push(top); + } +} + +void TextParser::addText(const char *str, unsigned s) +{ + if (s == 0) + return; + QString text; + if (m_contact){ + text = getContacts()->toUnicode(m_contact, QByteArray::fromRawData(str, s)); + }else{ + text = QString::fromUtf8(str, s); + } + while (!text.isEmpty()){ + bool bFace = false; + int n1 = text.indexOf("= 0) + n = n1; + if ((n2 >= 0) && ((n == -1) || (n2 < n1))){ + n = n2; + bFace = true; + } + if (n < 0){ + if (!text.isEmpty()) + put_style(); + m_text += quoteString(text); + break; + } + if (n) + put_style(); + m_text += quoteString(text.left(n)); + text = text.mid(n); + n = text.indexOf('>'); + if (n < 0) + break; + FaceSizeParser p(text.left(n + 1)); + text = text.mid(n + 1); + if (!p.face.isEmpty()){ + face = p.face; + m_bChanged = true; + } + if (!p.size.isEmpty()){ + size = p.size; + m_bChanged = true; + } + } +} + +void YahooClient::process_message(const char *id, const char *msg, const char *utf) +{ + bool bUtf = false; + if (utf && atol(utf)) + bUtf = true; + Contact *contact = NULL; + if (utf == NULL){ + if (findContact(id, NULL, contact) == NULL) + contact = getContacts()->owner(); + } + Message *m = new Message(MessageGeneric); + m->setFlags(MESSAGE_RICHTEXT); + TextParser parser(this, contact); + m->setText(parser.parse(msg)); + messageReceived(m, id); +} + +void YahooClient::notify(const char *id, const char *msg, const char *state) +{ + Contact *contact; + YahooUserData *data = findContact(id, NULL, contact); + if (data == NULL) + return; + bool bState = false; + if (state && atol(state)) + bState = true; + if (!qstricmp(msg, "TYPING")){ + if (data->bTyping.toBool() != bState){ + data->bTyping.asBool() = bState; + EventContact e(contact, EventContact::eStatus);; + e.process(); + } + } +} + +void YahooClient::contact_added(const char *id, const char *message) +{ + Message *msg = new AuthMessage(MessageAdded); + if (message) + msg->setText(QString::fromUtf8(message)); + messageReceived(msg, id); +} + +void YahooClient::contact_rejected(const char *id, const char *message) +{ + Message *msg = new AuthMessage(MessageRemoved); + if (message) + msg->setText(QString::fromUtf8(message)); + messageReceived(msg, id); +} + +void YahooClient::processStatus(unsigned short service, const char *id, + const char *_state, const char *_msg, + const char *_away, const char *_idle) +{ + Contact *contact; + YahooUserData *data = findContact(id, NULL, contact); + if (data == NULL) + return; + unsigned long state = 0; + unsigned away = 0; + int idle = 0; + if (_state) + state = atol(_state); + if (_away) + away = atol(_away); + if (_idle) + idle = atol(_idle); + if (service == YAHOO_SERVICE_LOGOFF) + state = YAHOO_STATUS_OFFLINE; + if ((state != data->Status.toULong()) || + ((state == YAHOO_STATUS_CUSTOM) && + (((away != 0) != data->bAway.toBool()) || QString::fromUtf8(_msg) != data->AwayMessage.str()))){ + + unsigned long old_status = STATUS_UNKNOWN; + unsigned style = 0; + QString statusIcon; + contactInfo(data, old_status, style, statusIcon); + + QDateTime now(QDateTime::currentDateTime()); + now = now.addSecs(-idle); + if (data->Status.toULong() == YAHOO_STATUS_OFFLINE) + data->OnlineTime.asULong() = now.toTime_t(); + data->Status.asULong() = state; + data->bAway.asBool() = (away != 0); + data->StatusTime.asULong() = now.toTime_t(); + + unsigned long new_status = STATUS_UNKNOWN; + contactInfo(data, new_status, style, statusIcon); + + if (old_status != new_status){ + StatusMessage *m = new StatusMessage(); + m->setContact(contact->id()); + m->setClient(dataName(data)); + m->setFlags(MESSAGE_RECEIVED); + m->setStatus(STATUS_OFFLINE); + EventMessageReceived e(m); + if(!e.process()) + delete m; + if ((new_status == STATUS_ONLINE) && !contact->getIgnore() && (getState() == Connected) && + (data->StatusTime.toULong() > this->data.owner.OnlineTime.toULong() + 30)){ + EventContact e(contact, EventContact::eOnline); + e.process(); + } + }else{ + EventContact e(contact, EventContact::eStatus);; + e.process(); + } + } +} + +QString YahooClient::name() +{ + return "Yahoo." + data.owner.Login.str(); +} + +QString YahooClient::dataName(void *_data) +{ + YahooUserData *data = toYahooUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + return name() + "+" + data->Login.str(); +} + +void YahooClient::setStatus(unsigned status) +{ + if (status == m_status) + return; + QDateTime now(QDateTime::currentDateTime()); + if (m_status == STATUS_OFFLINE) + data.owner.OnlineTime.asULong() = now.toTime_t(); + data.owner.StatusTime.asULong() = now.toTime_t(); + m_status = status; + data.owner.Status.asULong() = m_status; + EventClientChanged(this).process(); + if (status == STATUS_OFFLINE){ + if (m_status != STATUS_OFFLINE){ + m_status = status; + data.owner.Status.asULong() = status; + data.owner.StatusTime.asULong() = time(NULL); + } + return; + } + unsigned long yahoo_status = YAHOO_STATUS_OFFLINE; + switch (status){ + case STATUS_ONLINE: + yahoo_status = YAHOO_STATUS_AVAILABLE; + break; + case STATUS_DND: + yahoo_status = YAHOO_STATUS_BUSY; + break; + } + if (yahoo_status != YAHOO_STATUS_OFFLINE){ + m_status = status; + sendStatus(yahoo_status); + return; + } + ARRequest ar; + ar.contact = NULL; + ar.status = status; + ar.receiver = this; + ar.param = (void*)(unsigned long)status; + EventARRequest(&ar).process(); +} + +void YahooClient::process_file(const char *id, const char *fileName, const char *fileSize, const char *msg, const char *url, const char *msgid) +{ + YahooFileMessage *m = new YahooFileMessage; + m->setDescription(getContacts()->toUnicode(NULL, fileName)); + m->setSize(atol(fileSize)); + if (url) + m->setUrl(url); + if (msg) + m->setServerText(msg); + if (msgid) + m->setMsgID(atol(msgid)); + messageReceived(m, id); +} + +void YahooClient::process_fileurl(const char *id, const char *msg, const char *url) +{ + UrlMessage *m = new UrlMessage(MessageUrl); + + if (msg) + m->setServerText(msg); + m->setUrl(url); + messageReceived(m, id); +} + +void YahooClient::disconnected() +{ + m_values.clear(); + m_session_id.clear(); + Contact *contact; + ContactList::ContactIterator it; + while ((contact = ++it) != NULL){ + YahooUserData *data; + ClientDataIterator it(contact->clientData, this); + while ((data = toYahooUserData(++it)) != NULL){ + if (data->Status.toULong() != YAHOO_STATUS_OFFLINE){ + data->Status.asULong() = YAHOO_STATUS_OFFLINE; + StatusMessage *m = new StatusMessage(); + m->setContact(contact->id()); + m->setClient(dataName(data)); + m->setStatus(STATUS_OFFLINE); + m->setFlags(MESSAGE_RECEIVED); + EventMessageReceived e(m); + if(!e.process()) + delete m; + } + } + } + list::iterator itm; + for (itm = m_ackMsg.begin(); itm != m_ackMsg.end(); ++itm){ + Message *msg = *itm; + EventMessageDeleted(msg).process(); + delete msg; + } + list::iterator itw; + for (itw = m_waitMsg.begin(); itw != m_waitMsg.end(); itw = m_waitMsg.begin()){ + Message *msg = itw->msg; + msg->setError(I18N_NOOP("Client go offline")); + EventMessageSent(msg).process(); + delete msg; + } +} + +bool YahooClient::isMyData(clientData *&_data, Contact*&contact) +{ + if (_data->Sign.toULong() != YAHOO_SIGN) + return false; + YahooUserData *data = toYahooUserData(_data); + YahooUserData *my_data = findContact(data->Login.str().toUtf8(), NULL, contact); + if (!my_data){ + contact = NULL; + } + return true; +} + +bool YahooClient::createData(clientData *&_data, Contact *contact) +{ + YahooUserData *data = toYahooUserData(_data); + YahooUserData *new_data = toYahooUserData((SIM::clientData*)contact->clientData.createData(this)); // FIXME unsafe type conversion + new_data->Nick.str() = data->Nick.str(); + _data = (clientData*)new_data; + return true; +} + +void YahooClient::setupContact(Contact*, void*) +{ +} + +QWidget *YahooClient::setupWnd() +{ + return new YahooConfig(NULL, this, false); +} + +QString YahooClient::getLogin() +{ + return data.owner.Login.str(); +} + +void YahooClient::setLogin(const QString &login) +{ + data.owner.Login.str() = login; +} + +void YahooClient::authOk() +{ + if (getState() == Connected) + return; + if (m_bHTTP && m_session_id.isEmpty()) + return; + setState(Connected); + setPreviousPassword(QString::null); + setStatus(m_logonStatus); + QTimer::singleShot(PING_TIMEOUT * 1000, this, SLOT(ping())); +} + +void YahooClient::loadList(const char *str) +{ + Contact *contact; + ContactList::ContactIterator it; + while ((contact = ++it) != NULL){ + YahooUserData *data; + ClientDataIterator itd(contact->clientData, this); + while ((data = toYahooUserData(++itd)) != NULL){ + data->bChecked.asBool() = (contact->getGroup() == 0); + } + } + if (str){ + QByteArray s = str; + while (!s.isEmpty()){ + QByteArray line = getToken(s, '\n'); + QByteArray grp = getToken(line, ':'); + if (line.isEmpty()){ + line = grp; + grp = ""; + } + while (!line.isEmpty()){ + QByteArray id = getToken(line, ','); + ListRequest *lr = findRequest(QString::fromUtf8(id)); + if (lr) + continue; + Contact *contact; + YahooUserData *data = findContact(id, grp, contact, false); + QString grpName; + if (contact->getGroup()){ + Group *grp = getContacts()->group(contact->getGroup()); + if (grp) + grpName = grp->getName(); + } + if (grpName != getContacts()->toUnicode(NULL, grp)) + moveBuddy(data, getContacts()->toUnicode(NULL, grp)); + data->bChecked.asBool() = true; + } + } + } + it.reset(); + for (list::iterator itl = m_requests.begin(); itl != m_requests.end(); ++itl){ + if ((*itl).type == LR_CHANGE){ + YahooUserData *data = findContact((*itl).name.toUtf8(), NULL, contact, false); + if (data){ + data->bChecked.asBool() = true; + QString grpName; + if (contact->getGroup()){ + Group *grp = getContacts()->group(contact->getGroup()); + if (grp) + grpName = grp->getName(); + } + if (grpName != data->Group.str()) + moveBuddy(data, grpName); + } + } + if ((*itl).type == LR_DELETE){ + YahooUserData data; + load_data(yahooUserData, &data, NULL); + data.Login.str() = (*itl).name; + removeBuddy(&data); + free_data(yahooUserData, &data); + } + } + m_requests.clear(); + list forRemove; + while ((contact = ++it) != NULL){ + YahooUserData *data; + ClientDataIterator itd(contact->clientData, this); + list dataForRemove; + bool bChanged = false; + while ((data = toYahooUserData(++itd)) != NULL){ + if (!data->bChecked.toBool()){ + dataForRemove.push_back(data); + bChanged = true; + } + } + if (!bChanged) + continue; + for (list::iterator it = dataForRemove.begin(); it != dataForRemove.end(); ++it) + contact->clientData.freeData(*it); + if (contact->clientData.size()){ + EventContact e(contact, EventContact::eChanged); + e.process(); + }else{ + forRemove.push_back(contact); + } + } + for (list::iterator itr = forRemove.begin(); itr != forRemove.end(); ++itr) + delete *itr; +} + +YahooUserData *YahooClient::findContact(const char *_id, const char *grpname, Contact *&contact, bool bSend, bool bJoin) +{ + ContactList::ContactIterator it; + QString id = QString::fromUtf8(_id); + while ((contact = ++it) != NULL){ + YahooUserData *data; + ClientDataIterator itd(contact->clientData, this); + while ((data = toYahooUserData(++itd)) != NULL){ + if (id == data->Login.str()) + return data; + } + } + it.reset(); + if (bJoin){ + while ((contact = ++it) != NULL){ + if (contact->getName() == id){ + YahooUserData *data = toYahooUserData((SIM::clientData*)contact->clientData.createData(this)); // FIXME unsafe type conversion + data->Login.str() = id; + data->Group.str() = QString::fromUtf8(grpname); + EventContact e(contact, EventContact::eChanged); + e.process(); + return data; + } + } + } + if (grpname == NULL) + return NULL; + Group *grp = NULL; + if (*grpname){ + ContactList::GroupIterator it; + while ((grp = ++it) != NULL) + if (grp->getName() == getContacts()->toUnicode(NULL, grpname)) + break; + if (grp == NULL){ + grp = getContacts()->group(0, true); + grp->setName(getContacts()->toUnicode(NULL, grpname)); + EventGroup e(grp, EventGroup::eChanged); + e.process(); + } + } + if (grp == NULL) + grp = getContacts()->group(0); + contact = getContacts()->contact(0, true); + YahooUserData *data = toYahooUserData((SIM::clientData*)contact->clientData.createData(this)); // FIXME unsafe type conversion + data->Login.str() = id; + contact->setName(id); + contact->setGroup(grp->id()); + EventContact e(contact, EventContact::eChanged); + e.process(); + if (bSend) + addBuddy(data); + return data; +} + +void YahooClient::messageReceived(Message *msg, const char *id) +{ + msg->setFlags(msg->getFlags() | MESSAGE_RECEIVED); + if (msg->contact() == 0){ + Contact *contact; + YahooUserData *data = findContact(id, NULL, contact); + if (data == NULL){ + data = findContact(id, "", contact); + if (data == NULL){ + delete msg; + return; + } + contact->setFlags(CONTACT_TEMP); + EventContact e(contact, EventContact::eChanged); + e.process(); + } + msg->setClient(dataName(data)); + msg->setContact(contact->id()); + } + bool bAck = (msg->type() == MessageYahooFile); + if (bAck){ + msg->setFlags(msg->getFlags() | MESSAGE_TEMP); + m_ackMsg.push_back(msg); + } + EventMessageReceived e(msg); + if (e.process() && bAck){ + for (list::iterator it = m_ackMsg.begin(); it != m_ackMsg.end(); ++it){ + if ((*it) == msg){ + m_ackMsg.erase(it); + break; + } + } + } +} + +static void addIcon(QSet *s, const QString &icon, const QString &statusIcon) +{ + if (!s || statusIcon == icon) + return; + s->insert(icon); +} + +void YahooClient::contactInfo(void *_data, unsigned long &status, unsigned&, QString &statusIcon, QSet *icons) +{ + YahooUserData *data = toYahooUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + unsigned cmp_status = STATUS_OFFLINE; + switch (data->Status.toULong()) + { + case YAHOO_STATUS_AVAILABLE: + cmp_status = STATUS_ONLINE; + break; + case YAHOO_STATUS_BUSY: + cmp_status = STATUS_DND; + break; + case YAHOO_STATUS_NOTATHOME: + case YAHOO_STATUS_NOTATDESK: + case YAHOO_STATUS_NOTINOFFICE: + case YAHOO_STATUS_ONVACATION: + cmp_status = STATUS_NA; + break; + case YAHOO_STATUS_OFFLINE: + break; + case YAHOO_STATUS_CUSTOM: + cmp_status = data->bAway.toBool() ? STATUS_AWAY : STATUS_ONLINE; + break; + default: + cmp_status = STATUS_AWAY; + } + + const CommandDef *def; + for (def = protocol()->statusList(); !def->text.isEmpty(); def++) + { + if (def->id == cmp_status) + break; + } + if (cmp_status > status) + { + status = cmp_status; + if (!statusIcon.isEmpty() && icons){ + icons->insert(statusIcon); + } + statusIcon = def->icon; + } + else + { + if (!statusIcon.isEmpty()) + { + addIcon(icons, def->icon, statusIcon); + } + else + { + statusIcon = def->icon; + } + } + if (icons && data->bTyping.toBool()) + addIcon(icons, "typing", statusIcon); +} + +QString YahooClient::contactTip(void *_data) +{ + YahooUserData *data = toYahooUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + unsigned long status = STATUS_UNKNOWN; + unsigned style = 0; + QString statusIcon; + contactInfo(data, status, style, statusIcon); + QString res; + res += ""; + QString statusText; + for (const CommandDef *cmd = protocol()->statusList(); !cmd->text.isEmpty(); cmd++){ + if (cmd->icon == statusIcon){ + res += " "; + statusText = i18n(cmd->text); + res += statusText; + break; + } + } + res += "
"; + res += data->Login.str(); + res += ""; + if (data->Status.toULong() == YAHOO_STATUS_OFFLINE){ + if (data->StatusTime.toULong()){ + res += "
"; + res += i18n("Last online"); + res += ": "; + res += formatDateTime(data->StatusTime.toULong()); + } + }else{ + if (data->OnlineTime.toULong()){ + res += "
"; + res += i18n("Online"); + res += ": "; + res += formatDateTime(data->OnlineTime.toULong()); + } + if (data->Status.toULong() != YAHOO_STATUS_AVAILABLE){ + res += "
"; + res += statusText; + res += ": "; + res += formatDateTime(data->StatusTime.toULong()); + QString msg; + switch (data->Status.toULong()){ + case YAHOO_STATUS_BRB: + msg = i18n("Be right back"); + break; + case YAHOO_STATUS_NOTATHOME: + msg = i18n("Not at home"); + break; + case YAHOO_STATUS_NOTATDESK: + msg = i18n("Not at my desk"); + break; + case YAHOO_STATUS_NOTINOFFICE: + msg = i18n("Not in the office"); + break; + case YAHOO_STATUS_ONPHONE: + msg = i18n("On the phone"); + break; + case YAHOO_STATUS_ONVACATION: + msg = i18n("On vacation"); + break; + case YAHOO_STATUS_OUTTOLUNCH: + msg = i18n("Out to lunch"); + break; + case YAHOO_STATUS_STEPPEDOUT: + msg = i18n("Stepped out"); + break; + case YAHOO_STATUS_CUSTOM: + msg = data->AwayMessage.str(); + } + if (!msg.isEmpty()){ + res += "
"; + res += quoteString(msg); + } + } + } + return res; +} + +const unsigned MAIN_INFO = 1; +const unsigned NETWORK = 2; + +static CommandDef yahooWnd[] = + { + CommandDef ( + MAIN_INFO, + " ", + "Yahoo!_online", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef (), + }; + +static CommandDef cfgYahooWnd[] = + { + CommandDef ( + MAIN_INFO, + " ", + "Yahoo!_online", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef ( + NETWORK, + I18N_NOOP("Network"), + "network", + QString::null, + QString::null, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + QString::null + ), + CommandDef (), + }; + +CommandDef *YahooClient::infoWindows(Contact*, void *_data) +{ + YahooUserData *data = toYahooUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + QString name = i18n(protocol()->description()->text); + name += " "; + name += data->Login.str(); + yahooWnd[0].text_wrk = name; + return yahooWnd; +} + +CommandDef *YahooClient::configWindows() +{ + QString name = i18n(protocol()->description()->text); + name += " "; + name += data.owner.Login.str(); + cfgYahooWnd[0].text_wrk = name; + return cfgYahooWnd; +} + +QWidget *YahooClient::infoWindow(QWidget *parent, Contact*, void *_data, unsigned id) +{ + YahooUserData *data = toYahooUserData((SIM::clientData*)_data); // FIXME unsafe type conversion + switch (id){ + case MAIN_INFO: + return new YahooInfo(parent, data, this); + } + return NULL; +} + +QWidget *YahooClient::configWindow(QWidget *parent, unsigned id) +{ + switch (id){ + case MAIN_INFO: + return new YahooInfo(parent, NULL, this); + case NETWORK: + return new YahooConfig(parent, this, true); + } + return NULL; +} + +void YahooClient::ping() +{ + if (getState() != Connected) + return; + sendPacket(YAHOO_SERVICE_PING); + QTimer::singleShot(PING_TIMEOUT * 1000, this, SLOT(ping())); +} + +class YahooParser : public HTMLParser +{ +public: + YahooParser(const QString&); + QString res; + bool bUtf; +protected: + struct style + { + QString tag; + QString face; + unsigned size; + unsigned color; + unsigned state; + }; + virtual void text(const QString &text); + virtual void tag_start(const QString &tag, const list &options); + virtual void tag_end(const QString &tag); + void set_style(const style &s); + void set_state(unsigned oldState, unsigned newState, unsigned st); + void escape(const QString &str); + bool m_bFirst; + QString esc; + stack