diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,15 +71,9 @@ find_package(Alsa QUIET) set_package_properties(Alsa PROPERTIES DESCRIPTION "Alsa is advanced linux sound Architecture" URL "http://www.alsa-project.org" TYPE OPTIONAL PURPOSE "Required for the Jabber protocol with libjingle support") -find_package(Boost QUIET) -set_package_properties(Boost PROPERTIES DESCRIPTION "C++ Boost libraries" URL "http://www.boost.org/" TYPE OPTIONAL PURPOSE "Required for the WLM protocol") - find_package(Expat QUIET) set_package_properties(Expat PROPERTIES DESCRIPTION "Expat is a stream oriented XML parser" URL "http://expat.sourceforge.net/" TYPE OPTIONAL PURPOSE "Required for the Jabber protocol with libjingle support") -find_package(GIF QUIET) -set_package_properties(GIF PROPERTIES DESCRIPTION "GIF - Package of portable tools and library routines for working with GIF images" URL "http://giflib.sourceforge.net/" TYPE OPTIONAL PURPOSE "Required for the WLM protocol with handwriting messages support") - find_package(GLIB2 QUIET) set_package_properties(GLIB2 PROPERTIES DESCRIPTION "GLib library" URL "http://www.gtk.org" TYPE OPTIONAL PURPOSE "Required for the Nowlistening plugin with XMMS player support") @@ -101,11 +95,8 @@ find_package(LibMeanwhile QUIET) set_package_properties(LibMeanwhile PROPERTIES DESCRIPTION "A library for protocol support for connection to sametime servers" URL "http://meanwhile.sourceforge.net/" TYPE OPTIONAL PURPOSE "Required for the meanwhile protocol") -find_package(Libmsn QUIET) -set_package_properties(Libmsn PROPERTIES DESCRIPTION "A library providing support for the msn protocol" URL "http://libmsn.sourceforge.net/" TYPE OPTIONAL PURPOSE "Required for the WLM protocol") - find_package(LiboRTP QUIET) -set_package_properties(LiboRTP PROPERTIES DESCRIPTION "oRTP provides an API to send rtp packets" URL "http://www.linphone.org/index.php/eng/code_review/ortp/" TYPE OPTIONAL PURPOSE "Required for the Jabber protocol with libjingle support and for the WLM protocol with voice clips support") +set_package_properties(LiboRTP PROPERTIES DESCRIPTION "oRTP provides an API to send rtp packets" URL "http://www.linphone.org/index.php/eng/code_review/ortp/" TYPE OPTIONAL PURPOSE "Required for the Jabber protocol with libjingle support") find_package(LibOTR QUIET) set_package_properties(LibOTR PROPERTIES DESCRIPTION "Library to encrypt messages with off-the-record encryption" URL "http://www.cypherpunks.ca/otr/" TYPE OPTIONAL PURPOSE "Required for the OTR plugin") @@ -120,7 +111,7 @@ set_package_properties(LibXslt PROPERTIES DESCRIPTION "A library to transform XML files into other XML files" URL "http://www.xmlsoft.org/XSLT/" TYPE OPTIONAL PURPOSE "Required for the Webpresence plugin") find_package(Mediastreamer QUIET) -set_package_properties(Mediastreamer PROPERTIES DESCRIPTION "A streaming enginer specialized for voice/video telephony applications" URL "http://www.linphone.org/index.php/eng/code_review/mediastreamer2/" TYPE OPTIONAL PURPOSE "Required for the Jabber protocol with libjingle support and for the WLM protocol with voice clips support") +set_package_properties(Mediastreamer PROPERTIES DESCRIPTION "A streaming enginer specialized for voice/video telephony applications" URL "http://www.linphone.org/index.php/eng/code_review/mediastreamer2/" TYPE OPTIONAL PURPOSE "Required for the Jabber protocol with libjingle support") find_package(OpenSSL QUIET) set_package_properties(OpenSSL PROPERTIES DESCRIPTION "OpenSSL implementation of SSL" URL "https://www.openssl.org/" TYPE OPTIONAL PURPOSE "Required for the Jabber protocol with libjingle support") diff --git a/cmake/modules/FindLibmsn.cmake b/cmake/modules/FindLibmsn.cmake deleted file mode 100644 --- a/cmake/modules/FindLibmsn.cmake +++ /dev/null @@ -1,37 +0,0 @@ -# cmake macro to test LIBMSN LIB - -# Copyright (c) 2006, Alessandro Praduroux -# Copyright (c) 2007, Urs Wolfer -# Copyright (c) 2008, Matt Rogers -# -# Redistribution and use is allowed according to the terms of the BSD license. -# For details see the accompanying COPYING-CMAKE-SCRIPTS file. - -IF (LIBMSN_INCLUDE_DIR AND LIBMSN_LIBRARIES) - # Already in cache, be silent - SET(LIBMSN_FIND_QUIETLY TRUE) -ENDIF (LIBMSN_INCLUDE_DIR AND LIBMSN_LIBRARIES) - -FIND_PATH(LIBMSN_INCLUDE_DIR msn/msn.h - PATHS ${CMAKE_INSTALL_PREFIX} - PATH_SUFFIXES msn ) - -FIND_LIBRARY(LIBMSN_LIBRARIES NAMES msn libmsn - PATHS ${CMAKE_INSTALL_PREFIX} - PATH_SUFFIXES lib) - -if (LIBMSN_INCLUDE_DIR AND LIBMSN_LIBRARIES) - SET(LIBMSN_FOUND TRUE) -endif(LIBMSN_INCLUDE_DIR AND LIBMSN_LIBRARIES) - -IF (LIBMSN_FOUND) - IF (NOT LIBMSN_FIND_QUIETLY) - MESSAGE(STATUS "Found LibMSN: ${LIBMSN_LIBRARIES}") - ENDIF (NOT LIBMSN_FIND_QUIETLY) -ELSE (LIBMSN_FOUND) - IF (LIBMSN_FIND_REQUIRED) - MESSAGE(FATAL_ERROR "Could NOT find an acceptable version of LibMSN (version 0.4 or later required)") - ENDIF (LIBMSN_FIND_REQUIRED) -ENDIF (LIBMSN_FOUND) - -MARK_AS_ADVANCED(LIBMSN_INCLUDE_DIR LIBMSN_LIBRARIES) diff --git a/doc/index.docbook b/doc/index.docbook --- a/doc/index.docbook +++ b/doc/index.docbook @@ -111,7 +111,6 @@ Messaging Jabber IRC -WLM ICQ AIM Yahoo @@ -158,7 +157,7 @@ To use &kopete; you need to set up one or more accounts for the instant messaging services you wish to use. You've probably already chosen a messaging service, either because you already use &im;, or you need to use the same service as your friends. If you don't fit into either of these categories, please consider using a messaging service based on open standards, because these are designed for use by Free Software. Other messaging services are prone to changing the underlying technology without making the details freely available, making them harder for Free Software developers to support. The messaging services that &kopete; supports that are based on open standards are Jabber and IRC. -The following section assumes you are registered with an &im; service already. If not, you can register with Gadu-Gadu, Jabber, and WLM from inside &kopete;; for other services, you'll have to register using their respective web site before creating an account in &kopete;. +The following section assumes you are registered with an &im; service already. If not, you can register with Gadu-Gadu, and Jabber from inside &kopete;; for other services, you'll have to register using their respective web site before creating an account in &kopete;. Creating Accounts To create an account, use Settings Configure... to display the Configure window. @@ -693,11 +692,6 @@ ICQ ICQ has an Invisibility feature which allows you to hide from selected contacts. You may also search the ICQ user folder when adding a contact. A wide range of contact details can be set using the Properties option. - - WLM - File transfer and multi user chats work. To transfer a file, drag the file from &dolphin; or the desktop into the chat window. To invite someone else into a chat, drag them from the Contact List into the chat window. The File menu also contains these commands. In addition, WLM supports custom emoticons. - To use file transfer, make sure port 6891 is forwarded to your computer. - Yahoo Yahoo can send and receive webcam video. It also supports Yahoo mail and the Yahoo address book from the account menu. Conferencing is also possible. @@ -1047,7 +1041,7 @@ I need to connect via a SOCKS proxy, but I cannot find any proxy configuration options in &kopete;. How do I set up &kopete; to use SOCKS? -WLM, ICQ, AIM, Jabber, and Yahoo use the &kde; network infrastructure. Their SOCKS proxy details are configured with the rest of &kde;, in &systemsettings;, Network and ConnectivityNetwork SettingsProxy. +ICQ, AIM, Jabber, and Yahoo use the &kde; network infrastructure. Their SOCKS proxy details are configured with the rest of &kde;, in &systemsettings;, Network and ConnectivityNetwork SettingsProxy. @@ -1125,12 +1119,6 @@ -I AM behind a firewall. Which ports need to be open for WLM file transfers? - -If you are behind a firewall, port 6891 needs to be open to inbound TCP traffic. - - - I use Jabber and ICQ together. Whenever I go online with Jabber, I am disconnected from ICQ with an error message about being connected from another client. What's up? diff --git a/kopete/kopete.notifyrc b/kopete/kopete.notifyrc --- a/kopete/kopete.notifyrc +++ b/kopete/kopete.notifyrc @@ -1642,144 +1642,6 @@ Action=Popup -[Event/msn_mail] -Name=MSN Mail -Name[ar]=MSN بريد -Name[ast]=Corréu de MSN -Name[bg]=Поща MSN -Name[bn]=এমএসএন মেইল -Name[br]=Postel MSN -Name[bs]=MSN Elektronska pošta -Name[ca]=Correu de MSN -Name[ca@valencia]=Correu de MSN -Name[cs]=MSN pošta -Name[cy]=MSN Mail -Name[da]=MSN-Mail -Name[de]=MSN Mail -Name[el]=MSN Mail -Name[en_GB]=MSN Mail -Name[eo]=MSN retpoŝto -Name[es]=Correo de MSN -Name[et]=MSN-i kiri -Name[eu]=MSN posta -Name[fi]=MSN-sähköposti -Name[fr]=Courriel MSN -Name[ga]=Ríomhphost MSN -Name[gl]=Correo MSN -Name[he]=דוא"ל של MSN -Name[hi]=एमएसएन मेल -Name[hne]=एमएसएन मेल -Name[hr]=MSN pošta -Name[hu]=MSN e-mail -Name[ia]=MSN Mail (E-posta de MSN) -Name[is]=MSN póstur -Name[it]=Posta MSN -Name[ja]=MSN メール -Name[kk]=MSN поштасы -Name[km]=សំបុត្រ MSN -Name[ko]=MSN 메일 -Name[lt]=MSN Paštas -Name[lv]=MSN pasts -Name[mk]=MSN-пошта -Name[ml]=എംഎസ്‌എന്‍ തപാല്‍ -Name[nb]=MSN Mail -Name[nds]=MSN-Nettpost -Name[nl]=MSN Mail -Name[nn]=MSN Mail -Name[pa]=MSN ਮੇਲ -Name[pl]=Poczta MSN -Name[pt]=Correio do MSN -Name[pt_BR]=MSN Mail -Name[ro]=Poșta MSN -Name[ru]=Почта MSN -Name[si]=MSN ලිපි -Name[sk]=MSN pošta -Name[sl]=E-pošta MSN -Name[sq]=MSN Mail -Name[sr]=МСН пошта -Name[sr@ijekavian]=МСН пошта -Name[sr@ijekavianlatin]=MSN pošta -Name[sr@latin]=MSN pošta -Name[sv]=MSN e-post -Name[ta]=MSN மின்னஞ்சல் -Name[tg]=Пости MSN -Name[th]=จดหมายของ MSN -Name[tr]=MSN Posta -Name[ug]=MSN خەت -Name[uk]=Пошта MSN -Name[x-test]=xxMSN Mailxx -Name[zh_CN]=MSN 邮件 -Name[zh_HK]=MSN Mail -Name[zh_TW]=MSN 郵件 -Comment=New email has arrived in your MSN inbox -Comment[ar]=بريد إلكتروني جديد وصل في الصندوق الوارد لـ MSN -Comment[ast]=Llegó un mensax al to buzón de MSN -Comment[bg]=Нова поща в кутията ви в MSN -Comment[bn]=আপনার এমএসএন ইনবক্সে নতুন ই-মেইল উপস্থিত হয়েছে -Comment[br]=Deuet eo ur postel nevez d'em voest degemer MSN -Comment[bs]=Nova elektronska pošta je stigla u vaše MSN dolazne poruke -Comment[ca]=Ha arribat un nou correu a la vostra bústia de MSN -Comment[ca@valencia]=Ha arribat un nou correu a la vostra bústia de MSN -Comment[cs]=Přišla nová pošta do vaší MSN schránky -Comment[da]=Ny e-mail ankom til din MSN-indbakke -Comment[de]=Es befindet sich eine neue Nachricht MSN-Eingangsordner -Comment[el]=Ένα νέο μήνυμα έφτασε στο λογαριασμό σας στο MSN -Comment[en_GB]=New email has arrived in your MSN inbox -Comment[eo]=Nova poŝto alvenis en via MSN leterujo -Comment[es]=Ha llegado un nuevo mensaje a su bandeja de entrada de MSN -Comment[et]=Saabus uus kiri sinu MSN Inboxi -Comment[eu]=Posta elektroniko berria jaso da zure MSN-ko sarrerako ontzian -Comment[fi]=Uutta postia saapunut MSN-sähköpostilaatikkoon -Comment[fr]=Un nouveau message est arrivé dans votre boîte aux lettres MSN -Comment[ga]=Tháinig teachtaireacht nua isteach i do bhosca MSN -Comment[gl]=Chegou un correo á caixa de correo de MSN -Comment[he]=התקבל עבורך דואר חדש בתיבת הדוא"ל של MSN -Comment[hi]=आपके एमएसएन इनबक्से में एक नया ईमेल आया है -Comment[hne]=आप मन के एमएसएन इनबक्से मं एक नवा ईमेल आय हे -Comment[hr]=Nova pošta je stigla u vaš MSN sandučić -Comment[hu]=Új levél érkezett az MSN postaládába -Comment[ia]=Nove e-posta ha arrivate in tu cassetta de MSN -Comment[is]=Það er nýr póstur í MSN innhólfinu þínu -Comment[it]=È arrivata nuova posta nella casella MSN -Comment[ja]=MSN の受信箱に新しいメールが届きました -Comment[kk]=MSN эл.пошта жашігіңізге жаңа хат келіп түсті -Comment[km]=អ៊ីមែល​ថ្មី​បាន​មក​ដល់​ក្នុង​ប្រអប់​ទទួល MSN របស់​អ្នក -Comment[ko]=MSN 받은 편지함에 새 편지가 도착함 -Comment[lt]=Į MSN pašto dėžutę gautas naujas laiškas -Comment[lv]=Jūsu MSN pastastē ir pienācis jauns e-pasta ziņojums -Comment[mk]=Пристигна нова пошта во вашето MSN-сандаче -Comment[ml]=നിങ്ങളുടെ എംഎസ്‌എന്‍ ആഗമപേടകത്തില്‍ പുതിയ ഈതപാല്‍ വന്നിട്ടുണ്ട് -Comment[nb]=Ny e-post er mottatt i MSN-innkurven -Comment[nds]=Du hest niege Nettpost in Dien MSN-Postingang -Comment[nl]=Er is een nieuw bericht gearriveerd in uw MSN-postbus -Comment[nn]=Du har fått ein ny e-post i MSN-innboksen din -Comment[pa]=ਤੁਹਾਡੇ MSN ਇਨ-ਬਾਕਸ ਵਿੱਚ ਇੱਕ ਨਵੀਂ ਈਮੇਲ ਆਈ ਹੈ -Comment[pl]=Nadeszła nowa wiadomość do Twojej skrzynki odbiorczej w MSN -Comment[pt]=Foi recebido um e-mail novo na sua caixa de correio do MSN -Comment[pt_BR]=Chegou um novo e-mail em sua caixa de entrada do MSN -Comment[ro]=A sosit o scrisoare nouă în cutia poștală MSN -Comment[ru]=Пришли новые письма в почтовый ящик MSN -Comment[si]=නව ලිපියක් ඔබේ MSN තැපැල් කොටුවට පැමිණිනි -Comment[sk]=Do vašej schránky MSN prišla nová správa -Comment[sl]=V vaš nabiralnik MSN je prispela nova e-pošta -Comment[sr]=Нова е‑пошта је стигла у ваше пријемно сандуче на МСН‑у -Comment[sr@ijekavian]=Нова е‑пошта је стигла у ваше пријемно сандуче на МСН‑у -Comment[sr@ijekavianlatin]=Nova e‑pošta je stigla u vaše prijemno sanduče na MSN‑u -Comment[sr@latin]=Nova e‑pošta je stigla u vaše prijemno sanduče na MSN‑u -Comment[sv]=Ett nytt brev har anlänt i din MSN-inkorg -Comment[ta]=உங்கள் எம்எஸ்என் அஞ்சல் பெட்டிக்கு புதிய மின்னஞ்சல் வந்துள்ளது -Comment[tg]=Ба қутии пости MSN-и шумо пайёми электронии нав омад -Comment[th]=มีจดหมายใหม่เข้ามาในกล่องจดหมายเข้าบน MSN ของคุณ -Comment[tr]=MSN gelen kutunuza yeni bir e-posta geldi -Comment[ug]=سىزنىڭ MSN قوبۇللاش ساندۇقىڭىزغا يېڭى تورخەت كەلدى -Comment[uk]=Надійшла нова пошта у вашу скриньку MSN -Comment[x-test]=xxNew email has arrived in your MSN inboxxx -Comment[zh_CN]=您的 MSN 收件箱中有新邮件到达 -Comment[zh_HK]=您的 MSN 收件匣有新郵件 -Comment[zh_TW]=您的 MSN 收件匣中有新郵件 -Action=Popup -Persistant=true - [Event/icq_authorization] Name=ICQ Authorization Name[ar]=ICQ تصريح diff --git a/protocols/CMakeLists.txt b/protocols/CMakeLists.txt --- a/protocols/CMakeLists.txt +++ b/protocols/CMakeLists.txt @@ -9,8 +9,6 @@ option(WITH_jabber "Enable Kopete Jabber protocol" ON) option(WITH_libjingle "Enable Kopete Jabber libjingle support" ON) option(WITH_bonjour "Enable Kopete Bonjour protocol" ON) -option(WITH_wlm "Enable Window Live Messenger support" ON) -option(WITH_WLM_MEDIASTREAMER "Enable Windows Live Messenger voice clip support" ON) option(WITH_meanwhile "Enable Kopete meanwhile protocol" ON) option(WITH_skype "Enable Kopete Skype protocol" ON) @@ -37,20 +35,8 @@ set(BUILD_LIBJINGLE FALSE) endif() -if(MEDIASTREAMER_FOUND AND LIBORTP_FOUND AND WITH_WLM_MEDIASTREAMER) - message(STATUS "Building Windows Live Messenger voice clip support") - set(BUILD_WLM_MEDIASTREAMER TRUE) -else() - message(STATUS "Not building Windows Live Messenger voice clip support") - set(BUILD_WLM_MEDIASTREAMER FALSE) -endif() - include_directories(${KOPETE_INCLUDES}) -if(WITH_wlm AND LIBMSN_FOUND AND Boost_FOUND) - add_subdirectory( wlm ) -endif() - if(WITH_oscar) add_subdirectory( oscar ) endif() diff --git a/protocols/wlm/CMakeLists.txt b/protocols/wlm/CMakeLists.txt deleted file mode 100644 --- a/protocols/wlm/CMakeLists.txt +++ /dev/null @@ -1,89 +0,0 @@ -project(wlm) - -include_directories( - ${Boost_INCLUDE_DIRS} -) - -ADD_SUBDIRECTORY(icons) - -set(kopete_wlm_include_DIRS - ${KOPETE_INCLUDES} - ${CMAKE_CURRENT_SOURCE_DIR}/ui - ${LIBMSN_INCLUDE_DIR} -) - -set(kopete_wlm_ui_SRCS - ui/wlmaddcontactpage.cpp - ui/wlmeditaccountwidget.cpp -) - -ki18n_wrap_ui(kopete_wlm_ui_SRCS - ui/wlmaddui.ui - ui/wlminfo.ui - ui/wlmaccountpreferences.ui - ui/wlmchatsessioninkpopup.ui -) - -set(kopete_wlm_PART_SRCS - ${kopete_wlm_ui_SRCS} - wlmprotocol.cpp - wlmcontact.cpp - wlmaccount.cpp - wlmlibmsn.cpp - wlmsocket.cpp - wlmserver.cpp - wlmchatmanager.cpp - wlmchatsession.cpp - wlmchatsessioninkarea.cpp - wlmchatsessioninkaction.cpp - wlmtransfermanager.cpp -) - -add_library(kopete_wlm MODULE ${kopete_wlm_PART_SRCS}) - -set(kopete_wlm_link_LIBS - - - KF5::KIOCore - ${KDE4_KMIME_LIBS} - Qt5::Xml - Qt5::Network - kopete - ${LIBMSN_LIBRARIES} -) - -if(BUILD_WLM_MEDIASTREAMER) - set(kopete_wlm_link_LIBS ${kopete_wlm_link_LIBS} ${MEDIASTREAMER_LIBRARIES} ${LIBORTP_LIBRARY}) - set(kopete_wlm_include_DIRS ${kopete_wlm_include_DIRS} ${MEDIASTREAMER_INCLUDE_DIR}) - add_definitions(-DHAVE_MEDIASTREAMER) -endif(BUILD_WLM_MEDIASTREAMER) - -if(GIF_FOUND) - set(kopete_wlm_link_LIBS ${kopete_wlm_link_LIBS} ${GIF_LIBRARIES}) - set(kopete_wlm_include_DIRS ${kopete_wlm_include_DIRS} ${GIF_INCLUDE_DIR}) - add_definitions(-DHAVE_GIFLIB) - - # giflib 4.2.0 removed PrintGifError() in favor of GifError() and GifErrorString(). - # We need to check which functions are present. - # FIXME: Once we depend on CMake 2.8.6+ we can use CMAKE_{PUSH,POP}_CHECK_STATE(). - set(_OLD_CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES}") - set(_OLD_CMAKE_REQUIRED_INCLUDES "${CMAKE_REQUIRED_INCLUDES}") - set(CMAKE_REQUIRED_LIBRARIES "${GIF_LIBRARIES}") - set(CMAKE_REQUIRED_INCLUDES "${GIF_INCLUDE_DIR}") - include(CheckFunctionExists) - check_function_exists(GifErrorString HAVE_GIF_ERROR_STRING) - set(CMAKE_REQUIRED_LIBRARIES "${_OLD_CMAKE_REQUIRED_LIBRARIES}") - set(CMAKE_REQUIRED_INCLUDES "${_OLD_CMAKE_REQUIRED_INCLUDES}") - - if(HAVE_GIF_ERROR_STRING) - add_definitions(-DHAVE_GIF_ERROR_STRING) - endif(HAVE_GIF_ERROR_STRING) -endif(GIF_FOUND) - -include_directories(${kopete_wlm_include_DIRS}) -target_link_libraries(kopete_wlm ${kopete_wlm_link_LIBS}) - -install(TARGETS kopete_wlm DESTINATION ${KDE_INSTALL_PLUGINDIR}) - -install(FILES kopete_wlm.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}) -install(FILES wlmchatui.rc DESTINATION ${KDE_INSTALL_KXMLGUI5DIR}/kopete_wlm) diff --git a/protocols/wlm/README b/protocols/wlm/README deleted file mode 100644 --- a/protocols/wlm/README +++ /dev/null @@ -1,5 +0,0 @@ -This source code links against libmsn. -You can get it here: -svn co https://libmsn.svn.sourceforge.net/svnroot/libmsn/trunk libmsn - -Salem diff --git a/protocols/wlm/icons/CMakeLists.txt b/protocols/wlm/icons/CMakeLists.txt deleted file mode 100644 --- a/protocols/wlm/icons/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -ecm_install_icons(${KDE_INSTALL_DATADIR}/kopete/icons) diff --git a/protocols/wlm/icons/ox128-app-wlm_protocol.png b/protocols/wlm/icons/ox128-app-wlm_protocol.png deleted file mode 100644 index 7e5113720f211d90f5a5d21daffbefeaadba6820..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@zRqgQ%ckaGT+ueXD2raV%7!xG~jmhIB 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 diff --git a/protocols/wlm/icons/ox16-action-wlm_away.png b/protocols/wlm/icons/ox16-action-wlm_away.png deleted file mode 100644 index 1ec52cd6ca9027e7fde9a4f5df62f61d6be545a5..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@oaZ^`;e0rp{_3i$332Ih0Fb~h zFA*S5j#La2Y0iZtA+lIW`OQ`UR!XE8U5%n46k^T1N*=)UKu5S{7|onJ<$_9pXW0PV z&jEroay!72TmXj{pl}2r?V(h(Tn4~6U0qRIO4Br`XpA9ey!S;3w@`yI=OfBq`JaP4 z7}4KkBur7T)HE|=IlgHJOIT!al*xTo_7;t0t`u%lIW5{K;X0GIc0#b8*1UP@`bK`Q zwpd4(ejsX=4(t024P&OJar1pmxP8gdHDmAJ4oaocVVoLW!$%EAublL_+Wp2wPZ+|p zJFXwL(30_R*+3|j$_n7Nm&-*Egxl@*csyRO*XQ#c931@hANmo2fS;rS2$Bj0gP~9; zOp-?kiXuspq9{du>J)ly`eQ+r5ICG%1eYroOC;UhgM%`e9HG~{Zy&S9qpjEc5?(F) zdF%S4XC7PUki#DhmTj}(L@7#J?%JRH$@P~wO{P*6%h5R=gY1_pCszAf2nq>X{P O89ZJ6T-G@yGywp9KtUM* diff --git a/protocols/wlm/icons/ox16-action-wlm_brb.png b/protocols/wlm/icons/ox16-action-wlm_brb.png deleted file mode 100644 index 8524a3ca811ef731d5988ab0c6f657ea5aceaf69..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@z@;j(q!3lK=n!AY({UO#lFTB>(_`g8%^e{{R4h=>PzA zFaQARU;qF*m;eA5Z<1fdMgRZ+nNUnrMgRZ*V`p(?X>(_6b!u*RZE<>VbbWJoe|CC< zdVYp}fr^8Lj)#hoi;k9$lA4s4otT@VoS&tlq^hK*t)-`~tF5!FuCuMLwXU$WwYR*r zxV*Qxy}-i7(9z`7)aTdN>D$`t+uQ5j-t6Mx@8sq1<>m3{>GJFA_3P~P@9*~U@%Qxg z`StYq_xJnw_xt+#{QUd<{r&#`|Nr(^)%O4Z00DGTPE!Ct=GbNc002`-L_t(|+O3K~ z3V<*S1lQ6}2u1M!ztR_YZn7znAj#di&FpRnhN&nYGz64+oCJFKF2gIn$Lp3J>N`^) tjH)@fN)D4+A42yUZj^ArkmwEnu>d%WHVM)|%W41s002ovPDHLkV1j3&zs~>w diff --git a/protocols/wlm/icons/ox16-action-wlm_busy.png b/protocols/wlm/icons/ox16-action-wlm_busy.png deleted file mode 100644 index e1862c64c7589570f38a5a0386e925652c8e1973..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@Gjx|0SXfHL;!3beUK8uHQUu>(tV@)63@d4UG5_B(8K7*7wZ_i5 zyMT<+u(l;_tM-?L|2q~3l)ZNNO1%QhlICUISyK-zJ8+{@u{SPr|B?gO4qj=IVCYa} zm@LUK(^h<;tHhGFl}mjjR|ZM1c4S!-A+ye!d3~nmhB&!xA#6LRuiG_y>!D1}lWX^% zS-tICDc98rlGnCwy|!)J%_EoZcN;%EdGhI0$EVX=p3U}odC>Re^=q$h-FkET_M3;V z-tH28dtmCfCq3Vu-TeOX-~GM_TQV+|K8jD`}OhP-yi?} z{j+-{6$$jSTuG20Fi-`6K*7Mk!NDP+pr8Q+=FeZh{`~p-@87@wZFk!rsItM+#W6%; zYH~sgL!x~T-27cxxy$=7YlO>O*|j>lCY6ay uPJVXR_}ZkniVPUl>Np-WavormWMT+^!`xP^SZ9=0u-4h!ahfsd$9ojDt@868r}~qBj-u8&y(exr!RfPOzVi3-7ydQ zlfv8=*rYGY>0dQ4x^C!pgN^$}Li|k@nLF#(KZpu@TvGD5xA%E>_p9FCSNrz8o;vl- zgbDAถ^rfii%fdC^>*{{UNdItl{83Z&qqgS9(WAc{9Dg%1{XTKx&-GjXrcDQW z@IN>Ae=V*51_u8vEdEi_)w|K;WXD=PlCxBu_x_}|(2zpMLy zZ}0!UzW*CG{NJ+W|FdWRU%UW@!0-RN!hvBSRTAU}3~T`)NPvL-U~nD+42mx&0#(iT zba4!+xYc_8s!$VyK`U;93^&{?zBqH5XPmR(uR%d03GDJ9I<&ypBmNKRhBiY))GR-EEw#u>F3RU3vZ9 zE`b!6kAE6Z=LxG8_=+ycbDnl!)?9^aQ5~NxoEaLOR#w@VN~iLL82p%|94V)6v6qb@ i%}gv=a@N29x6QLWrTUM~Onwh^Dubu1pUXO@geCwghyz{# diff --git a/protocols/wlm/icons/ox16-action-wlm_invisible.png b/protocols/wlm/icons/ox16-action-wlm_invisible.png deleted file mode 100644 index e53c06e0e00d5b58fc1d417659bf030f41d170bc..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@z@;j(q!3lK=n!AY({UO#lFTB>(_`g8%^e{{R4h=>PzA zFaQARU;qF*m;eA5Z<1fdMgRZ-3Q0skRCwB@%Rfs(VHC%4UxI6MZya+g|) zuq6l@?oiZTTYre4p+N|u*2keS5Jk|^x`UzySyukTOF`677JNGr#ko^M=QkWUzt4&A zo52`oKDEIzvl!nvgG&gQ_%VGt+|Z!NBqpwbeDCu?SL!>Ow5cP+Q6OferY?0$cEBSA zOiF=OIbV>#%06d{5--f5z!F!Ki7`fxO@`R!jWrEssBy$Fiv+lglH`*;4W_Ab%`RC1 zd3Jc`mBTP7OKxe={XE z)7O>#Dzi8zqu#kt)6+m9rX+877Y2q^y~;*F-dRr<$B>F!OV1nfF$M}8`}kJ2N!g;Q zEUU#yagl?DM+&#%`pX?nN7TBmdWdxOwm5CgTTswY%G~Ls`m;Jr>6`A!kD@dM{B-paIpK6^kxW7wgRNq~uW8wgJarAOH@02)&t#+V>z7(8|67X< zwJ&TPonl@bbG*9$(nW{KUuDhtRFwCn#I3D6DX;wC_CJ0()}I0&ZY8K(0eXzV)78&q Iol`;+02;w`YXATM diff --git a/protocols/wlm/icons/ox16-action-wlm_na.png b/protocols/wlm/icons/ox16-action-wlm_na.png deleted file mode 100644 index 776d7f996754dcc2fb29232456bcd7cd72b924d4..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@V?uq_a1DYsN z666=ma0WYYNoH&Vs&VslaSW-rwf01`n1h0d!^J+QQ_7z@e)3;&UwxY4*8J$Jh4n#w z?o%FEMK(G%HM9EbZ#>MhMJW0}@z@;j(q!3lK=n!AY({UO#lFTB>(_`g8%^e{{R4h=>PzA zFaQARU;qF*m;eA5Z<1fdMgRZ-xJg7oRCwCOliz9+K^VnV+tR1>eCZ@)3LiA3~&8-ZfAWDKtg!PlZ}FNhN=<+0E?ijN>dZiMP4%gEQxwGjq;2 zH{%&&Sf+fIEb*eH%w`$1wlK!B!>nJ>SkT@bM~LfXkDW%2`7%>B7XRvV+9c74k6lIc zn$LRCa}&(WxUkoAx=i8hT(kdajOd>p@w`*z?yV{h>H&G-xr=EA)F0N6SdJA$7O(dE z92}h>qXFLT;l%9Jq1FDu>kop5cPcb*6i74P=hh64I^QU&RP&k$N0Ae*9d0gWq)?fNB- z`|!0ViKHT2gGaYL@`e0g^CX2NH3)5tn-bgQTc=C;@>Pr|aB~$lYVM*l$aI~-a74G; zVdY|##P}rIAe2psEq)G0tc4X)KaWgd;!IO>hTMe`d9PrDhKORAy+GRKS0oASp~9b; zW+4lj&K1b53eLxI7V!R55+%ZJ5+~R|$BE8*HLtmzjFslg$%y~{nU)Xu4GwEQh^7jp QWB>pF07*qoM6N<$g0Z~*@&Et; diff --git a/protocols/wlm/icons/ox16-action-wlm_offline.png b/protocols/wlm/icons/ox16-action-wlm_offline.png deleted file mode 100644 index 1662d652cd852b2474395c2ce0adea6b38153c38..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@}_xDdoNC2`kGc!v{O8or% z0s;a;LqlU@V}WW~TU)!kyZ7(k-`w2X-`}5{oD5|2_4RGty4B0eD>@<#2=epu)6>&4 zGBSV)jvYI8=FAyyZ|~C5(z3F$zU~@~D{E?MYHMp78ylON znt(28YisN1=;-Y1?CI(0?d=6R4Csal6D9yHoiu6EHhqD6}qFJ8Q4$&zKumMvelX8H2vD^{#nxpL*IRjXF7UcF|` znhhH^Y}&L5=-KVtx9`}oW9QDDd-v`IhQ@&d2M!%NbolV$qeqXPJbCiesZ*y&uf#5y}yaxepyQcj>T{k^l9780gCMP&B#64wFRa4m);hS2uK%hxKCU(|T8Aayj zo5e$)q#j|FHoS6WMaL#4R+ZIV#X*ai)<|sH#HD@8MMA;nb2imr2e^d2{+V z+qg6=R?xKz3RAwOAHwjeVBQRYd^<5tQ&+bc;XAJ8-Z;R+aOtJ~a|M%rQ2J-^boFyt I=akR{0ExL?Q2+n{ diff --git a/protocols/wlm/icons/ox16-action-wlm_online.png b/protocols/wlm/icons/ox16-action-wlm_online.png deleted file mode 100644 index a6dcfe9b5d5e7201c2e9358418cbce1fcb1d3534..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@z@;j(q!3lK=n!AY({UO#lFTB>(_`g8%^e{{R4h=>PzA zFaQARU;qF*m;eA5Z<1fdMgRZ;!bwCyRCwB@&s}I!XBfco|NEYkrin`pN!zF+HM-h0 z1({esST9Nyb%QZTFT`DpnO-T3fzk_cAhis?P!PRQ5SBu#Ll{)Xl&W=hjH+v8q)589 zD$R%`{n(PMNt=(8bB>kV6@`L7`14*p56>%1)8u`qLI_ssM*H!gug=@?;rc4y{L6_{ z--AS}$_iY$kac>JM?%eCYzercf56YbLOSalOnh{4MGM@?!=cai`UAGdXCNAfA^_B= zi7hhJlQ$!y#bn?8eDCSg*&xeYKD0mB+`Kkm8}EU194vqW2q??_hpbtz()}>&y!|8> z&~1g#wI3HJ4}SA+3zXD&MMrgE2y%0vP)Y?PY^w93jz6c%UuOwMMm7GK));wK@Ksju z@XLLXw*9*wv&r4%BNfFoOLq%J0Y!iW;cy}2Q=(JmRGglrs#Gc}6{gbjq#Z+{%Gy9E zGb_=Pvl#g_Mlpk)OJNk!APwS~BJzh5G8&uEJ6)?J&T19KJ;PJS*Mu#XxHB|N|Eq7I zTwvHG#?t#HQ_<12G;G`!l>pzjTTjl7Wd|G%!L;i(`Wg-4u@cEXV!_zRV0=5Km8D@Y zEds*=!v6`Z`#3D2#J-SgogPjO*t9YfH>hrtG2=JNtmQnL`Ly)sH`&Tj{M%tiJsEw_ zsX|Hn$u%ip*ZH3w^g60{1@7kVp=TBuUAT`o)rfFcfF0!K228sNRWW32bxLKK$%)vd z#wJ%FBJ&j2>ilnBr{S+t(6|+;O3)3^G>n|VqEz@;j(q!3lK=n!AY({UO#lFTB>(_`g8%^e{{R4h=>PzA zFaQARU;qF*m;eA5Z<1fdMgRZ+w@^$}MgRZ*b8WwHYP@xB!E9%^aBI9&RHA2Mvs6@~ z2FL~o$p{h65iZIuO3_MaW3+FqnQ)h-a;2tooS}4`q>tp1ljf6^rM#A$(44QnqNnDf zsot=O!&`mML{u(RQ_w%)V5?X=Cvxx(|i!0W!v)xhA&!Nlgp$L7V! z>&VUS$kN=(%;?nE^wrny+uiWq;q~C)@8st9<>&b3==SLB|LyVr@9_EX^854h`SbPv z(e3I`00009bW%=J01zNBKtND%pCrspTmS$7Ye_^wR2Y?GU_b^;(tJofMphPfMI-@c zJ}^KC@L5~hSePRV=&DGFi6aYWi1P9XAPb0ab8!kH3#bbT^GhNNSQ+S>sv-**>nUl; zA`2L5%V{bg3z!+{n8+Xtn5rpD$s-A{fnCnQKo9@`%{K`g`4h~i00000NkvXXu0mjf D%xuxk diff --git a/protocols/wlm/icons/ox16-app-wlm_protocol.png b/protocols/wlm/icons/ox16-app-wlm_protocol.png deleted file mode 100644 index 22ca6cae3c55845e47bf0c212ca27082b12bd8ea..0000000000000000000000000000000000000000 GIT binary patch literal 0 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 IM6N<$g5ayMvH$=8 diff --git a/protocols/wlm/icons/ox32-app-wlm_protocol.png b/protocols/wlm/icons/ox32-app-wlm_protocol.png deleted file mode 100644 index ce628dba1375f4e5bbf321a2517261f649b63df7..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@- 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 aN(TTo*alb-Q_5Tb0000w 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�opKONkIg zz$F+Gfy8=v#u%#s3cFhAp;s0xP|MgIOa)ZCSY{cfE%MRr6hn6bz#{HICqWqb8<$fm z8I2aBrg$k-gDYqx8bI0uMj_CZEP*VDBO~>?a2vXiM%qZS57y}qR3m8QcXhrJ1TyR= ztKk}?>ZNLD?FVvCpGvx;MATJFR#Wv;L&^GZJc&68i*!4Ak2^psy_=o@rBJ4} zR$uB~@JY#)hN-8aztTr)F0UbNwZr0NaW8RG{}7|a*~G5y5{iXl{Rc%WpI$y4k0UW9 z7fLR8qKfAommHV)N~m8!OhHV;EjZJXJvuX}=KSD8KKm^lSN3kOxl#yQBQm1ie0P6oS=Jn-s@Lxu4 z{9bxCYU&Ijo8gqRF-%Q#?(5(^2bux_3~wPDoE9z**yTAFoIL7T1HiLvsNpW-4q&&_ z^-*i>9L{3i((53BG-5VVOUV#;O+UsS`VL5?BXB-h4o|6DC`7LfkEzkftTlo-e2~=A z3?uGE4HR_&5sUUl z7$ejsmsNiujjv7&>Jt7HpGNMe7Qrr*kz?w6;YXnfd7}0fRtc-f7%f#Ql8UrsWwNwS z+NUMS4@HY;F@1*PYHhW4<;SP_UjL~ z7y|#Pxy!#-$KQh4)bC5p|J(AlSn_RI-Ej76r?`3?H z5weABlA-J@jV+CJ+2GZ&ta4dpW0Y$%;l6NxVSk!y#7?D7n18@$V7GP>z;Qu1A)6qB z-zWyjvNA@pDi&>zER$srh&qtu3Fpn!aL0?XhAQVVmVet8f(o= z%;y|`Z8`G%_NyPB2W^e<=onN~zh(XncVFMV)eF#3M@HF5DALwe3C704)s2bpjGpS(wo0djq&@7ygPrv}GGCrmMPTs+2 zbV&OPb%en%Kzj&Q{WoZ?O@un66|t!@S)&JPuM`%_NL920w*{Gak#k^xW26`vNeM9e zRPa=90Meh3G&~Pdw3GTmv=ts{x0OHiRgkMKSGsD|Aw{)_Me1$RNo_8q$bHBAStaIS+i9r=a5HT63wGc!>(55K0r1nyKwVSe0nlH_VC^B3*ublTfgSGDDAi2$U zlS1W7+AjblJIY##jY^*Plb7kCNy4K{ ztf|bD0-0PgM{^I=C!`u_3fmpK3h$S=lr=47ULJT`{yDyQ(49J|H=q1mPCu}w1Yg}J zXXnShYI!wVAL6=4ef_Rk#j%w)diha17x%CEruMs9R~|j4^OUgSI^(-u8ML-+Qg=M} z&fJx!LZ^|TA};G$+y>A6a5%kn%3x@{B6Y~`CqDr2tHd5cf1v6N92<3kfqyg0?|Z5E z?{z-_&%ag+11D5ceiy!xIids1puO8zX94)#@jc)s1Bis_LGJ{xA7NZ{ebuV1#lMGX{|3CqY$wMh6Pd?77V zUr`YieWp5G^c8&pw51{=GUjV^Nkpl!>`YM?ftB32Jjh~gBoYZYiLWK?Qdhxly#*Od zH6uOQdF&&D1J;5MQt&Qv5stxhlmT&24x8~h7)oBl-{=M!3O!%|9)|_6p$X1ke|{+c zg$I@9FAKedE@k)2!pep^LLG;)yXLJg-prM`ocwq;bC%iN!{WKj^BmR97G3dBNUUFD z;|0&RRYJBTcIY+vfKffb2b}VffdW8vWnXa8pP2%`)-Rg94haB5 zwghkW9u5G@xFc*IfU-*LF=i%!W@awY)d6q-Gma{ShvYdGOMQJ$#2@tQqAv-;58;XY z6tSu50V15t>3Cs0PtPF~NE@O?aWyAW_;g z>811=>7b=Zv!p1Jp&k~_3V%bY`baz~9@X!ugN6P=e{xLyQ7jQl0Q5|0rL@wViVNNq zoi6YD(8p0ve67}!kFZA#M-3wG&BU@>*d^3;oJ=>SkCM$yTQ-|r3=fzo>_o#Q@L+cu z?s73;V$%(yxm-Y;4|me|f~0Xt++^+;9_q_a{N$M9?|*Sj#L;D_gRUk-U2YxjIIDJAQ2o@#cyfA4$6qCfCF$X+T7?^Y?` zgnxWsv)f7ZI`zKfF=}nU9kEMlHPBD_yb2cU`=bcwMs2V31C@%Uci>Z?(AnHvYb!8x zG1o8b+Xw*4pf)&Z6~GBA@>uvrxe88^Gu$eeSpc^ZkF}Qm08%Kkmg)}Rct^9882~L~ z{-l}!kYfx(PlF6#*y;2$@B>#S6US*o$u=rMeJ4C6S=2)y+BDdOHtL&|u4FDcqt%mt zC*eS=9Ti{F7Un5uWCQ6>8Ym~FaOkA(mx-tnKYgeaDIOz4KPwIt!pS@B7tz5lCz;xD zVF*8%99IwVoA^5Vb>%$&hz}>1l?8kyAyEIIrt|apPb5`Y&Aai4iRQ928e zLLcI%w&HK{H_3CgjnGf%M^yE*7$61!=%d6n;u>QgT>PozQ~9eWv4uPB1BDNTFK{Fk z!mbA}bvFLW^Bh`+X4ncGRQBO1q_7kK; z$Rot{<;}C|=Pb;Bo8SI1{b<61quhCB!j@ZXP8|Hq^OK|UHKDuM-iRhS; z=jxj2iGkC{Sc0IaY1^(zP2Zq)>QuR{dLFe$4DrFWK}u+ry!7aOpmkTc3;?6ZYjD!i zo99&O4S=80KY`PrJ3iSi{lLjMkxc|}#88VV8bEJMHNb}e&^Ed?H3|T}&}ZlpP=GKk zm^M%oD5eAb6aegWS0$&siM|&5=_BMpqy}oP)lhOE0#2)A<@zuHiq$<*2hx;OS7N0s z!jd8Kd$9^p^$@v|7)C^$l|DKLFKDi!o8YC#Yag6P`$c_`wm~onzvyXND7gK9Bf&X?)elyf}CbA(ez3)h5e zBtQ)le-wWN&MAHt6L`*cPcOxZ*ja$&T(v)CX)jIuEDk+%?K5%w zAEDb(8PsIv1MFrdF%Q_vpfe2H!4ONfFp2CbLmO~q;|$%5;h-5xxgg^?z+4nJ+_(>r zG0J$u*bHRugz>3yC@5T%X_d(h!nn_-I>rccnnrX4-2#T5W;bBg7e|8Z-(0S?;7#UIsi1sr|>xdVJaPp8w0=@%9|SC>^*1KI!iO%s0ct{WxS~aa0_gVAAJ{S2*c~O zG%1+$LTU1OUMDmfr%}!?e>Wtk333+_P1?&lr3NsFyp;QieTb{xREiZ{iK>^2H^jw+ z=;NJjPZX`5ST3X!i?&wS&etMts)HZG-y@VVi9gL(BDa)0{y85&&MAbS&A%jnDuZ~! z7wa38HT)_549QmG_(13LdrEJ96hDd_QXldWd<5C4W(uc;)5M{<=oRz|0Hh=MfRAY} zKKkzB+`H2OaG>E;c2AYJ6r4GS!4ebOFsVyLY<)s(XTiYO+hs7EP04T$S+ULS(w+bXmY`` z*V)fEJzPezN`hZqxp-T9?owum(MqDK)s73@+IhzDr&aw2Pd#(Y^~{qYH}76aCP{Z2 zceX9tiE5y50R1TvyjAS)tdJYfC%yGdhv-MNfisH)*%{CuyoLkp>I3Nk?_Mm@B-8PFhdlG{4R{cv|=% zj3lc1L0H54ldbAPKHagLJW>1{!yV)G7xI3Gm0v*=b(rI{;}YT3zI-nKMc<+x;+H$` zyQrslo!5zn(oBdK;`IZhnf69|gRW5Hz|(mF_Jv%?75map4!)j|*&V=?ZMenky%6Hx z*ZZC6P!?3I>sIL5#;@4sW36sv**}Xj$~s9+cnmeb12z#WT)@-xEvONik2`7}WFSn! zU+@%|0{g&>gTRHfhaG4UP~;p4U<9J?C6^!$K)X(kLI*(lc6|kT3P}4G*6cGliX%)P z_|ubiS2+ubB!e&#B8gFs;=(-;pq>*dU{J$s(N>(W_$L~<=h8FbQt@KKY^k@)Z=L|t~e{Zay$!o z66WJQ>IxI-6TPnH@O00*c|z~s3$9nZtm|Qs7j^_~h`rM4WSd_j3ct`| z+w925`0d&J)I(ie=~+Xr`j_$yskQOthm$YpmefaEI{tbbWZWF!TuQA>|2hsGIv_;~ zCm?#-krU(uz*-4kVjiflS_nY`bk;)ngdQNom)s?%;1H^k81#jJbG#S(7I(;MUJW9G z$U5fMmU#vUyICs6IM-ns8!JrV4%}mF`L}G1d2eG)rAS=V%Q0VR4XdFarR9Yqe7Igk zpGzK-+IqY$;5E6ZZPM=Xb111TSGVzjD5ELv;q(TUXwTin^tb$mTDEAoHWu4;A9t`; ziR<(y?SyLM-RLoQBX?tdkUsH@^Nhnhp2H{cNhA!X5R71PwB&VtrXG5bJ?HtlH*G|h;(#sG{lwFcOmX!uTIj0GhmcWZuW?mQW~ub9K2?|U z-xPdXxFM@Q?VsNKS$;@!y(2wxd?V%sZHU{}{#v`qm7Pu6_8PeU7eYe6BHR1k>t}}% zPHISi+{^EzydAl?T(Oq_X2&)V06$_6sH%}$s0)esW3=dxV)7+)lq+GlVvoZJ2lr4k3@f;f2T*R@3gd3Y)N&R|nxSn8ALecIQkiMNiU*e1T_tJWte; z_!Ioij!G|RS$OCJafH5tYr0J=rS)cB>RqzXGg3eAc}3oN&TFqd6Zk$_QEi~UW|;_9 z!`xlz2f)BvEIhBMO}slG)#S__Tc%ft2S8snJ>dWNXD9hQV2qj zP)qPZ4sxU_a&>THHGvExAKs7-XUAmh&L^XCt`&@St>(+*mEv3>s%%UZzw&E}dr~8- zm5lu}GBNOMp52+HZO|Hgu2KXcURQ0S; z8)=L9F?UV3zo#OK+*ggW>Z3f`b=&pY^#sq18nmvSnf zXFHdH<+RDIkoSU5%deAHkT;TluUF9fYp)Rqjw+~2y7NPP4R6amWH)h$(}khlWxYRp z$zdNOo<^1W@@H{Q(AL=L?PY;Ed%ND!fy-W18GMc{sxmstOS`dl=jR4zgR`rntP z)gNEh8y{Km(0c(Y8fHzgKlS+qtNn-C7AXfvC3~7&N-E7=_$;*-&tf}Nsg_UynNaYY zl!FNHX}l@ifL=x)hxLHgK(7Kn!vXqXJTW|n!7>H(ie$6xrqK&oS5Y_olT8%cgK6(* z9{Cf37OzX>6dtSF)p#`0gI$AN1JT!g+10dYJsa#)oYLn^s=5vs@A!0GLYBwvTBhZZ z8*HHFrOn_XFVBnf2>u63K!Av9CS=eQK*G0DWsj6-7~YkzbJPl_86exR0RNdy^YsyU~jj2kgmupq|YeAyccS zeGNYx(vr207=mqTaqR@A;*3^R+l0xuuGZAHV-}uj(eyJu!1(gBn|Ov#dN)=YB0lOd z>Q7obWTWPu!&ggjO)YvV1u&{T zcFy$aNE-2T&hNt0gyB55=wfI`TFTX`sE^cLU!z8;>-CqsF|W%*`AIZHDEvqpc!Pt$ zZLEA_J;PNPA@v1^skA{%1FS5Ck#uiSco1HuYDM7FpE-RBH=us{*!SU|d~mBM)t#U& zdjY|TFM0oO_lHjm+T`r6XQ4WR%WCUuEMl6#prgnT{%V=Mg$8VAdLh)Fdz;=-d9@#NLAI#RM-KFn6 z9}3&$6jNr)3#5nS5n}v1_=Shgs4pA~Gp4+>^5DCRoco;(B8Jw?4qSme(yWB!^Abx?-AfODJhbM-S>@&9+22;ka!@L82!wwmG z(M0+kB>3nT>0rD!_ABeHSvCUoCHf-z8zQwH>I_;3ar)nCEjj=-w5Ogyx(>y&$unNt zfM=@5JyQP>ht>X`HTpZ$;J>kNS%T7(+!t!2v~M?jL>Y5-Yna({WW&hxw8&Dpk{7;e1t7SIfj@M_lQb9g%JhL7kuv@-mKb>lEhrL`?9(RT(mHkEcnaa3SscpPB(g6+T) zeAb@P4Uln&HsaqRjcip;IX;rZ0kwsRVl#eJ8Rr_{JdDPf3$Xzqp!_3hBM5}|h8J?c zm5cUzup*9zkqn~FG<`8%QdaX4xtGA-cE5S4V85_ccqUAR zH#tpO@Hn)j{g{8z_h^|t=tYT}fv7{~voTsIAMG7wFH)M3rT2!rN*g0qR<(OGL=A_1 z%CFHgQ4LT}v0T^za)7474G1>01`K^jKU1EJ&X$+?O;gsEuQ%04(ruQJ?42p?!%9Ol z^sqqafc}Q}x4sC8EY-3KZwt||CGQSc)(1Bfc^*6ftA}3D;7xb(iJ<7n#$qe}z-!{o z4sjXdWPha<1g}M8D}r$;>{ihfXA9KN9E>|{|pgYuo-ofijiZfwvf5s& z#1mbO+zFn+2sa*UmUz-p$C**|$kmsha#nIa|6B`+&QYItI~(z>x%czpa%&153zj+~ zKNf^_q5HM>o^evVc0?Vl^}{^l*u>wt1HDvLUF2DcQltwZ_!1y_#GB}bLxfgBbwK;Y zlSrBag{SXT{A&OpX9}(8LV))oFT`d5OIAy}uK+veR(zq$K*a_A6%hbv7s*QG0n$97 z5N2KzAIsV3XTlbuqU91cAFu|!-&F5P-&pRanyEHKZ)dq%_p)5CA2wCbYwN7;)~8!` z&>C3#b}h`ZqW0Ocs@BnzXY=7I$;?aBAKZFhm3b8o6Y zJd+KJI1>=9fZVVTrp=uNC-1$NGMDAH^3L6qoFs9=0df=pq&_Kyp?nDshX%&h@*#X0dhlQQ zeBJ;9*hgL!U%`(*;4jHF7U9{ik8*n)g6_|jxK{cv72l8#(r(;mBY7Kk8*TXvK8x>x zfWJYx2*RtO09ydIiltBq;7j=$))2st{3ON$!WD_geF1G_p)G3$z&pBFZY#hzue|QH z2T-br!^9K7iwn+p_8zD^%&!K$287O1(%=BJhkPU40Nao2fMGk%Oz9dn%CbA(X}Ov$ zHr1QZiI!2cv!#P}w;aS$EW>Glf{bn= z{>}TMM~lwQ0lc+RrD}u%!D*q#ONBv{ol;w&9R3METE0|6PTrATY_(^d-a&uEuAytn zh5R$Q&vPbqZ{c{MG$coTu1B~dClzlmYiuxEL5{GWl@z6n5~wC%1^)-{h3z~V*O7s_ z+@BMi=0{j3zKpj*6zj_d@QP^5>ai-UD{i>6^aq6_0y-j^+woGW!k@A(tPr=@E_iqh z$|1{qg#=&;@^~G9dt)o>YS;(&`9y%NptJN9)~$LK^9O{j;x@SsK;icO{2b5@TehV2utX%S`<)!en1bN0eE(?%LoB@2=9d=fR5*7VT7$? zv8FVI#sB*dSYY+b>@TZxcGOa5=S=Bz+T7|+nq#?-63eD+jAa1rY?(oWOqs?nnW74s zTV{|Mmi3TsLbl@_7=W)a1_UC%NuzNYV3l1*k;c=)Y9kyHsb*h*>JS!8_>{*eUfi6+ z7`dqz>B&eBmpmT=*0QmCNLK_lB(4#&*`ke z=?t(>R)#3%t+R(xQz-z%s=_3a1-!ldd6H)AH+t#Uh$aJGbHxz|0`x8XJPH7Ind{a- zm$B-WW!Q1c!)&DG3+6D@L)cx*s&tKII-73Ul-9QFM>Wehnr}*5&;ZNMte7c+$s9|7 z!HkTVmQM7w3`a8)5-5~4)mM8qLV%CAroVzt_Jt?eKVV7rX8F6~9wBY$8~c}`pGkLD zB0}YZXvb3}{5QGr)y+N!8w2rC)%JBc1)Urariy2w*hdSm#V^3MxSAU^au>Q?}e1GZG} z(EyF6iTV{l@QA;O8vvi{b{km=e3V!51LEVI~Rz z-VfFQSU!7TN)PhxmMVK>xr$n!>o#`RvO3GRY`|1gI+xijZ?QaUKaEc^#eOoygrx9i zro1kxWC{T}mPIJE>_pC)@FRLd%TzTP5=!{b1E2ws+iJfQf0w3}KRczdt-jI*2%dpn zfLl)*Omz}1;lItx#kY$Tix$nIt04@Tp=d)fFS2sW7>?Iui z^!CH}CkNNG^K|l;O6(7D9`!rq{nxlz!`cTDU+ETANpcDh1u1gL!|byWm}2J#YH89+MgU$a;< zK--;r=j8zaMCx(4bv?BnPkdm@IWyHHeVaEulm3#K=!Bm~5 z?o(?y=8InmrNme46PY3u2r97)kz!+VS^QEQElm=W0WnwFEN(}*6e%4NhX7KXd`}h) zL*!b@Qo~A0P1$Z3BirTDhGUgUN^e6|{!*3!d7fNL4grMyl3RKSa2xN)1_H|1z}U#; z)|D8`_Zha)FKB%MvA48P0^ncWvB$Otc$}#1u-yS3v?}a|Qh-p6|A1G3I)Da32J{6q z3^43Zdz)&*StF}2r7f*~kv6va1-jL;DjjDT_wW8yHq(@y<=&=y$;D4EC0cR^Ns|#q7`=Y9WdHKsp!Xb$E(zvY;!08<5zkAJL0|ToSTUksZ z)88+-K6%$4W7V87c|8iM&U&=B-_DL(8jE?U>Hqw3zCWhwHMEsl>)=W5m7XJ>yWRn0 z5h)@&*_Wgp>5f~XN9-!xmWrEKtk7A=N06wAO@stM94bMI1Ejf9S81NnXG`BnDMl}l z2FoW5pGkM+G(dbH-;gtnt}4ZpZh*W_X(g`*P@DH-0wC`2y&N>tyrSf}-n#&Gj%T!I zC4j2wI>u;_8 zE9+qORJPmF&DvXrvWb=+mTSuH@Cv4=PIOBTIbbQ^w51z;Eia<8wcTDAYf4=ne^d6S z>lf3YXIKRegw?Mb41d69C<7^^^(>yGSFX>4qibXsI6{^_Tici;X^7 znj-Zu`f)i^&I5$L;%T9@VP*M>?GYeO^J^Ry2dFjOd9ENp52S7A&wxBc_LkcKK4lzl z?OTAf8Lope2XddP&0vH*Vb86fhsX7buucH=uS~TTEXL}G=~~N;bfV>b_QvuO-C;_* z^4q5P0t-#Zd2-e2)iK&K1&Ug_ET0GqkNCCZCV7z1P0W+irAid^TWt?o>UR2Avm=Pr;WxMkA``ib?E%<( z7R(Y1_c14HXPC+7u?vPV>=IpK_=(+OCk;!m^X#$VeHKAS7$z}0YXHz)%$t=4FqKRv zMSyzzQ`^_m0Hvq0TImbeg6wbXHh^5@iEJV8>AkC|+6##Fp<_IuKuAYLz->Ssg*UJP zY%xy<1?Yf(4|vA%p{Dv7+R2hpYj6yFzA28Qv87DbS;k?x38CbKzeXvp8*!)a5xPsIOYJXbO^AN&mvE$DFh3^1(6LOvcMiy$+}Oq^kD96A0@t|=Yp zWUZXA&9hNWLfGw|wsl_neBx7%yzBdxzuBGeD&y{Z_3gC4<-rL3P%M>|aV)kk@%@1W zt6lVgo&XSbf&Zna8rJ4r_%(p#@v}U|@Dv|T8yZrUP0JZBV0NkibRF|z-y8iQ>qmPV zZsH@@EW-%alI{fPX1ZG|1t3F?wkHFcnD;L8C?Mpjr-~8*rLFy#!wZlW3U7t&K)zdD zq4@wl(FKh?0LmtMqWNRMJzXD;k^qb13i1G22NeKAA0A=K+_+=PZ;~HO$p<0ZvWhUu zay370inn~835(WqO|{a_UY7R?6jLcuwVMXs=d(>qSFW?%v~1>xDyGsv#|%?`)x8pS z!xUZ-ZukiMwduGLLbOZ)|DWP=KTO#FAJyDvbW~-d zxAAN5JvEt-gfx&Uy>|g=ic|#wLs3LPkfI>nLQ_OUKoAHD3i==j(uGGvg@8yA5a|K| zLTI4{64H~I+3kL3-D|$QXT9gsd(P2wtu^bn{`bzxm)XgrtpvfmCw*uGBD&Er>8{-s@?tmFr^AN2dV^`5Ao zmhbvQt(pF3`ny-B3%{1b25%!&btLsXM?qwYOLPR9D2+uqQ0gi-ltv+EE2q_JA@^%b zv;m;TY7NzoLsoP=r=@{XqV>^gfV$6-=jaVunr3RpLFw)|;8+fhvvIFg(jmAsI3YMD z*Cr>yD zP;=8e6#%riz5fOfs&x~95!ynjUon7(iluB-+`t;tpRt{{JtdL0SZ6j1er_3R>%4~XS*y<$95z4c z8hP>VhRJG~o2?T!RPXfQ=Ka~((T%I;m(6qP$L&SFX1>&@%}N`$?h5^PEwD4KPwaFs z=h@#Izk^jrEHzEA4_aHyPeXRHzmT69oOaO41go_*-g*l}4SS_E46HGBhP@8V1y)a^ z1jukz@QeffN_PD_<3TH=rqvnkVk9JZh#FY*2r*OBMc`^G4TychEB-+bQdDgIO#-v&Y~H{#Ne2bFZRX6*ZT? zR6B0oi*0zrZ?%Hp3g}X%;hM^e+RsZZD0XLzt^OImm)t6Dl~4(P)iG7>SFc8w#7&8r zWj&y-R}1VV5FBr4rR76@Y`$AGG~~<1!P1JL{~Vm^?*zf4!596(kmZA)1ull{6wC@3 z5XdYU=`R8Oc4>lk4Ez@|JDj=%t{cTeGTac|Hl|X72h>VRtauzAoX)Dl+gU6@+9 z9foc1HANhUn|CjqA{q)Kudbi~0%?y%0~96Sn1cKwu&5`1vxP?kaD1zM4&c64<`h75 z(^`uFV!Jog0bI{U?*h<%aeN10Ue1q__APn|K&0xIrKN!?05*Z^_(IkU{6R5THG+ec zr|fScCl`P28l?_%4J&QI=X+~L&+7dJ>0L9RL8jh>UJm}7^A}uP@ZJ89KOu|i)A*Ia z=h1`eOV`sL0sQhfSPC3}0-3c3PS;S18cffP%IjXaPLplijop1H_3%1Z8B zfsBV&bAGOI3SzC8b7h-?Z=dh3;{{NsDld4JgHqX;DvCmOG;)O=a)l{>darCTBJ9gR z!@y9xBk-Z_(z=1i?`u`=6Nnqw`h$*bA*^62PfVg8V10aUyq-U-E@?5u)0qjG8 zXaKV?e>s44q2xUPqg>HV0P&JJ20+=Yu9mxyGyqa*DILZ$L;`mxp%|2+S&j+LyWj4{vjcxo|TcKnSr? zh)1W(H=Fp}V^L=}RLn0|tBSuPYDsj;&C2$-xo2Gq)*etPtuKD6(;W)$>c^Wd0pEk{ zh4t4!h9626N1ySngQDR2TX_ZG$aNidUI%v%*A{lbg|Dt$(&|CM;C#gb6yZw6 zfM8GaO8_O#aYtIkSqQ)qHA4D_y%j*Dnw6!k^{LX!!QE2DI4eDCod!@+cwFu@aSDL- zc8YY6=qArQiy!6QDt<=+>WT7lpWuXcp0nCVc4u`rHHA<7Z2B(ODXLi%!^mGopZ>*9A^pVnHV+#PU zneoy})&+T$pjo_6=+C``!Ua=Vu$w8J4I7Myk<*CgPC7-<+B>e5aZS_JiP)_Cw_vcrX*h zeqa|=E>m|?heLHYUJx;*dTC5%RN=AV>C=zBOLwJ9nX2kkc8g=)a<&H$k%fE!l=xBr zR1sO1ap2t=@k?Y9czlt&eD8uYE9#<}3)=O_)*>I&jHrKGAA+{oy~w45GDmCg?hTH( z#8Zy9Ag|V9D>ns7&Mt^A83Nk)=p5(Dkkf5LFMxgXSLX#TL)~9%UttUA*`kyJP#ZYo zFhN-j~S9$d)B>c7DOm;Ih)urM+vO(MpsXko^H`wF{2> zN}S5yR^NF5_5)|3{Se^X%OEcGzCBLqeMjluuh;ZP{d#8>-aA>`>E5Z`%RTRvDeqYZ zo_Ke?}LKF~u{ARB0Gjllp0>6g_cu%m+&=?NtRg8fToLTcpTiKnUBxy*alBQrdo~UHB2kTP7 zMWZL^O+|I(2xfLpj?*21P#T*b^9byW;1OEOC+r6R+ZCKIEeh!2JqJL%5wxW<^{Y~k z@q)C-NR#Fm6#-~r?vcB@87+5pYrNbetu1m7u?*rt)U{g6{fAhiJ#YWyOtZ&palp^^ z0kQAGuo<%!_J*9aZ38};2oSIf*C`K0ABDfYAzJ~o=;&TrG*|`pEvrD?0Qw-XUj`nB z5n(o$+U7K=+qeN>AJIRRdxO4QdQ^WX&)*I{E%z6}I#dI@Yw#S`LFs8tjA&p{ zrmVlv)lh>Ofxab+-aX-XM|(ru`=q6vuasBc)ViyQYJYpDwOi$H&+`s|Rp9Dk6#(Qv z0(%pDbpjyd7T8g6b57xmn{y6(;!Y-xiaV)1?;NRKbdIzY%G=H56W`WWX$xTO10ciR zK_+n4{+2aBqBV(PptHS=XMncWRayg1vl1>qGZN8&2)zjrKo8?}dH~7!yBP$Gs=1c~ zIE;5jJuutgFMGq6YJA1ade`Y)>9Y9VisR+_jcLStMjho9T;lz}FMN$|j|tABAJ{hn z35bw`0}BAe_TV`HyIU|z45&+~Ps+`sF~f_x&`)WyFqZC(hHaU z$p01F2-+#ZH4FsX4m2k!WT(J*0P$lG>6W0}_NV#-?bY+e%I!CnG`5CcIL+?eo18ZoTzjamk5R7t zuZm@VZY7oOyz+$lCZAYi&G)d-l|%GH6LZBGa)5YSl}sUsR4WQQh6EDBJs6`q=Og9@~kmJ~)WJOF-ZoBGO>#YG`eq+@$hksVKVD#*DyT1ia zD$TWH>a(8G_+yR;dzyMTkSe|dg?~&#rU7VwhG8bJ;Suc;$K#v2~gkgz~1q3nt$jaPF|8?Rc~`HPLh{KZ-V9U@!O z0l^_pfI}$qiI=%2gpEb!suK2BWX_Yww0a=3k$K(&Ya-60k)SQbI57*B7Q&s%FezGy zo$~>*GE+`Lji#QR(P?GptRJq;D;HDo`&Mt7eJhyWMPiZus-x+{m&6t8Qow)zrm~Fr z#@m5G${lgoI>|0-GSP}bMTnv1X$%w*VVVGs#~%C7b9620u#)OPmm*xb7H0-2CC!JOB=9TU~j*)OW&;N|{K z`QQ6HSrhajTKUi;g<9TpYGIS^Za_LJct#_0tqhxw%-Ii_!-q_}j7+H;J|7RZ2M!sa z2Jl=pQ6|k%_L}>su=M?*JIa;S>bsf_n-(#^+M}PT^|<#9D5JUuL^X(PHa)0~^)-#1 z^@gF0E!!`4KpC&GE_yK&S!wi8yhZCsv4$J7ipN>6Tf>Zj{v741C@~|f5@kJ;ja({I zB)XWtaYiiVF?)&QQ&H+Ut;TrMl^VV)%+y<`$>wMNfInwqoIAnSPQ;|-irwO#HdQU- ztsS?44tAkA$luBsh?4tq=0KMRku?6J>wXJV{;?hFi0pblz=RP1et(N=Z}?k?(uZ9} zHF($s?99v`?aWbWMcMjL$iUf~aBxos2Fe@;@>PEWWM?Uc`V<#>Ey)7U@MuFUm z!d68V42InsKA#R8gyLGDu7twt00gu@5ou#Zd-WoBV9nzEENhQhwnKc|aWQH5V{#tv z5%pEkM*BV8Q*wH$Gq^K*&Yj+khue?t9k{-Gc{68~%tjA4<<*Et%i1P7lIGh}6ev?i z>)`vwBJqs6)YnkVN$98K`TD5S;+H69R2N5$*kNj$m~zgTh%`-$TBwW+Zda4-qsEEA z`UQ=n6YExY{g#rembx6y7D{Twa}(nOU)zQL)!9+T5uCxF3P*Dhv8>BS*Pq=3gj4uu z=LxGovI&?_XAWS15eG^g$h-sMGQ^*O*i@=|UZ?8!wJEYIQ`E6CkHlymSwEn--a^r) zA>8{Bq=D;uzyRkAzzNQc$g~~E)P2aDivSno)&q3-V-;jqhSHi)|4RmZQh=J>Ls{4T z0#Vu|;m)o@fmq#b`Qt^(Dl(s)Uq9aatm5o(zGd&ICRY0z(Wd9YBTn6RJsJvedn2~` z(j6%2vt7n<0r7Oqcw<}Kd2Rp|8i`SKFBB$U*7Aonc>)IuI zqxGEe^5&k@(D%6d99m^>ie4ltDl3a$O|N8rD^`hLtiQC+IHe}JTk`^{R>pUgo!I3v zKPm~%;eTUeS|Zar0auYJUqRJ@;MfS-NKocOuWX3A3S;ZS<^eEnEeHV0Vi19Fc3G({f$sui+zdfV@3q8p5Wt+fk45Obx?#`9rn?1-JPk^@@#2!T!9ft#; z%pCgC7hrjiz zNs;gJpQiB7NC_*#`of+^rYgv^nPIm9JwZ)DVHb+J1L59@aJ)}dQz&#iPoY># zZXYkXZ&wFTEts4Ljsl3xfyjBl6!6vsI~rV3AXJp;GVKGd^Ve*4ziy`Eofz0}+-T-P?J8XmS@fKu`50Gi) z!X}2z2O5SHzI)l>OSyyfs&5Ux*jyQq2d*IYb|ItbZh~RQgD|8_i*4S zXhVSq5NHd$0Qv2}{0VX|z()d(Sn%BpP`?CkO|V}F>lZ);dn;gr-4vND~G%5nw`#p;d= z8)3hXjsU9$GHWQv`h<0b)&J8Q;2(M;j6|l4L#Fi(n-sPKGRIorG0++U_d<38#R5kP zxP9Qf1i>?4#Db^;$`PooL7i5RI1Qe83Dl-g{#?kp5Zw;+@o;k%WFLhiTOfTET!{d+ zHh2z#eFdzEKm^zsKxxSJ$gJ0p*;~WAXLwHy?_pu4(w4C_W_SN{*!dxcFxX1^NN z8+IDVW`uQwHThqb!v8z%KkOyQ)RxG!3&@;ffEU62Ix_Dy@J)m=Gr)TeVpbxH`~&%g zq@y7+cV8e9qP|4tHGo}E_A7AKhVuJ?{*d$=K*(x<6B475#it;PYlfO4xlaq9El1?Y5yUs7U zcv0ZL{`a}e*>c(tP3+%!sryYqCy~N_egj9gT~jr6t!jC3j?22Xf=naWdTp#g@~5H4 z?+YN>27-|~iJrv~gs_s@@i%{w-@?KI5aJcy_x@e14}!40fw)ARU}-Q16}z5VaX9(A4!J|1r}-v-Ku zk$Vj#*;Kl?pC+%DIlr$jJ+qmM1BWic0&qK}6;-ZmP1!Xx$W#WoZE@0wacE0 zo~y^Hqy5aYkI+WV-cC*n*$tvB$NB0wzt6WZI4(1J)Qgdrh3=b&-0fT$j&KeG8jcw;#&1y5+y$K2|Kg9c}HXGtj1) z>lue5pnASGvsZ)p?ArCdn_cI;cmlSM^&Y%gzqNJmwQOhKt~I9z%oV$?+ViOUeS4x6 zB9FI=EYyR6B%q{cJnUrmk1k+9XFq-UjdMG9w&S%G=mshWod6gOY{cI}Sd19- zuAb6}zkxw6{X>hJQdV{#U{HApY{Ph!vgb6Qd71M1SoHCgX1tq^^ep zGtjQ3L;VYMaS76}nsO;ny{y_0{$lZpCOo0zRyO~aXxxnKnytXJxs=N*gi9}*e5aP^ z!8b|%B91GdOQ0U0q!lT;F!fU6sjS8bab`G5Wx_D>`UqKGODGSP6rxf)lTC0Z12LCN zbKO9cc{Z27;bm(>{%>G6KoEN0TieCEUjC92Us?bODZbBWo~RMAXXrl{N|>stc}k!& ztdsV7(a1qZ_QE%@4yCdgG2wbdITcE1A6oclv_Z78z5Yq*SFFdFf#`WpSq?4acIb*$ zoy^cxY+9J2%0uF$3Q$BDf;`d2l1ucB@hVPZvKk_Omy0US!DHUghkNH4h{p+gs)FhS zg)@q?smFrJT^l0cwg7$xoG?Is^qKJrl0>m>Q z9rtE8M67;Ik!DnWbZGYEja66}s~{W|FArr%q%@39jzs6F97zN(XD=rzClpQbL|?Kr zTwL84M(LhPADOXYCMl&Mt=)YUc9brN&69|&X&Bv$%4HEaZMBJ}J|{wI#(l%<$CmKcPIUGn$^&B{cZ z#1}>A5VavOkvHjOf%8T-J*0acbYRyKgmIFUz;~M_qD#Nuvn@tI8 zupl6B0cvX?_K+DYctAXZkJb$VL7|rv65EJTZg;!ox*^*Rw6UO@_YWAGE1%!W>)%IX zXN~29<&ySSQ%mDpUX-5dObes8C%Y3lW&+#j!ba;_cRM794wMpAwFYy1P+iDbs6Eut z_cU2p*GyZ@%#GBSH%p&-i;BB0FORmH-Q3B=@dgGVa`++9@$j7XRi2OWmYAQdAX6QL8kG8nN zFJiCuP~(cECB%$@m#L^zTU})fdQSq?b{0&XsC-S~I5aT^EZD&o5`% z+z&x$$eT)1#k9eh+3+sGBOSUX5>QzYF8a?Agcu4Bt=h@#ICXWQQ9|mnHYRNdLgM#C zFV46O;KBOlHzAxL^an1Mt7?mL#X-BcsU0e$ypKf!a!92&&k@H0v*TA=Cxs)#Oz=(w zu@PBy4nb2AlnCq4ZkuDeF{ZtI%IC2KIO4e$jHA)miA2Mw97u^CJ}$M(?vwoY@cXGIk@4i|CHx~bY$sd#YQWB)_Juq15^!u0>`Ii=Q&lf>BUO_S; z0Mq6VMtk`(uKZ%kznC>TU)0l88c^_Q%QtxvhxT&c5gZI=@;4fW36efDul^Nu4S)SA z1*dc?1&1b51O}$+=l>dWXMy5~+LlDXj|@}#VbEPFqz$;MA6+0n=tvJR*m0+!26W$W zr^6RtWy6gkvV8Bs%)@rWqBBYqqTb_QlY`BGGJ4FD!b!H#0*Rz7Km5X^%VXFUMW<60 zOi6mrU_fU26`OlkD3oMwThPB<-C*`nJK9@f}-38 zk_rNOGgOlb^n5w49utIH;k}~4Fv5A-*V0;^AE2WTT!|Xvd`&K<<(DMj7M)FJR%<`5 z1yY4+t2xA~P8Y@0I8Axh?|fjU!nPX4Xv9zO9%0~}-JZ^F%j2jY+hw}ctr6C;oPn?H zal}0jE16A~oKoRYmREtjgLE%>oJ+3)lABSL>8KRx^>6pie`Tl&Q`yzUnTtf&6WQl%U84%iEpQ z`S2Cuw(}P9(QAN*;GH%2ZgoV7gYzL|qx<7`Tdul}c@#iJTRDvFk5WzM3a+WX9*Fyd zp|D?yNE*LnU|RB^jVJISb~fMx5)IDU1HSfxkm2DXO-IGl1&2cVyyTM^Oy>(!5uu4a z`xPXEf#l)ZQ^AFhF96giLjCdmh?AKCNjwa~n9qxf2`}M$qi$6BHOl(2Gi5sd5+2m_ zjb3BS|H6P&zQ45KZ|c7gV&yv(qsdmGEVXienw9NXA|jb>hsMncp8WLqkwKCQB4Tf& z0C|M}=RESM;LSPeFA4rjMs$mq(U71<`P>_LoAZ6P591AO4ex2+i=jZazD=Sq>SbEZ z0X4;44)ytQkwk6(u15}V@LBZt<+0p|Nn{_*G@61>{e%&FygGDpmDfk76~aiOx_Tg9?Mg7zMCUw5{f5c$4s?ik zIdqRjIBNKQBv@+jlmsaQV%7}$`}Zn2wmAxI6 zGSzxQFk4pyl($=IECXR87;piO!VX<^cqaWr1)F{oBVi&FUP2r}`w7C`25);q&_%?S z#vim%q>kSL3hO}mpFyy<-oKJjN^{;zxQ6s6|B}-N=ac6V@}a}OA#C&IKiWb*wEwfl z)rH-WfDN8k7C;>c{f%et^Fu_fjEhxs719PhzIbUoKzHugdsqe^lu;7xDdzSKT6;)U z#DynFOMB+ma|k~Wu}ad_g!p0Vrn)}5mXnf}YEgiE{aq&Jrn=nHC--L?oI47xT;JBi zcj$a?xK^RZ22mA7jtR}sqRnSVzIKq_NnTlOY?QIhB7@3=y_hZ4Lz)Q;C0&Hol-H&} zwmkK>kCfCy_q51}=fR&p3$U2P1*RF&`; zVEr9T_Z}~ciPURo9kX3!!mT5t<7Hb5;~lF$Mu)7io9c-!Mu!aBM1zY7SVVOWDQ&K; zS5ceCY<61HyI4eH+v6um+#A+A#B;6gWFE5vwQh+g=+-BHDYkWY68DMz2G@iW^K>K6 zv&_A9olg=sm-}B{*vqWLHG>=Cxd!67*uUkzV-mT!YBz0wC;p&LbZ z^{6{2>&T8dNHPgt)^|?L^51y+EOXe zfiworZ3x5=LF!K z`7}_eetj%v{y4rmrf7y>v>%+tDUj4@qd)uiI&sz~G(5Y@^wEBUxU2h1*G> zWTSO@fP1E!e61b!xR=67nu$$uxqemsgmp%nf;j!3dgD?CQ%mfizqN-1c3T@IK*dFA zYi4;F9kv(ADJN{Ecf?F_Yu7mMuqy1wcw@f7JX;VfW2re!W0k8wu#)-)`3*MNn5FFO z<`K;HGTd{u+D}2QroS}@fKqfi?xc#8T_G)6*RP{(xtlns zQ?QEa+8qv!+pP1YbWc;Uit=9NNx%ZV^wLDFc^g>Ng~ue!ZIFdUu8)S4jAjYjNzC~q zd^G!DdU&3X4l``m7rPG661F)U`d597jvHZnG=RN~j-PBT=xbxG-0%LKuX$nodKlL< z`s%e|^5FuX5Fei_a{_=R@D)$+7U!|(>|73T`@L`dGZ!zks);HU*mKio?rr(-Rbc~kcM~E2>mf7 zWp(`JfNRwg`c#P>h>vEV50OM^y&HY`iC~SAQ382i$*d>(2Qn=oY5hU{%Cs8D0boG` znUVwQ$=(V^#$$B4qJ50te8hb?BJd`b-J^$~Jj85`o6~Z!f!)Wh_BW^{=%4 zE*lWAJDP`Son`Q8lE-njGX&p9DM8LPwg1Lq2ynJJCqb^uEYUgWg$J!-bSOlmg0hp1 zG}dF^roo}l@Igv03O?p9>)(~?-r@l{67?b`feVg^Z?dOT#bz4&fbrx{pk1{0Hs6vw z?gwiG?m`NQ1Qg0@y2sYFjk^0dqOPxdb%T6dlV(#!h2Cl9Y=M)s%~F^9W56smCp9af=ZZd@?Uq8g^uj_-2;K z*SX$O2IG~tFy;4A0~6!nxtb_ z>|x#KlWVrsDH!S4XM6{Uc$LeqMQ9jfG{rZUfpU@wn#%2J2o2d(5DM!5Ji${?mQSlB zXvxUm%Vp#zrt#-`l13=zunb`}sD}17=<4E74(%)%%)U|*?ToT1GH`CzZ3aLo#<-ih zEi;}=isJcoLru7?ztIvqg%l5c=!n+}&|I$f>C;>um#qQ1J5DTEhvd_0x@2Dc?GtYt z56`&3IyRjRZIE*I)QXTe*1QilnglI1!cJX@!SRK`pW*;bP|48o9ep~8rBA+eJu-Vz z37T6%qXy=?#n~9Av4zUAlQ>WnRZwasTsLjmE{RK>@zPHt9E4#dB<4F6`2)uTWoXzM~;*e zCvYqmp2QhmqYL1f&B}^tpbd=|p5$yI?q99rb#iZrDeo%NY30m$h~148O9{TPkJOGe z)I1>WPh|q^FrBn#ib`*5pTR2+A?4bF;>7zOEK>c>0u%xD2S_QEpY1Bs%cE$9x8STA zqB#H$eahjxf6OXq4BH#1X&U(-J^MqLvGI!L7HbS!S+y&8C{Q(IQ)_d>HgN?}2FKuz zmkcY-D|Epdqnk-YGc%tZ-iTb<(hme{2gav`rgdwd($bX(LT`M8+(=#&ON`O54P6nP zuSkwN6{igx;;jSAD|nZ*7xz`)g=X&To@Z@3Vu&P$ZVG!eM4V5K-{@m~f_=av0LPFn zU^uNs**~AFLd~^8Li+*Ltv!L^*@#mN3;Nz4<~Ut~sK`XgNm48DSBZbN7Of{-C1+9v zW1AZECwWZ#Cy(=x-jN5M*Cpm!&4PX2lJl`A|VLZA2M?h zf>(XQjLsvYxbUm6U;5aLh8k___1@#>58F|+|WO>v!- zbQ4CGVG=A!Jr(A!2!3ZnCvF;MlEZ+T9R-4bp}y+}itquTIuHe`4NX10FbyBF9E+00r5Xv^?-q zwY!8lS*00Zu}*Pbx`fIh06NWVSL;R!EQ=C*?71@VB6C}S5e)8-_Tb3b;j1ydJpHbC zims%BnkC&nXmju5hWLY{JvefaEY%*|LMs4SAi2~Yj1VuM&_-JTjGGNcOTb@| zz|j2~t)}hl=f5dl0AEjdk0)60f)({GQ^T_QDO0V2A;4~}7#J_l@u&*o(qP>{MX%MV z8svlH-3O`baZyF;X);_PTqkXTlmnv8Qi20p4n&KcB@7oVJeW^9uOXo5Eey&-yYv0H z=kSupgyGIUp$IjgbLW!hMK@VX_DDJDV9(q8YhGmi&H@GA$U!S;rQt=!y2~O+u;2?w z8IZ(OYdCIKU3B3RJW~+pSUoHLDFH7?A*FzE22_0i&KM-UJY(wR0T7zS(m|iVBugDf zx_#SjZOE>pk8ZNau7N-{h7Ri!5aHZ?WA_KsZQJ#=ZDSAZXmA7d$F$l6-%14H8A2df z#4=!(;FJ|ZIrGSnt(5m>H^}g$bze!?cxr1+?~Y@y5CSvg zyC*1kq#)`-HE?F;`Qi#&nhcz(WB+6XY^x}aEs$8 zpJF*U!LK3X6{priF^j$ngM-a_+0Z8K^}NfQYlP<8D)(_Ua1L`>p}UD1G(WWT`o<_CoNX}$9%y7$7^Sp^-Nt| zJk<<6+@64zZ+dW-oWYx#C6|oA5E|YBECPn>$|eAD+dmeBk}dyW@(&<$??dMzpvCMr zK0>h4N5T`n$rruYGp5M30%ihAzC9a?MtMtbST;98DP|PIt z%O`NNxKdgRxr8|5vjr)DQu21qebU%=O03k$3S1tpFO-*e|IRiKSubv{An@eT_ALnm z{8VEoT^0Zm9_~jxV6pf`k$6P493io?*%s2Fe3q#qzi=S}a7k~9_s{2D!!6T*tp7!| z9d;o5a0?5Pfj;Yl2<5zyMX`auMIA0NQecUx zuf{u?(H`B7N2Ht=7;zS~GW<-~?^fJ(312Y9VNT)(|pSb8%G~Ze{(HM9^G%;|f!jOJV$E=6Bi9M#TxG zNid=l;rw%SmKk7#ihUvaKM;5%myCb>$|Qeg1o^m%qqJn5{6+KczI+9hvAHi8-009)+!_RZ$Y z>BSGO?-Cc!cjxPo-ZXp|VRs*uW?YzFX$sXCI32~5N`wU5AQnJ~7*RBlk3LHLcVGs^ znq}VobtVh2lN$wQL%SrTh`^s(ohqi_1U&0Zguq0vuJ+E@9xKDHTT%C`GfdUq)tP`WTm%{h3gePuZNdbix-*c@sc*3t~A2KlgOu;ciQ@1=E0Mm8`T~? z`JRP(FI8VGd)_HUF0t&ki8+aQ&AC}$Tcx`bg7>ZsOodx~5#0~M`Sy{i#X;TlHkBtc z15-DEJ{ypp^cL4EkgaECJ>a)BnVF5&&!}Hw+s{X1c{COXJFscp*8mlZyIA{bJV$Bg zO98L0@K3~oemzO$Lb6nGd?Gx+S}z=@8xdbM{T(rZOB~W+TJl& zF2?RP+iWwT!*4zh7TGfHzdL+dxSF2w6;*2vW>!FaSSL%kU+;N8E$I$TXrtuQ z2?>2|Zxm2_R}b$Ly_25+y=M})eubiu`j-m_-6m4T^eY@*J9K++t@-Ny{?4aGPU-B1 z>eGeyJ_7+xLlnu~@zb_T11tpfEz z?7h1}9^M8JU4^5JETuD_AF|iuy~0^pUMwfZ0(kVY)ByGKMHdQVh8C5&oS=Hc95@^m zN?F-l%pF^DeO!Cm(?M}vt$ZmanzJRz0b^i{>iMQ0|Dvu;2h`s3fjHk%w9X@1@J;T* z3Kwa?%V9?gQmk*wL+FF;wF;D@7A$t#rax2{ilszlS7U5bivpL%xLV5mMTKeR)Nrxd zMcP_rM8s?&i0{(!<%yZ5btEjWkjg!y418>|Ky9p#4y3wBSnp{LCG`%!2`)Td33JU{ zPl;$}&m{;+p%vtXrkC3esjWA-ItU?1E@N)SPbW2;e+xu}ofGjw!g&T9PA= zVhCfc3J>FA)1u=~5wP8_JGRZzpc6HsEvktmP+veN2}-Mc(lcH0*Hni5E77d z`ej!~>rzz=!+-=vL&789Mg&jU#oW*0FD{9>eet`C^ig9IxK?VPPO5G|phxLf^=K>74*(TBpUQ z7N#0Gb(;kIB(@RwO}mA+Q;b&LXkVT|8=yzU7sKUpWp$=0EV;x|gnB=_2l&=E5yQ?~ zb*Or-DN6wSp@q=vpHgoU0UqXZ7ienx=J4f0B;kYvtls}L#tmT7M-pG<&t_aJPIKjO zDjs}cB712Df4O>D#&`jCn0e+0_Rt?ge5bn5H*J3GGesC@R$zl_(D#PjF4FcNgBRM` zlm%%L{g0uj3V+$4-;QXSBlkDkwCMHbkYV`I2&M%nTG?{kUq6{_?!-pA?R!gp?$dwH zkGQnA#@eZS4zO3q6C;o4Hp{NbD%9WhW6pdNCBw54ilYZ>#A##hT#3_;ow*VN3bjmL z{-oQbZAm$G;7E`a&4_bmSd0IeuwI3LgiK-Lzj7RNaJW}2xA|+c8KILyb2aJOF9DS6 z%A&VYqKOS*$Kg40dyt#?$qh%IRdzIe|8jAI41FksoLZu9U8u!eW|ySiP}qN9 z{5%MY%j10?NoF5a_@gqS-d6UuKey*$|Q*%t=7z$3ptpyLKY=M@Oh^PMH96G}6 zIIKB}#CB2s!s^N}A`80cP&x}Epvl@iZI(4Qaa?r)!=(YH$Rnp2FE`gG_MWm(P!7qjpZI?W4CzywsJE3?$xI#oQ(ys_t&u+3ZJL znj;4Yqf3(PISF?$u1?{>rG~r3GmZ6_D@v z!?7%wDstb_Mn~E@w6);Z`*W-V1B!?bhj93ZoBXZL4+*UZb<@RlIlGZ(DadGm|8v~J(RTH7TSRuyNW=n z&E`iU{uGkiyP9FN`-bw2_iUvjS@VvKx7PLuWcZdW?Xe^Gh*t3`6m?TkZ_IRCk~DCw?&}FtJbJ)j&aX#?`t-|l_`ktt;0TA`%eA^z5*5ocd!$u$L7$bWgBjX-c30C-_It+I+CpnS2 z;wxHQMhEK{@tTz@(%uh$G%#>IdukK4(qusxCA;@6%z6dRln2`l6E2pAK|)4q)7y8# z?WDQebTtjyBB@Aq+uykHh&pQ1UyoCe5`YgPBkXiJlpyOg_OsAt=|!HYNP8Xjki+#w zdo}k%+Mgs*Awl0!kaoPw7NBeH|2B0QQ*IHu({MjaO}3@J+jQTGK>EjpW#H2Nz6-*;+z?I-kvObMTm%JDD$0PeQ$)7;Ml#RI%8$DQ8HX?60 zEaln3-k>k`XA8FHi-A}=P%R3YsdpD+C?a64)i|R(SED}M%Xh>27|ns>I)f&`O4oY4 zG2W|DUyjw?A^o6a4!{kWa>%(Y09N>>w)HPf@g<$sEPe^?HmyWe(+?mArJKPE?ZnNP zO$5Kc_osgjcr9xMx3y~p@26`99~7vL{-SWU6RdozLJf#&MEp=Xy*{)cak)OcN+Yd9 z9w7Lb;Htowx|kqqfH3CsC_uiOmCNzA>fw2NO*xh?Pn`camQPW(^h10#xSTqSnaJ6C zcOtX%V|aTHnb4B&urk`gU=pFXx+2Y!MYW~;n1JdKe>$NZ*4&?=t`aj{iw8C|f`paZ zl*&{WUi~5x0obSs%v9*yA|_vDdd66eV%M_X!R(TEk-X75&^I)j|00|Y>E!m>!Q^UC zXW~s`{SIV>Erw}#vy;}JdGwlqG)BG#iK$Q)aqKEl$md{_sHFUgc=7xB%DeIV8Qbao zxyk$K{At+9yGGjHi7BnTRI}R80`|~)>K$>%{%pqT{`OT~-gr3}uVIZhE#cwI0p5p= zJ+Wf&^$?ERAdc*bl~fb8PQBW90ml{Dk|V~WNX&>Fe4(QL)Gfq3t4b!AFLyO`0c2Mm>2 z*ksJM@wJ+^hKjUn`gM&4#uTyb$4aIawEKn|0a9@YU2reCV0TjZnSv4q#saoM zb(5l?!e|7xSwSgG?b^RZ9vpJzCTP*;k0_D38NeeMZ{c_(X86}e5^)@Eo&WojihTvx z()%D0`vkA~8%NmqFAiTTbQF#s=URuxMu=^nvoC6mcPV!qHhc%svDIM#27_$Oem)t+pVd2g4=R6d_QbR zlfuD1Y2%SB)e01pP)C>dCr2>|Y3ltR0|$|pZPLo;?GSbuGuqqd&AMF}TGSTperepu z!!W?*_;9$f)0+|`I>9M{txk?wyP5%=1C@wPF(4F1wAc43BY`KwJ)6HflI$dflb}vr zsEp9<_-TnL#^5hs>PtA`F-v+o4H@nvE4sUO{|ca<9>-dzll>90F5W?CEqe54uuEBE z7@TNtud}IE>E9}Q-8C)s8SkHtnzj zJxx=~p+$9z66#(^I4`vI3Y&C$hePV=^!5c;)94%sE~nDkVOw>2hf5~;&9W|}oLf73 zh5uiq&pTquJ7U)N4Y4ntZhkG!hXtZ5_ytc8=6-qleJ!1w(1vq4{q!>Iy7|g|2iKpf zqH53BY(D~)#jK7A+B?q#i5tb_mV-PlZ6hZR@uYxTx5J%Ql1mnDBzeidx8D2hh*X3| zw`Z$(LaW(NDcJ#Va_14RTb92g|B_nGjgt&c^)I1yIq5P)CuX+`CIguG3A^AEY2m_ZLhIcD-GN|ra=&-K+OJHRd1SvMZvZ}ap;+7=+*RcXl z4uL4swXXB(J2@Jxl;v0qIN0h;X@~#V2Ia}yQk%j?o}Z#)AGdN&r!Zpw2^!*7{SVv# z%A}_wm?KY9V5Ag9UkB%;(2$#@8QhTW5g(knv`eq2D-e{Zqy3LdAOsy{FDPLp#GAp9 z<3DsmrWQZQ)X*oapb5RB7T!N}!@#uBn=Dk(f)V}w5{RkRh&<%gJZ|Wbq0b80o6$z}L z1LN)eyn;l75v`-9E*EhPH7LP|!I9|1@MU1!hQrZFVtL@NrpAFQiNT8MP8D^xG}+KP z>h*bS7=q$OV>cz#v3W#pXeX7qYm?5o)L$@q&<5dnXK=3!jGEkQgKf|zohW9M2v4(k zNG|^6BA)vjF|3_X`tvt~F{#Y>Zz($C`($p%Hkjh@Q$AVp0Ac1$UseyzEVAQF?h@E7 zi;cTpp8uc?*;e=5EL+I1$rJKePU}rdrIK3LXaArLMv@FnYmE@L6&EDJN&zXwSZ4-;DcVH>QZt}1kNMmlu1xL87Twl}^Cx$`&j z@V?$6Kr5`4j-?f1?aFA8D`$1cu|-oNq-5CO1kuOZl+f~KPH1`K20f8V_Gdr-p&N3c zpAXZLut8Ci_m5VSF_&|8>|R~ZzqL0KW<&t$*L}4|z9OM)TOk@MHEfoOHzPhkyh>}g zvbfS*u_ZPLJjtjrVK?g*H375aHA|03s~4}{sHf>7GMk?^TTopwJqitxNSae--(*3i ztu)jUz|8o{P~4t5^iTsE(p}=!ooqxlan(O*UNh#j{N;SN_uFTI7A=0m$PQTU%qnLE z88xnBYp1P$el^;H>sda){T?h~{qe8DGW?rH)V{CZ;?Wv>1lQt`QYxd6C1hEGTV%YG$qY-pwuRK;28^AE<%*KTyNz8Y@kX6$FSO&p%9q{&7pDheD&nnz|HJvf6); zhIFix$ffBN!9b0FIxQ3uPjVKNKu1@APnU&#*up(t($aB4$j18*(||pVJvH1D0TNMq=b44F527gLl_N_r@sF6I!KrbG75-jXM-1on)d(^D_LPh4*s13rT4xBozGqhZudSn!vwI}xv5ejOiB}IdU}qor0njl zs+Z@F^jt;{)!N=lrkQUJX+FWXk=}NP-As-F;BZAiL@QefPKBD-=p8q)+(bgK(%yD2 z%=$)Lj)@QQFU0-Gk+1ZcOr%=L*ufI2xPRryt8Wnfo9M5Id4S3z@7iBPAU|dY3FFUH zz({jHkm#O(;?#_PD#|*OUIP*y{u?@0IY7EUoQ#e;7;n@shM6Av#~ogoMv{#V>rZ=H#O7%iP^JYrnPA3P1s&ns%~t*11Xd8fy&;#LC=#dz;MYhuXB!}4G1N{ zOlLphW@u7iyHm|QMS9sBcknt2yT$`jNZfWx#9&MKaBUzJ z$>%MR3WP8(E^N*o61!{IS3JDtHjv2+D-UP@14qtrZcHw(7@rB+z@>#KSY1%Ee+Hm= zTMUfwRaC!8?O~fobAbu~lq8_QtL6QAE<(H{Ds!7kwF$VTL`JI~MX_kBHG%~(Sw z`D@=sRK&Lzj;rD?$%!L9Q4$%-A!ICbTHInxj*(JNF{Szqi8FMJ(i+;PR>OQR@k4qo zY%&DK>1$+w6)#ns+Q8`r9sT^IM=F;|O8^~aOQ8d#A5o}D98hbC@J^DzkrSnD{`d>F zn!-z`&yybiidND@3QTk$G9@a%MA8N-MDAEYK)D^hMDmW6DTtI~+%u|HC?f(d*Bw8j z%i1rNOD8c{*;K@rP&uoiEMTYXu)1b^c18I3tsMrP0KVqDMjgSDDWC{HGDBo3np_cPAp)@g7Y_a-F-40zxoq@HNDZB+aPU8RoV`Ca?(t zbHPkN;Ews)epG=@i3tD(_VHmvY?d+#IB?0?N0f|FN0&Xx86VhDq^MMGuj(}};3~~A zVGYMvic5mX0tAB;#j!>j=q$LBMS&&gsi0~E1_NhP zj89Nd7v@$DRdz3q=6o1#4ryYM2v>nUSWLzNQ$E>mNeFK~>_mwLuZByJf+1GgST%mP3U_l#D1v1&`K#|$&}9+twhF;uPSWu57Q6>PN?1}6AL~_sWeo!R;6;AV+y$@# z%^_?vsBuSubMapdiCP6)RQ1=jIH9%^3s%U2r)&|%0w_T|SEFY)g*bM>n3eqjhoQbp z_(lK#D^)7<8)hFeyf&_n!g&-yC=ah7+b&y_-50ideQ&%#X`CMfrDL{dsHbm>Ab_mF zW1)viFEd|ZfNvxpuF#9r0^OkvM7toRs{|^wxcKemhh*F@{ZQM1L||WO?>wUey5l+! zmx3=G&Q?KNmUQuPWHnR$f;*O8`3GKdViJo;*+lbUVTt$~lX!5%N`+9^D*``6zT}*E z5L~=`+$%yJ5N=is@gI<(q2>u~wk<}fHo-!$KXM%JPq6My_B~qaQg?VYB@uWS3kf(x z%2;P*K5Z(G3y7)I%6U0mkR93pl#b85t}aHy`V`8C?kr$!<{voVMF6vC9lHNe47F)Z zfyJ-kUc)yhLwY-#JD)GYpt!P(8~E*1y_ZVYB5Nybhs`fUl>E*KzS^1~!|Iz|H;m7% zQCDu}^5o7R{mJ|hYsZUX_S8kJ9D$|3{WF$u^}~FRL{vg0v!LUL4+OyI6_`#AERI7k zm(uyg*D$MsAXYAT=x$A3?#1}1LfKiiZ;qgZ%MV=WevsBZwx)KR=yq;9)B4aXal&0iLIe@n^1xhq#HH{#HuWb;sD!A~KoX z0*@S0qgeuindRvtW3t|=)@ey>icSAWIPO^hM{+^3vz6A!4y^&s1|{Gha)C8EKBdxt zNnUlKMnySogk$t|nd8!Pgm&|at#keNQ|?#S*S9`UoxUFEWfTSqgmR=q7BSq3Qh}NQ zPQ=5AcO-b>CKgpNf)Af`j^av&=?)GOWzrO$n^^Uq)2@U6#-!88fIuUc0Dmxqy)Qj@ zK*8`r{k)LdDPE)|X!R*mCzVXk1NNvwEtiOgqR&n4+{3wqR~&e6(T}W`)0~{lWd!61 zSTN=5it}8)^lswkcFeACr~BK9guM(!(wc|z&zg?wVX@#SCB zLMgeX>!4~0IU{c_n{WHm`-S!L8+NDHlk%nY7KKor_9d1sB0xRW#d{4poxS8hO3@$L zVuM_f@InX?v9c)_+_AhR0vSHR9C%=m?y1M`$5HP!c30GYN_J_7%a&0tA)&e}8(J1a6d9eE13ToRO|B?3~uqxv6W!M3=QQe-5{vYFW$d>dG( za`^I=F|dfI_Kz$-4COVAKeBq_5@$EW=zc;+!$lRCgi!tB^h?#ZA@%3?xKeixa(p#L zIesQwL5-HVnJ_d0kf1)9r*@FV?or};#K5q;K;?WD4O4hyhaL48BDs=qXGSwex(R6? z7cSwiUMg+}exb(my#m0hWaryp0x6a%BQn5(;)WW;W6#g_!AOaO+@bKtRC^=_ zg7{K11i?>|uS~%Z&5@(<&s2MT;9`^|tr6&og`?%evP`s6LDY}AcJ%QIDbC(C=-h}c z2U6tlD&l&(AJ;&x)}~Mq!jKhhzU2u%P+G>CI(!SAG|4;V+W#l8qv+G~qd0 z4Ue*qbHWT?Oui$m*e!SzP|RSK&7b&7k-evlSqcLvu`R}ir&lhO?7?w?fcj~d8lpLH z?63qc<49eoa5LuUn<^kr2Rs`aaiVy%6E;p0LK}=-A)rG_RSq79aJqzS9Ck8!3BlM| zoaEjHI78_HNRTBa9l$ zOVtdV$gkN<6kPK9YyX__xs28oX&bx_NhgSqtvacc5}Yi8HITWe8sMU0RIk1a&(G&! z;b(iN=j({?g>7zj_bG0LLKHBGiNhs=7M!JT>MPJH(5jOc@juAIQ}<-c^~c2wo}cwq z?+Q;Bof2yI^%_qSKHt%z+SUhGC)s=RwNB25Mn;#%z7viWZwMn>EKA)&u1f6tVe<(m zm|x=F{K^_=EzH?}fyTLMS4V9L-vnb@WB2tBH&Tnu#!tt!5pNg+9}85^^)O%5P0R9L zNR`B;=EdzGibAT|Af49INqfL;%e8Y1exLT%S^WCp9m@hyxlJv4U+M{;m&TG0)#XJE zsb7$7Z10jW1+bM4#qH83TUnoH8{hMW_oqJpi{H2B!<^bf)o!^_T|A7KFvh_Qr_GFvl^osp@QC7mBfG+~6h3g=^DFESI=x3H=z?#3ZA3 zY4khD?me(+X`=6fBhDC8&+=vA`A=W3w0%!;eH}0Mj|aL~{!X9p_W!5l0&xA7fj@$Oc7t?WT&?su4Hd9CG zjox2bi7!LgHCGInxYEhK{@b9mH6D`%n~E9&5+<*oFtc8RJe9>b5F31H##2zH6I% z%ase7O$HWM27MAR{8WFE&}6h;#$xp~yv4oX#{I)K2Z=k2GD{Q=cLsbck)!#e5cHJO zKc=khq8qX7r+wgA(w9rOdmIq3MwtE-&S>%>mh=vaQCGJX|A2Y7#k7^5=1txysVySA3)+7XFg! z&}#5v`@Ef61zSa9v3z>8rDfHv6;e%DDsYeN+;!mGC#vmF`E2pnMAWV<mQiq{=LLf=6f?MSQXJ`KN z;tg;cZBP`k9n%M|bJ81UCw}>G8%0Z^1BjNw3V}e1!5e$)ik&}M9TE${tn{^8@Az!v z&+)}@=KJf+%>@{1q7i}V)cN8L16bSZYH$ePDjg zw+P2RWo#3B&B<%Ls^28%)0;=zO)anfl!Onh`I8=}UoIjPhh`M(HixH#(+)dki31#X zNtiCPukTl+E+=t-;mVFgrRG}LjAE4qzr9WGHunt@b3qJ4YfmFBhi4?7ya<%d+%a{dQAk6ih>R*Q zmR;VD-`meFb{`k|Y^B%NQ zXeRw*sUjJOcN-;qKV(L8?8CL)h+Y-ShcGS881JE)<5bN%po}4ctJI<4iRx$L_$mll z1yxDT#m~?@6jaR&0y`VMvaM-CY*c)qv1bNCyK+F5qU)jxC2fjqcOZ%Lx#)%n|tArFv9N!4PZA{=2b-FD5fk7X0QWXcgK4Mfg zO5U`JVR{{$$nv{Sej7;Aj9xCp;o(z+pFbYl*yy>ncH#XL6b#jazxO`=ig3aAwKiOM z@1s}dVV$T?a%?B&Yp2iiu+I)R%TCX)yBNFCm=ipe+{8)GYe-inar7Pi+q~K5FN^}^ zqlyzG6H=F_=K-ShKhvL%F&j74cumf^8ki7Pi_we})Er)d9ZWu3S>K!z@umf$@xmed zW2Qz(mhCBZ8mJeXs~0}YE8^=7O*);_xTj4}$kriUI_-|Q2Tga6 zYbLx}a(Ox#$Cc{@H|Z`gA}ZM_PS+U%o3ji&=l?{Slh-0LELY+J?=qEeSYhHRcflWP zI&>8}u?m2vr9h6!kU6oZO;&Q%FwQ`5Lx>>sYP%t^m!9xf7-Sni95hscBF#Umme!)A zsUCd>jxI~MSpoiz(7+^7BRd>1;9jAJDg+$+7>RT-a8Shd1B1Qzyga!s_eoDC)py1| z7*<}5z0oe*8hWFiNBm}D8t3BYk;WckvCcPc`--THtagg-OXTsG`FdgP>7KZRbsd7$ z`Ig`5Cy^uqipSGdb|0N>K7Q))%3UWFkPO5dHx)$|i&rQ20Q>i;KiXsZe;C=KX`+X@ zt-&)f)#V9v2fWX+zzY!C2Mq5fI|mReB~3koLXs!ZvzRh6j^Sl2l|Eh1_ zEjDqQxglQ!$0nK}**>M$9d{1t$|?;pP=`%g$aJ@C@xrl0@T~}Y+kA4Ye?o_iI@0Eb zV>r3DOb-(l_3!p1Ofv6k(pQAKxyNyEcMv`5ybCthI}by(7dEc5Q}7W8Zzj<|t{NZ` zk=KNfkxlN(^?4sSLkvB~M#hV{gkAGcAi}0^5R1q;x=lRiNP{`yV}{Z~Fv}E`%d2?@ zJ#j66*T%k-8l_QQZhv1#;tI~7wmm&uV7GmEK1Sb06tiZSWXKVVByx9|Cc3@^EAo+A zn2A$rs$w@p5G%ys* zP=+-lHaj&dWR6Ax)ifPwTbTF-JP*zpiHK~(L?~Anl9$};6gzy>X_6ibRf;b-l_L?# z?1-!T$WuXxsHyrafhPDZIPVj>a{L=}!O%ywQ^ zKWLVnu+Q;c4uPi(_iLV8*U0m!{pKUUK&$?4$?E^3;XM{lkJ1+>##WAxkR%+U2-VMX zGX2XWY;J%wTAnbc3)IkY3fZ=_??u05h7W} z_4{LNzR%U$^6XD7yD}`=pS3i)*r>t|e@@!gg997sm>6;Hx$(i+HQ?+kC~m zUUKi=+nlJwp+HaCVce*0RYEwHj(*QFsZGM;8<9%zMZ4(`;l(i4jJr)ku3GN6 zszo0WuW4_e_TQj*p;0YhNt~H}Hy#!2Rxk?js4x6Ulm~4G#jdjcaY;uU4ZhT(-khQZ zw5a*0-{uD4DWb^Wi(nJm~>Rm8k-GiyY>CbQq_$4@v?3t_G*_r>ls zm%iQ;w0ip!4kDVF&(cyWhX5FJ&CVdBo~0#J?5KPTe?TY{_cBs-XE$>#&PL9ZN0@Rn z2ODy+)$FamjblfLD{O|YxjA~t#k?_M;ZllyqlsPO+sb2aeSjPxWP=@FW$l1OM@$c5~lYY6*7Kp4LKcl?d zW$|^*v_VKjg~ioFy?f`COU+b^4K89Q;j1Hc&hX~4iy)9PM&15hQO!PR!4s1&0lz{l z9ubGO21LeHWb>3C#B=Ow?J6GNOlUuQ7S=AP8c?~Z)=99hH0Eg&7$QjU4L{ICce0aFR8tdFcelKjAhA$s*|^Tndp6KLLBAl)Y3&0P76Cgyvx%g9-L>vLj3oMy- z4Q_*%;yD7s7@FOEZ+@~oq#tnJG45~VvEh9km?G6|v_z8!LK+=|$76EyUJ3_sj!-is zIY+|MeC$RB!zZZkc;rgpK1=!J$lKsokhcLS+OS2-h{s@kxu#h1vPwaQOq7?lzO%1u z9sVA#gxl#QF&{VvwM5X8G_uVPq*%=VA0qyFWy%l%SzwjMrL#sBzw8~ovOwjmDek$NGWPNft0>X* zWG^6T^0VGA8kd|`zg3xj=5CYF=-3A;<|EsXfP{F-uudApLR#%Pn=*c{(vI3(+gx_K zV$v4bmFj2B7?B$YOKXoLDK(;XwXMOv@`l#9Zu!6 zIbGAgb(wDzc_GVxvcoZBBRP;9x#!1vs{y(ac6BJe>Jurpv4nfhuuhEZd<}NB`(Rwl z0{V8HbhJA2DGKS=P-v@Sraip+5sJh%5DFn2F$Q_$Cb7G!rb-`*&{`ln6!>Ft znjJ5t*r_rR?EPO2YpDtk{xI-j5l^e>g8HdJ5?$5S^aDsFMoa{?%zA_G$(tITb^0`- zCQKJ>ia01uUS)`Bz#GG!{}ncf@r=V&D77|<$`4=0&Ps$dtG?S;vP9e0L@Ru1pSKC2#K_w)wVT!m!OE)C}Z|G5k;{GXiGRa9-g#&j%TY0jktfN=4z44YKbXyG- zTlARnRo)(00Ft|I3EEQGSDgI0l`iQD!z0QR4MXsJz2qgWHCV6*rVR@oYtzzNSDC`Z z=z*9;uh7;#MJ?FGEPKlAFKnnoG|JGcy0WFwi{Snc!m3WZLieMo=Tk1ONM_utpDi-;6?k+bVSZatH5sHbFuB| z9d-KeMWr3nW?3&tOUJX#FtKXruD zRH_*5YUC48`x?P}*@rkR6-&650+9%Hdt|HnY$Tc(7TQW+cD3n35W^_(uh$wB8oCTK zmY08Ws$jKaU*9&WM&7Y)Elq^4*hq2H9EPMzaniDZ)eS%st@x9PwC&m`tl@iE|D4^} z^FQf?wXxh@cWO@L7$Fr2x5L0$#{4F6{=(ML6KeBKJ@iEU)w1Rh5)^H~I=}VLS}9w% zE3Bmy8W$YA%RMS2{iJLXK892(oMG}74i|AWqo9ziRqZ?A z9qwW<7Nz!001}QTntK-UH=)|%U4#roZj1=0(%K#2Esit}J*n(U7=yPBi-t;3TcG^z zCe!0dno|cxA9&kG9+WyLlh#e|4HB^O{Y($OLx+Q)Sor=k`?@|F3XJhm_Ib&4T7-Iu z!?l?_^QaJzN-G(y@J*dd!CwE(KsxKS>j$r#-IwLG1m@qJ!50(}ib9Jg0XC!|rLSYv zQ-MId0e^*ZX+0N&0(m`X=6|K6&w(>nx}RBE$eR_JH?O>CrgZm^8R^+s@d}MpH7LwG zG;9_e;Tswu2ZcmhHZN!>9p?kGJ#=q$fX6|F*ac3XVr4DZAU2Xb)^23S{X(6VS-9QOrF~8f zm92t$dfMDYeM{}=1E#vBbLg3B(uY)o6WN+yJlJez1wLt!jk94$Pjt5}Yi**(xz5MV6Dihp@b%$H4z+e?}t^&|& zSqGX%P_C_4)C-AmEFMEBpxu~2MLveDvfXy2kbPQpzy<`ZM@#4Ty^%KeBL<5>?5l%I zpYaOk(}om4EOG_JCk&{1=(u9SAOHzfb4bCcpW8lFE;Tq|8l0v(8UXX2OKu;yPl$2j9$?bDRukWL>PjK1vgY z$dHbU&}OJy8?Qgh@6!>_7JDe#$RO6J`@r2EkBb+Z6s0Q8U>P`F2?>NQNPCq0hG8<{ zaU%Hy5iXP8Tb1?F{Sc=%VqEN+_K;`14Psr-!fmu|4wkP~qLC_&#U^kiBYV#e<5Cd) zS{?n`_LNPK8`+co4*gyDX7NU2z&3Bv9&dUo_KT&chyANHCk)VK4-=@SgMTcmYV@O3 zce?@4`pTrOYZ^C_rNJ?rg{-}xV*^+ZlndkK%2S(b4fd@~A5&3wfqsd(IHz7$O53{6h2 z731#(x0xp$=l5E%S6WV=741VoPSRPVHl1$E`#^rjH>*RyVbPetfE05id}gzxu3rTR z%EIPhDee7KjbrOm+x4V?O%=;vyr(G|v7DzapF}6QzdaAv8V|}w|6ND75h3y`SL47_ z*dNy8ieo4nR6g-zOOjtt$wL=r50CQicU`oJphT#p#g_|v@-%m%C!Wc!Xy=Dx+(_-f z09KK8q4>P%Bv%rBbX~?@_BM*qdJaE(roLF$iDBCv;o3!*u36XlDNSy_3!av8+`PJM zk(|K5Q)?)Y?BH5lVp{aP&FocDqw6tf{+3KO{N4$Zv4i6p+Qx49lZ#N*{Z=9}p*xKv z%KamnRzynD$78+0a*1wtxbp*5wj@};<^b0_f-9-IGZu7{D)ISjwA+OXy(?*3ko9wm@9VQI z&F|6=c1(}n7jj26bdzOB9BVUSi!YjVJ1!dMrRaGpuD8-UUu>vqNzL5Gdo=I1Y-TBz zPWqs5K3glCm&d$Cfj`@sM^9l#-MafyUC?<721K?n(${1VTEX`DnD973OL8+<%mHEz zXKhC%r8l0e7?G{fpD_gwl;mjR{lTHZQ*ZVAH*^wv42z@PFTeW&P$_?NQzTXX!*gbr zmjnPOE>}V+2$8z?zCTnvp`D5~gS#d>{ z1LheoB#iUy@JZd9A>^J7P|rIazzW1>@W9iP4h#tnfoAc9agFgg>&52qa_!uY3}|b9 zErom)Vd_RK+~S(MUpR!S<-{BWVe0xU4%PsDj4^eGkQ>!M@MtD7dTJ>KkSJ%86I*%8 zsX(<$E^$?#@76k-L9{knk!`5;f?_ssGX_pkGe_@M%CK}*6R>r*u_5wDYRVvyQ=Ze7 zO3BaaZjLx}5d5wwhdV0_#8T2TDc9FM5}rFk_d}13%K;^i!F$NWz(6CaG*43tPM$|x z{7qTsa0g6A+tp1A&^B&q5U*k2R^R}}a(J4=F5ORo-2<^YS*x|CRZ|KCpPFPy63W?+`Rb-zSrC{=hqw%%ILLldZ)7p`&f|eDV@i4BPE))9Hw(J!$grFfLcOfAyl~62?wYCH%_4 z15mV(x-JQdZmDyWa!rV6eNbO>x{f!lU%GPL5R^2y1?k<%g|psm2ArbU8t0L@o-%Qp z#qPffH~|qF&v|oXm8(+WvESDZtr2#aoqO|9>&q4GKu5}JZ46ZS89z{wx1h(yJH%x3 z(FNCtCEQt|AXg0Iui>gSyFU?G{hm#|hD9d9zx*7uU1jv>U!Cx_z z9YCeWq-Pl#ChJvAlgyl zj$AFD_B3&179OUAEMNLm1S9226LBzqC}%BV7tNr-v!y#~$LMGPv5oiB+=he)3ozoz zl=61@%Z8ibVt(^6FxRpd1pO&ae=Z<+H#^=!CVN!NOkv<+1bCgkZQsv^mGUvpA`qWG zS}JA|zPs}7G3fv3Xa90KiA-V2KngV#f*)un_uvnuUlM6SAU@($at3WGH&>PqEEtnT z$%D+6&-&>-12Run_TS-!$mFen;ezEr-LWJr*Ln!hzxrot7(r zz2Hw3pQgFlnrW`0s$;fIQn4Nm5}oALZ5)q1KEHPasCI@q*)xe6p%ABro-WfpRK<_I z|1QmjQ3k=W89Zzu2)pc%pfm=z;=olF7-gPK3deeu1zL`i+t zVolZM+PKBzQSQls5o6D#vDv~UdfP2`-Vx-8`21`|)n#j9XW#~a_*~s1c0_2x0%YWp zw4u>)jat&yQ88@2?^{=1tXUD^fR3 z;*YZSg5QT|*1VB9qSIK;fJ{l)A_BO`^s1Ggr62^AsIWZ`6H0tnpIggRF5wyG_ODqy zJNC>EZq8Vb{g8H29LC{JO5%=pHvv{}i;S7Nd(t>nG_Wcb+o-N!4x72vqnQDJb|%Q< zg>P;SRb98nZLbfRWE|dtd2XDnPYZDODoWeA-6)@=sXX)V{2C|3`D8|iq(PhHvq=xY zljeo$7L2*ajp?BlEEsVo)$pd6546Ntpy9wRy8u0P(=avcS*ssCw+-8$u>}OGnoz<|5ySKgwCoJ zDVBdv=2UKOAOckS4$SxuI#i2z)IJ znlEi`FtHy#|-**i}_) zssf>Cn-rB-NZmwr1aY#F0w66M4b%Ke&uNbv#wlaqm{rou$-VFQ$Y0=q<919qaHMst zt#3O*JeZ7h@f#7<+j3A>n0O6^T^y9a*ikTNQe8}XlRZu*dl<^d^Yo>5qFP~(^w4u) zrIKG^3sv1^hW=%2ERE(i zJJKse#MtLG4IIMC%F`c=ovXzhW`AG_CH7b`;v2!LJ5%$a7V#D7IE>BYaTDkX_%P&n zY79PUZeuXU8@3HbFnag5jo8I;8PMrf9lx*B=YdbbN}V*Ye>c+z_^`I=Va2JC^+5Nt*{7`t#^R2?T%y+mfpRnGEcl90H_#(amNIBW|?IRm!5YGd1 z{Iq}BY8;DcS^0wL`Z(T>yQbhBfqtDmtLII8YhU?nr}Nnv`u5*`W6FO3_zidJ?h{;u zoj82ErF*%!Bk@ip*sJ6xC-i0aJnPbyU?kRmllavHpsBr0N46@q8kSDJJTWjaC}4;` zzHuX7WZb%#ncJvi$>DI3wmzg##n&)Si8?VEDKK4<^u{`+o@o*eZ@bV!fY0D5ux(3I z3VSWNs0l!`OS$A~!k4zy*7!9WpFCftLs=g@NenrW$!lC(HRgZ!% zZM*D0186{H+deDu5@XJ`Tu5CR!T;BqGZ14WF^5EpBarfefmkyHUISF=lUybt;TmTx ztRtA3Or=@#H-w2sFz%>~qE0%za!w5wNTiDvz|c<-V>Lf%{19!OTg<$tkc}|cjnMyV4XMYP~{Tm`7d98AVQBLEjQu zO+a4eAk~UKZQg1{pR~o+*kg?n9eAjWt-2e{0HLl3Ghn%%h8TDqBpo1zuGhLH_GoWW z?itWw+^YOvKbtDFReU9tVkVvBI`SP;{!(bCVhc3nG0~&qDLhbzzXYY@Nu(Gh9&4j1wC=XCtNo2*@Skf zO4;%4r={;}vl5T*>9M1am*?Bt)6etk{qaK%?&oXfF0LyM@9lMp@B6^s)5q<7;Xn-V z$MgLQ?{SMQ?`Q5{@AhJ7j4RJ)@~t(GH#i+R4(_gUW3Odn9?f zI9C@fZW$_Z)e^vXXX{-6k*fx@5&8%Ndk6tRuROuTd~P588#2}eoot9Edj@uQsy-&3e*>CR~A>+JQ?S^hONayvO%&gm=-N)^LY_=U% z%eiMQDf89xIcdbB=8QY)!n4T(^+ka-nd88UHM!%Q&QeIjo>i}lQf0-)ys=O+*8R^N z>$HjneJxL`q6<&!XNk4CLL=J46Ip63nQG)k-etMOgqz~ocEDUq{cE?5TutFff2@Z$ z!D};iIj43Ck9Vp~=kIR9;ua!tWzIG;8$(Su+xj^SDf14^MiclW;^lajFht1NDV!ck z>A$*)%n3loRPlLJywO0)?#hcQ zG;>H63=pKg!IL#B8g+owdGTZ(8zCWnH+GX*5qQ9wGF@~Wg0gUP%Aa8n-T6!88Iw7! zEZ}47L>?{?=lv!je2!jHM*zd3h`@jpP~uB?&Bu{#i7;zx%5sPX9bB8?x8K-p(LC~DoA6WPnfN`egD0Z@C{6o=W zv~ih%n&1i%-TXD_^cS^%<$nNZQ7f+(WDB^5N*8?bG9KWoH$#>}te{n03k@yWLjjdY zKT0UQ8Y0=W|C_IQRqn>PbgtO=EJTJ=ZB+aHzN`Xd9?7A)P$s|z{E2V!v4r6zz^H9{k7c0 zFAd=75|uMP)xRiMtS2|j8c*uMdO2Mff;yFBBA3F>G+QNFDewmi7A-UXuGwuGdroUU zL>p@$!sUj9;u6#zt8ZtArphvWI`HTk9$N!kNkw{I^q@fRNGAx;aJM5+wv8a_4+Dy)Wn@~F5R9Z5@6iEZw zmKtE6dZrfnC{u;>t6_D0D_A3C*4j|A42w1lr1Y8vc-u)OAAHAjY>5+z? z9<~$~2L6%cy$$oHMf#^mo|kXwXBUju-i*`Ti)-j;^W=L!f&c~K%l4Cw_*aUofQjKg9Bp{MJQkX>a-sK>uNm$X}~g}8GqIjyu# zH37$|51a1&N+2%l9YJ0a(p&%p&}FGM;QEP0tkx9xlM6KlTxmSh#&gyZ1S80{5>N@_7iIqTBL|%T?p}{TDOQBdh>Cl2(kH+3eh#i!&Xuu)K14+c` z33;AT@)qPR(;(%A@>)y{MDg;iVN@>CJOV~F4CkovrmmI(4;Wd?IxWJT9 zpNTAiP6P`NyZ{dwODx2|qZPfAP292#=-`bLLOsFLRaqi=)3})vsesg!w0CPtx39~< z>QywGCx`$@ENUE0{Ix>$NN)=wTY)kW6xUL^q~QgGD~^X^4GryE!`XH4(F+=JXSkI* zaDS|mNP!v0uuk8LO{dy*L@V3U*z;^!jrB*Gi9+<*a;6K0bu>j}!x#&u4k3YHWNlV3 z{u{VYB&uL}iOoe%eRR5Al85=;_+L-Wxc!o;MV%}eL{S;!AJ@=n9<0;c4#%bXDLiQd z=Q90}<{$@vtKXZIL(;CPO)Z@2l&X557e4wcQolFo4&k4Vuy8TgJP;3ZBFymaR2t=1 z#I|=k5$>b>{4{=%*GGIhn`u6ntz~%8`_ROyKop+i^deWEXThuW)=(Qdn!l`_P3bi?Sa)DdF0 zyoE<3w)s3}>oN?<;p$mcAXZfESw4j$r%oXD)squ{0Fh zeFfT$oq2Yn?QL#+Qjozl)`R_U1Fd!qmDZZSKNA=!t0jL2Dj-ruQ{LX_SG4iQ2FT3H z6VkU`=2xT*a{cjW*ZtP^H+B1SgXR;NYJ}v1$PA`?eOce!)a0%vsX(> zbn&f6U>+giN!$MF^CLY{4#Q0y3FTyAroH5EWLjS+_6*~BOZtlEJ!gpt+-$S?R#v&C zyr`rU8nW#DS62G%Z;ch=@uu1svK3-9Qh@=E_7RRW9_B`)MW?a;V~n!5v0o}WHHMMJ z_EZ^~P0aDd;BD*uDU>=|*IE@9HtpxCIXty9;!(>xW_bxuXt=~I`Za9k6ZPkir?pBZ z6u9O4SJZA~`RN4S*(oec+byQYZaRw+Fx8=UWZf|9rh{GUnD@0*iHO}88i2}moQX@J zmzYrbA5BY@T8$)BBU}wVeJx9ry(uj+^g=8?d84XTkD`_v@jh;?s#W`{`Y`R}g_!jh znL)Wqh2RnR+3gbpieNBD-RvZj5W$ok6IY61j4Rr6!kYQ^VbMI;Q3^r6n>9A4CM?LeL?v4oH)-+_+9G2vja=0iDL5Jl-Bq1&FJY z6Z)Qu!jZt;SvZ8C4(1j$u~13g_YXB*Dij7$rLd5P6iT&J6;cEilqjMjY2y~0)gZ_a zrWT8bmYz&Pg0I+sk5_;)%B#1!{Yl|oa2abRVv|o&I@Lm-80-H^w0gfg&05XHUGw$Q zbH|tz9R1xAV=I*gRITg+t-E%syKACPfLGkpy!VAf7cn6Wi&4t}T(`nm1^90}5UMSG zyn@a&boIaOKmq^T4&?uF=Y`j&ywVFJ3cQR#FD7#S17_`yXlV3{?w$4Xs=Tj=6z;$C zO9lTszm(v=^GoCZJHHgFNK|zk4;|;CnMeuz)Wy-jcHD?ubBBBR;07!a2-^c*%wr52 zL)~(*zSIrMu^OmR6Xx)JzT#q_BB{(^5&gn~8Z@LV72>+Qf0Kj`?F|;;_z$5mm`SJl zArogYq6eBFP2xV2pcG{_kzj~?bp*tqwmGz5SM2TG!OHu|&=2qT{q5uH$BJdeH0_^^aQNiS4gd3hmXj+6;Na^5e0@8Y52uH4xH%-y3LzdMA4_NK%SRsX z<qgvJTuM8|~ zn1ozj_>O+cjsCu&#~V*CZYZOTAILqbzuTo1ngFj{D2u&2LM+7ZSPORlO^~XJ2Sll1 z11*L(dv_J~B@R7KMOqu6z_&bGzVp-I*4mS>A&&b)+rifMOGRxCuB#m`$(ght0HARd zW4C_in{X`&fJUs;NHe!-sjd^IbM3uCU4{BvL|0>pL425sCkG&rs_yae@G*JnZ*cjT zELHdD967Z6HwOsuZxnQFnu>=cC+LsZ!UEJ0fusYDs7K7TP^@D}76*RV&`in?wnK6| z>WiH0_J~N`$d{8@#l9e!boz0s;IW#OsXH_-O@lUm-Y*L>|4-k#T)Fo5gP#k(-QJxi zskXYW&!aX!+nctP6S|-8rv<;C`frD~FD$>0m7O1;wiUiszOQF4|DU(}o4y4;-`8ip zzOVbK6S+ROZjpJr9$URZ>PFqcD9@oW&!RD}CcFOcs=muJbdkKEyR@q(HHJuBee6pc z?4na923*B^GkHj#h=vFhUZ{n+Jlr!|?4&)5WzrG%)D{VbJTn``>Jx)Q&Y2g8m55%s zc39A>%`Y*pT(FJ``;nm{?8x+nxq%31z^KZ(6%_Ue%6Axn41&rHtCo-TJuvrj!h{V$ z_-et{D@$$YiNhkLf;TeV7ou@mpO&x1F$(^>tljT4be^TaP9exz}-y3CHQ1&#Y|LTPjM~f z0Cso3P6<>rK6ZPe0FnhSHz8v9B{W1t0hA#wGb7Mx;?Gf5tQ+&kzQ*}K1@o5N3U*yE zD|gQ8k zrf`m?F#3^TZ!Wf}yPI5{J{wvquEugwG&RL8;*y&=vsNcA+6Jc8!Em7ks86rBo`H#={XL+1L9HAC)JHe2N*0fJG$@uv;x}t@|8l$xZkc>h1 zd))T&q3xmw$}5G5Ajna2f9Z@I0RL@DrBbqut-#2FWyy%Yg^0^dl#)ybO)bA=ZA^Q9 zx>JeEeh*)$Z=)B&cr*M>T`F{N%tv%RVt8^--}?W02dbTm`3I1aNA+N~mE1mk=^b}~ ze5ry))k-ge217W*B(NYVG^XUE@CJmV1z7c^(Q8=})8M6kM7WY>vOjw?1_w~W2iCe* zKM!={DbNSg`T^?Mqn>Vx7q0bvV`%o*N`E6p!!ltS6pk4i_MrC<;d_P zCad0ClVNclfyH;hw+AD$z->baXWATkn<4%Cp1afIylQ?;J^2u{N!SiVdWc=Ol?9 zD_4-yZ*WiZg>aLw%chedT(;JSu#sGnvO5f4RfO`&;7%)NP)X9W zIt7qO-jR)K_iaRJ| zmLc3Dzv($e2%H9e6x)f^Zlwz5^PjA+0f0$!Q{A+wT4)OUEk~T{W0#Iq7D_Ri#LeSU z5X7a5@ah3hCC_kH{@!rM6}!5#oMkiIv~dBukWrX<;mr|lVKe9y;@TjSxTR9K1cE&( z(Y77BSW^4O-U78Io*nSyCOrk7G5UG&km(jP^~ldr|j>tY>O@#HMKMlHvtnnO%lhb9z7&tv)eXn9{yEzQam#l&GzoQ74RR6jT#jy?? z0rDh#-o5S8L9cS?KM!MhVat~ci6S>|iOE_%2V5+i6+aL=D0bE6KQBe~DoDLi>W7RW zR|VYBHZ5ClqHO(=DrLV%qHN{V&?gNe&m^_&@%m-pMeiw`pQtdh+3CoBxf0&v=KnMN!R!sn z@t01ok}!nVLM=TY+k2gbUY~{{=~rGBxdTFujqADD3nD4tQ2x0crhP8Zfkhb4iE+S- z`TJl}i;&b4>uQonfBg<8d#i#+W*cZilg=8;zkbJ7PgED6n?Dp)%RjdRqeQ6{qP=e= zaPi(2$Q5KV?4yevE|fPJ_{ZxIR96lu;^ zVJ=@h`W;1@)*eOm3hl|-BoJHZj6BJ3jYnl7zqnN%fHI9mlH6?>BLTw6+AD$Hn=Rv4 zV8#EAPvA-@Lx0>fbNGA=RV(X8F7ywrfh%JhO3Dx__Lb=G`!COMMBe#e9;1Xh+fB3pnE_+U zZgDDPeAoveBoJ_sz{QS4+~v~Y#}%C*4f??O1k?Ge%wY|B!2O7@E1GGD7>k8x?ht{P zYF}D8qxy9x8yH;66{UQ~)%~dkOX)|QRL$qqknqFR$~TjkkE3CTA@D;Mbi|vIDe#@t zckg*MYzL-f%IY8CW)u0T++%gl#Y{Qa@JaH<@4Z#dd*R!UWW`BY*v=1wC3j!S<4BJe zKO^O3h*X1fO)ECqT_uY#z=^;>{@lp_mKzkmM`;QNu1U{GtZ5~ zakp`XiQKGb&8x)ECSC{s6WvI@@+-1*Ecf~GR!L0RD4g&5J)#$ zFhP(J7DM~pb;E@(qIe@fJhBrQE#StnfKN2>l6B%GwxuwWf?-U4@fvxMR0JWI!sHK7 z(Qv|iOp+KIubuP3!N9aGBYENYmeDPkbe!44|Dov`!!v1uZS0M0+qUgwW81cE+qP}n zwzILVjc@k5_x_lfnyTvVnV#y?c+T7JP0@;<=X}JvYXiNA@W@uAiubpnAQPClNq3OZ zN7Ubhu+pbCM`%jpWsi#QT;A@cZ#2%2x+dsH}(A&JWQX7m>Mi<$x zQ+qdRagJjT*euR}CHP|@KPP>7hi zKYV(>oZt<}Vupx$2E@hSEpzCmtU`ashy--!-O78dT_Ec|@NY(ik=;(9?;shucf;PQ zF|A!d!!?I>TiL5pWyrj*_0Hj68G`E4y>KmoJ#!AEMgWj4T!31Ru2qfHO|PCkarPOG z|IyKDOC_8EU9*&lK^P$)c=hNq9G0k+=TK?9Os4Zpp4ud6NrZn1=zey5~hU z-~_j)8}|ec<5J!L)Wd->NknnK=?n3c*kCy9w`0>xU~B2vjs%MZ4e?~y*J=CPAyGYw zRCO}keG>K@qb$@taHPp#S)K~>0N;nbJW0bIOv#iaIPI$`_b$2ZPUQa2b4Q&7t_Gt-{ z;vIe9HPa!Bk02Yb-ski2^+A5f;EE0!B9Z>Rz~|rI7j;+yhWgtE^ zkUXBoiO-umUMHv?$5x>}Er~{?Oz%6witiPrx>*f+nSE=^rIHtjKq4RSR`H zPsB>3sjl+>4Pq6_Kn8-_eAI&a6$noNh7s~)%hBct^5W6v+W9|0@|Xt37{Y(sZZODa zgFQk?`|{(!O5Y$;vH}~kWHX=NZSmibBU`|U5i_9jp~r)U(GK9u{x?Y4awliVWI-%L zK4=jSC@GQMI~UrMNYdV=SPO>7o-Ct@$)g~49D5UaP98g_U!QD;1;l|>IVn{-z?bbd z9_8lqsMCNz4yN8HU}n%*Z=a9&w^1Bt10lXz)lMP{Xhhlh*!90b1Q8VxiR{@lel~)& zrVFDTOO*y6K5{sCvj~6HR2vOwn3cI>8Jq|sRgS?7;7~V(BanJKHvlday3G>c?te8F z!vNb_USQJOuo%DmsZ3EP$eP&>sr%LQ5Jb8krZG)}n zW;4$SP9AxG&z?!VhP~t1#7f=*bvcdkzulh@i0~bA0yIZ0VkKUE>`ay0s*)sxqp*Mo zQdz*OV636@tD>4|v;g;*L!03me9&};0HnyxN^YqdW=Tq>3R+C!b zNr)$j|KQOo)x-dW{T}3{Nuqj}AKl=^Pm(WT1(Y(_fWaC2Z3KHgPyT9i%nU8493rU+ z6E|ciB?d&Vz{D0wCNCImA&p;T6}{XaWC`oUt>43R&qRjeJJU5dYIO9y#?^|$=0F6~ zD~qa!cJAdC#yw=PkBWPbW+B2k^Nr!7?jxTTBs-5U|AQiH$w{nUJ= zVf1H@n2ig_RirnK^AkY;RKotiCy`r_Q2!C@TmmPqyJ8n$0H`M8{!<&(Vf>_x(IDcQ zQ#^k+eLKI;>P*A+HwVALR% zBTC63@{%e$X?`g2nYpq4X0Z2`jRhsd5;>t{aqkIR)FFJxCub zptH*=v|y;mF7(2CSsZN7>kFK?Cx$Q}WntyI6=g2u#P$VjAGQ;Kgn#;+&XofY<{~|l z-J*DufqqdlT)tEGdr%mYr0JSokrPI3_{*1*Y(S7F%i}HeQN8!)1FGAs(GiFQl%YO9 zof%$k3SF{O)TYCg&Ow*erY)p5A{Q;e$gj;5YU?SbU%?Z=uUh^48$Fy05E#*-7-#yr zaD~u~|8}igg3Gss%Qsv|^@ULi*t$)C%HkCfO9DU}ym~gUTSzNJMu5fg%mG&9RNh~I;L_US|^(@W>B#55Ew;ZQ}u`UAw1k;{t4JOQT zW*^~<X8>dHx)%CI_$#WogH5Yk2c*6yoeMwCG+0coq=xsO98>4~%8Nij zRLW*0^u4!{dw5fFzYa&ZUq#$%*osO$F3|rv^88YwB5CSeM;1pWIkS1b1z74kO^s3X zmyqwARyD0ljGtIOU>&ZJ&4rB^={r_`eGOy-K|||3XLp=72jrop|!2g?#Zm0xSt;(a<(o zIVT*!2t^KF-EB5S!RLSz0te8D-(2SH<7-Z78}R2_BV+P4DaQkZcS+xzjytrSE(`Pt zsZ0QzI!^&O{ePFd0v&IPj3NOjlL|mD8UIrTa#jrgxYKedr+?w9M-lL^@>9 z>Gfzkoff1ebm`?twM529IUz4jfzJJuFgZ*}qub}zdFo1uMyB4E)f`#Q=zzeqr_ zKQxs$Vzj`7Hl~;gI_6A-M<`dDp-Xx1GPlKM~N;KMF?O&r9fq55|(+GD@pE;M~n$$_HMLwgQMz4qF z@pXz$^K_y00FlU&6)f5jbN2i5{=}D*G0qGeS{ULTZacGw8(*5^E%gvjMNcB(UW&dO zOFB0YxStW)dO-6UozA29G$|E4MKDZK&Gp;FPu*%~`%CE3{k=ebsAScLmx!`@1S?Ng8%m=p{P z8Gp$&Gce_f$P_WhGDIvRQP&H9AhT2aPI=BxKb#PGr<06pT}J*r8?Uw52AT>%590 z$F_UrnhUA`GZ5JcBU6Go@4qC%==9wT!Li&M${e{MpUd6+ocG z`ndsUwR_EEf1XhD(j8KAwx4DJg&{|fOH)npcjtcv=JmA|Ucd&UR(-ZX^i{|XcdkLY zF{vJ0DHHewC)RBH01>8~-G0@^Miyd0kLnrK`5_r|g+Wzpm68j;DUW=cdSf!i->vfg z%GNsaAqr?Pn8|f5?Aj`|K3+_FF!|zj^cQxl0-dsF!ecOHWyqZ6cKDItC|=b1w%8tC z(y7$c#()kt1w&CSMD(c^eqz9n1GppZ^e1oxL#L{#y}t-R?yd8Ij{!#})S%OBp>a}Z zQY_9Mnul9MW153mg3;)Aao@a-H-$o*3p&$>ypCIVocccS`;1()0lYI$<+Y%aSx(Ss zTV$O2wglQ3QSpD=d93G+bn<96g?kMPjLaU=FIea83mQetY5aO*oVwUkCAt7!pXU^E zn934YBDjCr3aS&5OuBCSDeHVGQ>t}=Arc8{0q9k)6%r09XEO52e~paRqP*!}GW`rk z;^3cv<#9?n29k|w!=HE0JcZ~8$ZLB8I^7f&n?nLZ`F)Za*`@vHd1MfB79hRL%NY_w zNzn}O214XLyokcLP5b?JAeZ~a4_}sK-@qk)j15@yRH~@+Di8a5zv;V&q+5h^{iO^? ziR-kON$wC`OE${=TTo7>z=a+t7@RGFL&*H|Zs@7heDuu`oF=#HTh#)QnP_}w!NOu-bNv<&YR44}Z+I1*K$2t|@*OPO6()4L~?&zC3 zM0AA|7qvnDZKXFSWe`{4ao9@EqI6`r{)yE(3)wqnU}BoXnZ>BQg@QNHA%wZOBHdJm zfU3N6ECi`O@&&1Ah`?Zr>;MA=*&SGraiijpKSK#yVL($vSos1756E&-T_KrXIM;#L zRm@aeJ1TJ)#W*)F0lPcDzD{<(@6JZ~KJOOgd|x-OM)*EopMASk43Y>#a$<>oM{M~2 zDT`Qv4^T?hK&~?vX97G@%(!RY&-jHZ=Z^i~-p+6+O=Or)-T7ce@*>YH+ZdVZ+Xr)g zp9o~e9Y&?AN2EX+v?7tf-j?qDCIKlslxKeAuX006ovWt|-fbZP- z^m)UZl@D7dtC>8kSauQdMeNYiXDYLRh=$j>fUt+2n0{@+D+ZBoAVAFo&y(Xb4WDqs z=Tx%S-n7EV_Fw+$pQrgtdQ)^=(^?yp*p721KjzM43@#Qa(Wd&>`g@d4Ys;OM{Q8a0 zXD_DT+kNzQz`N|?p7$~Mge~i2=kr2tnE|4JE0@W6T-mvi2~3!3ev`#N45K+v%}?59 zgbYK$k@O3PZ$pdOKa@m7NRRfuG1dsK)C|PfAM=VH2(orl+3&b$VCEi}y0Ht^`Wt{M ztX4=9ZNcYj|8M2u@zEr8Z6^Y-^{{Bv>TcSMyvpS+YYADU`4-+SrQ*>mc-QTlCLQa8 z`II-4Z*IGwgvc4taYuUZtd^g0lp&zw&XkyYjkte0tclHN(<2WLO zkN@3)Pr(IDOr?Eqm>pUd40e#<(4Z1?S|i~wiV>%%^?7BUwy7ag6~Ar>ZVHc*PM{n^ z-~Z^=gw;VDgWG-}5vqece9r5*O~xtfbl4~vI?omjN0m0~nsryizVq}U{pU73QYbHe z{s#_4z~^wrL|9CjMk}rgz71|JT{cx}$UkVWl>yy5zI|uTCW-5RA(O`yj8D72Ye??n z9@%Xc4e5h8va_||J4)fLUa}NT6-%Bj#d&&-Lm0uL(d1bciZfs1KkgMY&jkX&b3u5o znSo|!W+FbH(hiDFR??!Hn_sx5qO)q`Mgf&TRntBGhytr%6R7I~XAOZ~PC-*F2lE7h zF4(cK7{lHE7loGX|~?1F%Hle*tC>j#53NQp)0I z`HUBZXPlduD_fZ~tY#3)A-RHb>xpeI<3!oU5?GDP7hnJdX5Q5z>4obZQx*uZ|9ELs zG=l(#V;Mo-q>(hiNR1**r0N#=yUBC!JOFB%wcS!uv+P`9@8%Rg>96m4+Qb>d-L!vV z%iHFeWt1*%dRk>%;?ngeZK0-4-=g4DA0*0bs zaNuW~1Pn&rw1p)v8uM}FCkTGd{L$C#V#|xi!~=Jj!;%wkjsb2{cEcqYANtvdXNtm} zhBWE_h+>%ry&QRQMx9fD$tE@i_n*Bu3&8Dxg0QXG|o1H7%Tp-w{wao_~|n^X>f4W&NKKpVQ}Ev8GmnQ6W9yPs$#eu z)=d4eGojf!cFN_H#5nc6oFB|n_r)hvZPQB1isit^}f$#V7YMW3EF8a7bf>Tg4 z;QM|uuAB3)mIXTe$rzeulS86I>?a4oiygs;mBLmSxb3WVI5-+l=pw*>dLgOfl#r5t z&+wx%;jGDR!{p^|TH^4aQ~=NZQ99Fx@AdFHV&Q6>b0a32f9@FkOL7fpfaCPzcS)ni zkNaQZ^h`i3S3TGpp1+Bi;h+Z<-V!kZ|nA-iG@fU7sZ1gHmMjfJ8+go(xc+B4D(*XxR520KEtr+b2ktF|LNYu6yLt+JTd260Wa5b6x6RKJ%Eo1p;dZ zw^Z{;-;z(JOHV67Ae#$Q8nD=^;mipQ7)0nZr?m<`7jgFj;$ zTkMt$c1AQdsd1?64XCX}JpXrMEBf`%Yt4A2fUPO-01@z^FPfj}f$qD%tft=QQg>>$ z4Sj4?P!{-=*ufkSaR-|XGw?~fi%+$KM7cvdDCf;{-)ATQOs z6G|Q~CEl|-0i5g@>`4Yn2-eu*p0u4TgDo$>tC8S2D??NZk-T=;sAbl_Ru0s*z3D z%>{6Nlx+2D@&_ zQQxnz4;aqhU8~I;B^G*ltoj{5i3V)*`)1%6@A}aBqnM|w6+U=2Z z1}mty=D<93rO4t;M0QMaE|KxZU^v&4n^Hju9YYAw!Gq+b*pWo)&^K~(;|e}Rr(>=Sa^K@O>Kgy;a% zy$9m%kMsU@|0`jT-0ThBjXj7ACA9AtAxuh+m}>?hSKkJ6t}uN0h*n*U4_8b~p0zYx z%?fH_4^^NaTfT{cJn<-xa9_wwOrFv7oTAE5Ztik3Tdxr@LqOW-w|O`XcyUF| z76S6DxeE4XKme8!@*uYSCM#9Xut~6E28uvzvy=AqvxgFWclP=>>A2obf)V{LwnTtZ zZw9e|g$uK8?o{b-{v749hEHMVDqmHtDZl|Hr6C*e(pyn z;q;$?FXovIQ6K{-w72nO8R=-bj=dVWs%3Dc)*J0QzAqgc=SptDEGSTxHf@|JtX=KP z=0LYkU?~9F8#db4#~ZXrq1|V4LkOD^G2ssZGw*kUqoJ`Yzmft5pJZ$QIK?0G@_2Xn z6$MBMIEc3M5(f)CSR@SSuNmI29Q|D(trh&6nW#$OH8@@g57>H)mNDYce8?PaEtFu6 z-73lmQS9Q}>&4I#(fE+opAEFY`)VbVK(49UOI|bkTn>hx% zsa%ZvyA0eci##gS6Ur*5%mLpl$7aHp?>oiW5+R-PWOs~qVQOr)C(M4oT@GoMXM0e3 ziC%Fzc65JLK`u{Mghwk8R{9q<^$v=&s#`Yaxy4d(esLMzA9uaPsWI*?L$gST)Idc? zfxKLZ!WMk+d!~V;=^%;2D0&MiqhZGZ>1grw83-vM2iAIB8TOS$mX@J0v;pEQ`!>_Z z6p9J(WRp1fO(a^Y8;=2ljM{DPXTIl|>h@@&&I4T$W%uw3u+bBr`OL;n32WsR#pKei zcB?QAOI0e4l%`a#w>W8KyS9UoRXyJlo(3`G$U-PnPER=Hj0l zzkv)Hu6ort5hjQ(Q)t*U!J$#{G#S+(jjjoPqb9j$bYW|9PWoX`Zj(R)nwp#WzDC7q zC~s#w1V|BY&Y`{G^+w5ASjlu2@!Fv5{uN>MBk`MxUj{6Kup7eho5DvxSOBzYnNYOf zosL|cn~t0$lwuF|tE*6@Bmxq#yFPZXGgP@SMu5aTM|3y z9-GaeduYxR{zHn8?dk|ZD0PO^;^tq^rF_D2vr)sf8QRSrz!0h=v&KnoQc8Nad$UGjeB^vvnJbt;FL ztq%r?1e6l!lOSOL;VNyPQ;T;9fbdKO1BMKh1*}2^L1VbnPIn6Yj2Is)8&-5mxdGTdiMM2p5mal*!g>E>Fq9 z%NL*T-`U;oXROcTe1yh7ZhB6au2&~)@1o0?LEy17FLgUw471S7I)V^*BeXHi9Dk+nnV&5CRF}23u223V+ zoWZ{;thL~X!tV*8>s|K-@Y8zU4=X{C6SSvO{8Pn`=AEU0ohR?+`tB?TxuA<ABI z?b_1rzq@p6KRKbHO*#FRv(^2)9cBCWek!rP3CDb3@p*VYUg%j*+clWSaX%~14k0+v z__9TJ$smbq`nIzFN+pOs;pvtgEc2nqCLk7i)1gcE2l>s0?qj$K7a|6bTDt2a>KIJ^ zvY&5My5{4*A-9Pyfj>2$l_hoBdT zF_A6ntg-3ITj`%JTl4XFyn@0@4o3U6Zt!<>xziQz%Vlb)V}S@?|8ReN>FwmNJ%hc+ ze7%kcz3;Ws{>@I*Q_V~6G-@HTuviz1RxuDEl?w$U+^>{+zj&n8Xog+%O`_0Y&hx>D zn@>+&xc4;h?eaaq{@BrkFDzrp5H9x?@4N<2V{V_J8R!E7zSSrTqoW~4xS2~4 zI1=VgL=-&p%}5r5eh+%wF@@g;_tTkMIF9IH;DYyu0VRKdpeu%E+jAtjb8tt>K-9u`nDwMQ$K-IEHgyDPyOvITuEE{ zk+_9(2a5iTJoLQ$jcVVb<^_p?>2JdwH<+cYm7pg`H_Sq{6aUAj%- z1e3BOQ@LTEX!zlwpTHGsZQ~n0f+7HIVYT1x$?(U{?yoZtX zX*FBFVPI;f)Koo@*!_59eiZgH884rjRH#gJZXpu`DLBMwl7+?5TzTE@`Y)p9>7k)V$DF_a7&|MyVLXT z^mH)m(cHBylJr*vvxiOf`|j!_7H`+*{cCr}+h!Dt$KYbO=j&=&_eW*^py8Vt=r57x z%9Q$IYF4_ciL-MhqHX(mv>EIBWq$Jfx))z$LLw>1=K46;n%mR62-$nKVJrLBrg0^6 zI~251~q@`sMP=S_T zW&gRlW#9lzg}0|NWTDNi;-{u)7ic6-6crnwvhHjIDLFKPoxz~|)u!y`KsERnW`UBJ zoV*fNiV50!ju_{pU|wuuf=f5xx2RrzH635GJQ2l6P9}9Ly{^*Y&m@(|FTfrtMYZ@? z^=cx_;@H>98~*?Br?hZ zG7z~qhbCiTo9ukjNcu*FD8#SsWaID^=U{sKP15`7V~9Yk0Kyx!3sqA83PMb@aqbgqk07eG)%NexyiNR@l3e(bk@IyC?X8y zHs5;DxL~U}(C1U^y<_-J;_38$>OXu}Mvu0?J;vhIu+rLo z+J9;Le*CrXe!WQfR3cv#o|n^Fk7E1S1jOTa;3h3CVQ9_ zcvK(nSX0Rrzla>RY-qEq6;y_`s>l59y1YIPMsWwtq^J0h2ILRV^AQXx-`>tbhA|;- zedAqxtf!dXDEHfd&{m9EvHUoaO4)d49YFne!7JUs{gg|*!a3=cLl}&DMm7WDCbqiL zdiB+npN$qrXQgyP23=^8xF&{!`?T?1aDF0W68LzRtAIoMbTI;X4IMVYVnU5JVT4BH z4SKQq)fQq*)2}yDe@sU;N18pAlxu9qbk2H*$hQ%cy(>R+adKwa_j4-E* z`3VlK`fluoG8e2~tTqcwwr-+CLN*F0BNJq{^>j#t*?Z#BI0+;ugw`u4jCxWUGtgzH zEu}MzBuDckaaLPF?12T?F`e+I0t!wEs$4aden=H=B=~frsTVg{0oP zAS0J_xHMv1M_}SVdQa_;`d|%Bp8CqHmf%K^$`;;CGS0Ows~D1^tKDt4(zeAj`fAa! zZ4ts$hNaY-qg5<@bR^<#?p@rfCllmHJpvkqN|$KF_-&CUd~2mJrwJw6Hx(dCLUnk0 z%|QB#YWLQ%`u36VGK(mO+|@R`J0I@GuoU8mi<0;_)7e;;y0G-6V+=xkAU49zrHPdz z8Qv^ufkY{zGij9o3MMcljsklSQ?JhJ(<>F|AT(S(VD?tF%DEMs17U^JnD#A(kpS(DC9T0J7wfDP0R`?JiBu@E zv`3C`JAr5vNzXwtKmy7Yx&<*Lsg+%kC+7Hv3TB)2^RBdZ^?z=F z_6%76MhNq3nOztER->+W;oZJG)VN5;h%;_@T*8KtVd1o(&Lhp3|4kJ~c#l33GIg4W zO0PKvv_?3PD~@CgH~`P_{G5VzuW#Z--S|LOMgSqrmV>OeJyxUQ2!-sDn+Wq(gpaxP z2B_0#P_`KHTR^fwPGQh*Agd#@KvbRStwQ81 z%)|L-3-)jzd+KGa#&dJ9k0dF?Pb!Qj7{o?-m>Z$4K5v$h%#N185(^|iZRLxEDc_s~ z%qV%I6Ez4i|2&W=z?9uQGz(&EkcI2e)q1u2O8-y^p%-_yL9x%NU}Hg92+DSDJNYZHG%q#Y)qm>5+Cw*j#gYl02@c|AT zIRF__jE_Hn-%4PCZ-p|9jhU@wQ;`s|$Ce%cw-tyg>FVzi6wqQ5avYlS5<}H%GmZc= zs9g+@Fr)4l3Ze72xvx@vQ@Q!-)hQYR~{M4 zd1~8C6;U)AsMLR1R<_Viu_UKU8@;^6=hFLTX|`Ne{n5j&xn?? z2+<^Lpu;gJyvvk=snISPAJPC7lU;N?f8L_e+X_=Eq7HrXMRQDwUVvPQg7PY#-7Kj7 zSst4`iHMW@r=GH}`1MHtR8d;v$j~{JLiTT4Y(k67S7lJOt6-ttRA>*&Sy5g4{Oivb`P?g8*+Q)hwU4;-ckOVtVUXBH?!`=+I24jb3#@ zzh;V<#Vr#OxQIs18X8p;7QJSrUys3aqGH8gHsJ+S_g1xCC}`$B2iX_FXIob$u2TvS zncCJk8RW=*&5cL;m}SV|?=en+jm2{@nur2Oke&@h&FffaY)(#wADJqa+$sGRki$MPD`;DcvfIQYSm{REoPXP{f$8q>qX}P$C z0)=2Xcm40GggaG`rh?6?eDX%qKs&4m87K|gojHnl+^NiI2>irk9Bzb#|%V0rXKOu{8J-5?idu z)QQ|B%JBY{6VIJA3C0*Zv$T?|bbv$U51BVsr$RWEJN)GN(%B%?;pQnEaiwE~O=7@@ zXb*HFAL zsGR3|Le<~ceK8;{T0mX#Ed%%`Ft-BhhHA3 z(d`)hX-_*;wP_1gYEX(9F!F2Enx3o`TVDU@s98!#it}7ckmyn3ofIQ$ zL#H#Y9}yHLVs9~L9ZcP5k82qLb#71uw8tkNz?6f3to?{ogwrAXmx4(N!}QkqU4`LS zwohmjkI(hl)WY{Cx@&-mA+$L+{%c{~ZT1kYB%6fk&Mf`JMDH+C#@XMShQf{xCGZDz z^%?fg8M}=P;Sp2i3P=&sj*an1f*p=WTYw4%=}-YOig>x6s|+K8Y1GWB|FKay5hMid zm7WPHK@*g&gq!}oTnxSIVOSdS!~$`x3S%{pU|LdZcSr?Hl>`V-wK7~Lp#2fzcE~Nk zaZy$;Bh7C@7PcCF1N-bFw(PklG72u~OAhKI zV^rY+4}#JgZgL2>g86LjISQqDSKZc@^yW-(PRV%pvU_sk_NRVesCCjny@4q6VQfE! z-hE;al7sNHXuWjuQ$sjEbvKQ0IvyV>(EY4LMi7_6aPUzX2(>6;N7J<+z)t_$C!HUp z@uYLW!L4oUn)I#edcCLpj=H&@zr*O6{KrPU>hubp;O8Cf^lF+<&q|dLh!wp;6LXLi zGkE*JhLm-4i0v=LJqUO@(Hj=1Lc6I8bDhI}f=%svQCsp!ck4oH4tNi7;>^>a4$z?U zjuO%l&KIuqcNI6(4r1eb;02R~DVmsw{KG8;kKH?Vl=(LuXIX!Vu}gRlTA4N<@b@?} zyjp%wkl%1_jo&ENeLK}Py{vZudupu62~1_EdoEj+zeRD7%S#4OcmeTtcMUfH3%${c zuJUtyf!eBDJYqVqVG-zTn3+ii4HM%J{dR2ZC1kD@{-LxCioIe_4 zlb$J3AUs75|46CB%Ce~t9)9lp4)TBZ8B3)Ac(yoHozT>Ej#B|V(%Op?sOcW0KDfE= ze=OMigTk`6Yq38TKaPLI)cY|yz{lI)zRBZ|q8hh|{BZQ9@?yNKU8ss%mW7|FCnJmX);#+@oBS+G014=e)w0a9QDHeQM@kDDUUZQ83*9~ zPoZr0UO9J;urbICzfI%~8PDROjmjtQhdu>A@b4ZghTp^7A#=cY73EP1sbfD7x#2t< zMj)n-KB06zCVYAa;7QddiDD-QPXLquW2we|+~2wbwDXIGP|JNF^1vaU2=fGw(ak^L z-$TF^9>st2d7iWovDtvk?T!PT3vScl#mA~iV;>Um2N-?hVK`r^H}WtW6^T~1y^h!{ z`nfA*KUpFQAp1ZlM{wg37(ZUQ!9Sombr~mqo+{#<^ zWqn=ep+Ii1X!w06qNHK{jz6v5(pu~D9Rf5&a_UTsZ*<)2WXE$X2y3->4kIbb>!1v* z(u5uu0r1=Dw2W8Ux_?41J->xQ9uljWpT~^r++WfvPMIQBKAV~wykZD4OapjX|Ju1; zBPW98GKWP1yei>Okv{OUH)XnM3|GB(c zl9)rEpIw4lx1WTJt{7~EAa3lnxx4EcBB4MLw=PKjJfNhgVchHveiXz;u%5I7iejDLe`K?=6}f{|^8*m;j&y zz#1-OjXGF6B7n*e7~U!CyvWk|?pj{I;KZ0}UO1~7 z8M$1U_Iz+mQwL9ET#-Q2_{zp{L8yxI-4)N?kf6$3zmU=R`i$lpnO%+9zdGU`TPbLK zPNnjd>er+XeGaAankvlX$!aXmdOC0{{x5gaseiQA&5I!| zpiiCbH2n>{6RCX1qMkM3gsXqONT--c9&=*NIvIe1!EKRgdWp>WT-?4e*4?k$ z5eW2Boc0QMwN7%Ecym+nq!*orT>wuOBX~7V*s9s_QnTkG_Zw(r7mk8Z$#}ZO|M6N` zS?!R$*(qo6L&yzNh$Q)Gy~}8^mnJE}YG&jy$`|~f)FR}PQe@%+BlXtnAQb^u3YPSd zlwdSus|ImTH{0n3w}@E4(G$1WQuar>Vud5K*aGGtqG@o%p&h0A7)`I%KGbjwY5w|G zVJyVW;i{_=bpER9&3TJ8wG}HiITS<9 zOfe=IoKzSr_MM9A4}5d|J-!paz)Z-55ZuPxBb=BNP&mpv1TqmJZXY5@yfU}nFMg5| zgew0sLY@E=JF!yOy1Q>66?l3PV#^En7d;-6 z_JohYdd@J3V-tv+5jZ8tC~_(A3jI7AO2azJ0Iq^Ver22m=?Jc}35JRc8crtu1wmXV z6Od$7mTNw2z+VzZbLj|1pv!IFbs$lMJWbzvb@J7oto7t%yS4d74GaIMtz8J9X<{}( zU?NjEoWD6mGd~W@cE|c98y)(rLDLmD|M=M6Pj)7Lf6n@Pzdh0Uem!pPe%05$FY3Pd zUexawATvDrurL;z^Dy1K^#Au0nJ<~6%W%(L3@3OrrWO2ug6R!SYf72nkzFD2(5N8IYUpVe0Ja! zgUoj6DcR9RL;=$&b{u$$*tWHFoBxqpJC)~Y+~lr`u4~>^2ikA87W3mAU+M!3Mc}St z<*)vx)@m->vnV@14C}fU_Sp}J?p0*UwIH$Ps&*ImFLeIB*v&MA7k2I0&5)|8&^Cez zQz>{);~$FBA*%yOznn;nDofe?ke+q9Nbeg=Fc8wCb=b`w!IiB?NCLI6Vk3&X-4FxJ z-~q*1M&kb64s+=i5E`87Z~d#T_5t~0zwRi=lv34uH$c{HcRzqGn<)w9JvDVEahVx+ z)*7YU;k&*1fQR}Yg8qk*`9%dyc47twE1)Nm zxy652$@q`gs_@SM=?LziFzs^K0>TOH2!^;&;o`r6cpB6WXc{l&oA%>6$c+(S#y6EJ zU^)dl5MBOLK%neRlUqt^YbmNWShlS|{6x~`pw>V8ueqVdw}Y*myjBiS>|#Qd?^qBjo4e=61t6UunySIJN3&Uy#)5m1DjkDHY2HygZT0=2y5s`yR(D z$NlyimJi;q8uH^A4Ai{< zgykvXoJlLe+;U=_WeGWaik{l?-6zl}~F&r?A+2Y>9<#8Bc+TR;Gj$5GjeR}5DSb-obrmFReZM(3Zifm56zA|NukXTzn$-4_=#FO zY|U*!R1o8ByGcNYgw;2=+`-0~T<)>$_!f3vkrd8iG&AfM&kx=6Wpn(SIo)$s#+m4I zS`$t4cx=gL`Q3MZ)Q?@++}#$=_uS2irK(l3Ii}5j9vYU%AGp^VeiDFZs*uet>Y4ud z%gwq?$mT%d*3{(gnwQDT`f!tC#V`4$O~Hs+IU)NqvFthP5vLd)8iFg5i;*+^PEU&$p=;bFslR6!W zUx;+yvP3y7l*RwWta}o)1>Y^nY@$D%v#dW-xiOc$=5ZE08H9++jabhVM=hL0WHH_= z;|U0dkQ=E7-~G|d4Swu`&%RX7?l=|oPOMfcPw6wYH1f^Au&y0fk1zZ;nqW?DR1tnA z(tXY%LuGaNu|2x8I;g*8k)l$Ijr$x*<^Dd@k+u2Pd6$L$lR& zS@+nqU-T%^XsS*}Vq`ez!PrK2$ZLe9E9Top^|pB#U8f5fO0!b*ZWjVY{Jp!RE9Sjo z#{;}pThcXm5Zd9744~2TBZH*&94};paSNTz>^0AfptWN8JMhO3y(+}ewYzajPJisk zKkMHAwFsCke8ix9f71G3z9m~2o6i=~`6^Re(B4o) z5Lc(>sat=ojkR|9@)wCtI%wxyRoS!K#NIV3fE5-qjQP6;_(hj|>vD34!x$XDB?@DAvav{vQ?MoeQ zp>b$~j*TGc5}xqx_d{~v{zYVe0R-m1&T=4*);<@%yutik)EI5kuAkGULrU z(>G*_|0A`B)5SaD+1vLs3Crpbp4jYDQIw(6e<)}kkvLs5-NUe@-ih`E&1?^K2NglY zwBG$_-$|wV5NG(kAhX|v$oeo49W(?_a^}K^6SoYw?|qM0%MbZs8!6kYr=;P%T2>QuE z3VvOfdIZV$t{I`89OGxg6;1w{VM!#}v%e9RK-a~(4+Y&xa$-A-AVcjx^BY^ifg;8Y zzNVOcU!cq2M}(;UC${N0+Y5(tL=au4vibg=b?3f#NR8!N?e*pAcrH`xd0qLuyS{$7 z3M96A^!~cPc;BoQtHtGA9F?>EhKS|k<96}(!nglET5bI+^cfVr;V6{1)WS1V6RQYM zgt7WC@8dNZXhdOgk?1TVcfZ}xCDy_t=^9fN7hv_wZPc>CNzmHR^P4qD5U9i`zoq?{ z6-W@@i0$yQeWMSD=s*JOL(bPibzu)0jtdnRul}~I#n5WNDL}Cl6Q+n5C+QGEQo1?Y zXn@VN)h$w+6vjpZrhYL<1TLYwIMbEwro+g&HRlCA@NkBJ2V#ytr_}T1uVd6N%IhQ< zfapgyBqWDKw$bwYy_DJ2=ImKM`IeO3y(*6=gHj3lXZd|1@_A?Llfod5D?A7?ey7?7 zYe}5QJj;BC0O(PhZ~iT!&6)t-b$ls<+wBIAxJ#~@Y9UnD%2)PGKiJGZA}b&~U)cu8 z&SuTfo-IZ4CHq#m(V8v9m%|jD(U$PY;Efpjl2frF1h(evX_-2?8;3Pl(Jp`g8efRD z15$eGIQLWuyT`wFF_3sWpOE0PF)q?EGj*U>*g((Kt9l}f*@=eQiH2Q{Mg#~dcZ0R4 zP^JE%w{Y5T?;pW=mbVOVIeKHfK%V}G^iUhqyMqMW=4`$<9bedWGT2@0?4@X-fB0uv zs$HZTyfimo$rVDO^Rp5W4?q!{=YAPpQi?3$okxrcwGVqxamOwh06GCvw0-0gbY|XL2v^N%9=yM7V^*HfJ zz_~2eb#!y%6(h2(ta1>U45Wjlm|7qv5*b8qqxRSX=xDK#;B#<=&&ip<;wfG21%l{t zp@}mwKfqKJRV(^^|MbgrKfZ(p?~t>eewpIwix z7YSrV8&NKv5&u>{j_gvt-rvge`x$#wfWLa>RcOtCR(MZ2OcZtKCU<{J$PyK>74ERW z4yV!ZZ@9)JBE#N3J0Dzx>P$yefQ{F3b}R+6?->9M!I>NKVuz7D_%XmOh7$%Yb(j`b=5w~DJPVw&)O;GQITh1 zNBAhG18N?UG(KXF+>2~xjT^6N3FF(OZ%IO>dr10t`?3R?W@t0Zo)2*pIr$4}Hu6J> zAsQbTlRz=FSscV~M{=g0KWDxqk`&+IL=q;&yBv{ZCtfg%R72@go+*6$2Mdh@);6I> zTGB)-$_YzxcH8;qnW-)rjT6Z2DkLFGMpzpXEg)M(N4K$uwvHUDMM>v9n2VI0^UAhL zO~}eVdOHjVWYL=(5v$-creVsO2WQ8-MIs>+#G0|QjJm8P{@NGT&O*L}@u95;A+V=f6vRKUwih5-ul_Ops|G^DHfgy@Z)*b% z2rX4O2L;Y3_XZ8UaYQLHLe1*chwgf&1BECb0t2x1A}Ugi@Ng>2NmlmZ1d%F0An(?g z42i0VAx|*X%D|Mh9+ApQ(!lTm62i^?b;zyJ$+sL5G?tKjM^<*(0L8X{#5InfCYQlf0%M&?Fy#@TlD z{Q!%iXm0~!(+#y!Lwi+1n<~fmG1uvM?Ot@|VE*<1!I0O#ngZk!ei#nJ!AKDOH7Y99 z1ROOg=fer%j$z8ruYip=&z&*ohRL73dLBoR*ffw^4_+xCHW70Pea`$Eh;8Xe?3c2C zMh;2N{WZhGB@{##z_|9G^KV>m-fB3UGCEK|XY0BGLPJCl5I-%9wYDIC;oT}qfD7XU zw9?tI4^Yj<+KC-+lg`t>%**ZY0++w-^2 zyYJ-^>Ph$O>Sph*u5bJI-+UiJ)YhlyjO@6t$K>&u;H}01`n5US?hmL)^y1g6^9xQU z$wy3ciNRNNuGiPMNjc$i-{D?XUL)f_3To|lgjVWFL992?WJf^gG0~>#xx0T+8ELY( z)k{s53?FccY4yeum8zGXHhZ^sKaLJQL+QTNMPfUX0>P*`jmCVyzMua#>K|3>iGw$BPHCFBt#led$XHwU7)NoMIY%c&CxI zAgkp?0*TT^LKLJ#WwqSG0_S3|cv_f|j%F&gsnf7kzkfn`w|d^K@NLotXXE=Hn?9rx zVl~ZNs|uG%*)$|e>+DxG(IOWSWIug>X`F?mHmMX3$)%U^65-UtCETZ)mYE{)PDh3` zda}@sH>1Q(R~vYw2ELV*bTsqFV-X0X2G^fY@XR$VjA=B?zKiCJs~!i@b#TGyNVf;; zRzr6+VAeob7YFk$3!O(dmhlUkXADt0fgzq*!CE^3F^VSv7O8yb$vHJg;kjnXE@N)! zr-p?nIA6jTn!jf=H+m*^zupSGV#NSH}g zRd5hCm(6WvEY;Q1mqq2oA(~VeCce4$@Fm%ez)_Y|v~h`e63Qxiq&^zdVfSi07`z7G z+E?IyboOiIF=*3_G7T#802tZ?f9T-BEx-f08x19SJ9s9%3Qc1YWcF~}aDEbEPDdzM zr_Uv)#}|a2!N>=tqZNccKSR)vee)=MN{i)W&S&^pV&++0-0 zp=W>wu3A|qDBbVy=3Th;uE#x>)|uW6p=iYVLfDZE(rk4jqGc>V3jg9_OF3QQBr@0e z8N5#^;MH7Eke@`|O2zd_YwY-d8FRsky!zT6(|je_!%^1x{&KVXb$|BB_i^{4`Vt%a-MKf->-+k6=WDa;^Y`!G zb8Bxcu5GjrH0U}B(?fYLqg&ftYcB8C{hmqVLoc4qt(E7u%eNiV{rh_;-_FGE-RY;3 z+!{Xbj<05f%5GhpLrsb@x$Vw|AaINCyHFHFRH!kki2^9n$57w$Zl$HA(};pNbH%Gf z1FLhH+!W%X>BaAlIT|_CVkPRRd&}0}{lwd-jW->){9A{+Uw=q=uI>}up}_c~EUUCOqxelLern>zE{ zj$GEhvtAZ03sQj9)Z6Pj%O4I1>;DQYoe5d-@MBryr1rGe-6#$vbRwi4C^)e@PJep+@h;v+RKn3CYS1Z-9`TUyy|BXm^Y%CbSVLF#BynM>`=0wt zRAv`x=IQL$#|mIgX$6Yr?77FE=ylx}>oti=P!&exR&0EKRPeZ;G+bC3a=^^6ap+Kp z!p?rtQywuI$v^0xec`T~yUX4;@{9%UCQLc>J-f5~*k(_>-pi;8Jk0Oqi~S1&nEFrq zjkSKc<{Hnmo+)i(uTSS1O@u)5IB}=A@ZwDn>fO>)@|oRIRsiWDccH zSuiY%4|6cAfDS{&6%q<7GG)Z}1W5xiCB!{OM$cf$Y`YrPc^xXSI&S3?H|XC_ypz;G zMTCbeAw)^Gwi!9?q<&vu09Jwf$$o~UXaq<(i`G;=E;aiV};WbvQ??H0<2?uq_@ zHTy4quayE*SZe!!rF43}94hIWVG4E@5S96b2HVfX%=+>tWcXaiii9oCN&M?X)^bv0 z&V0WPeDS{B{%#)he!br`cEskMsA5w-Aq^F9Si^_m(3lJ2D?qP65@0V=lmIw0iDshv z3reimRVv=>?seVN5eU;OOtbI>!5>u{wg`7jFlxoJJ7znd1cZIYT^|^nxt1tRkg!H7iyu{XbtM9CM#51J2xYmZsxQ+I zZxPe%>Wk`zpE~=Z$)BNlD}1U~{Nz-Q9~U8c6~s}y2=H69S2qW1qdAcdai=@xW_x`n z3tK5$i%eyVdMGV0>Cdq=D|F--M{W?5?)6UpNINK#H6oC`>O*y0T(VPw=@z|} zozy1OrEoza0Xb^BH_E~xV1)Qr^OZQi;u4LCL0)?LW_z(C@;g!-jHvLvh^QPR8a{6u z2Z$hJp-c6Us{Zv3nTu;HnkxuhLxBWP5>G@<1}%9hV~#L>1;|M!Bzx-%k=vitcMR-# zW-?fMl9*SPUtJNzCP>UetlCX0-|v%&D3t>%5I93UUXn6;i-&2$6S%~3wjz3>@eK9? zjOCk+c0QAg4ekO5BKyxG_j~Gu<0FY=ZS8YaL_i8=3&}m zrSRlaNnQyIY34_=?7PvkChIpTe$uQF+Cm@1PV%{#yS^lM&&R#92_@U1Cs;x>#;l75 z$}!eRS=7wHzxB(XiKW6)c^hh>fYKH2h5&^z={odC3T*j+s4!`~Qig|R2zA4PdLbLC z0bJ!Y60LZWY-C%~sA%F4_t>ySuKO<2vWv!$i0R#Pi^$=V>a22$$srA?J^-qakx%IQx8Z`b9pADg4m1l zekL>(CwSs{ws6@xjZDhXt!6?m_cw~WVnR0$C`G(tT2mpXUNE;JyVhz!0oNdcT>w}) z*AlImb=f@&OX?>adR~tz>SGFeUW+2unQGak0~62akTWF)Qi+(~kvzou<+F?AYOonG zANd>}Ei53R{gNI%gs=Pd+p`{ErcTtl(SVw~LCpFpk;Mfohvzny%~LJ!?1kg*NWc-h z_{_Ni9w`t0#SkTke}D&;@e*N+CEC;6DrAXyzMto)k8ny0Ng!UIqPng*YgAUlPFc6I zfZee~IdB>(jfMf!3Q(OudS1_R6}JDFdWNMM2yI1Xj}QtTbr!G<-TybE89{$@WYl@Eqm@84x z62bz@^@O@1ilm@o+B5rDyoZBVa!4v~TjDWgx3{pU4!;9l>+h^sL{;qpd*<&NmOMlw zPIIX-wBGka4$Apfc1;U_tZoU0-ke@uDiN=cC6xwmIK2B{kgLS#_nsSd%m@)0OLyJ|;2(pJuVTm zx@IY8AcA*`rDP*hzr%Yqw7?;WJC8U~@W?Esi~J#bFv(n8Ts&QW#8q{2o?Am+UahDE zEhRVS_MvidN0E$ABW{oq^_G)Q7;(qTu4(cdyDtIIO<_X6Fm49H5I8zh7QNYA*#}$V zUK(KY$=qtDuC?(4nafqUNB#D2bn}7oN07wtW*Eoza7=STYFQTlSHRRO%`XKgo4#khIMshESxpjajn8Mk`>R)jU-E@-1)u~jVwviz z02Tq}>3~po3G~wABnW=78UQJis`J+>OnRI`a^cdv)-1zqp+Fd?ULKeNBd}eCN{R|f zge&Q8I6@58VSZB{K&wwqMm;Djxq{AH{W5+Jm4~>%6Yw8ooPC2>4H`yyVy6z|X{3-n zleapOd8Hn!61SabWGpf_`rQLDL}{KkIE&-8fnS7FF}d~H&R@Y!Dhf&r{dtseEu(Z% z=IO{W)`zI4kk2da5D=wjYh!k{KkJFcMt9Bbw;F=aZQxqeK*CXKO)xbknS3FLOy$Memmw5Q>WnnKFt2<){GX*ptu=N%SDNLFE z_|*?k=lzW?l&m4Av>}z&{U{xuf>pIb630C_e6dx4SP1 zqL2y?GB{x)nT(%?4cBlvqH>Y)ULh+069`j22Xo7O-k&&{6G)?Psn$E8#NT0Ui%3O! zSftK85in)M|=BZ79fI(TRr_NkSf9f;=)q}_OYhT=Hx4|6U?q`k$ ziJ$Tq+NRQhX>=3PFzm z>G9NZ@+%+(DMJpTLT#L-5O?3K_~Dy$R{p(-AV5#9o&vZ5h(=X>awZImjND#Sn*&Sj zoNNrN20&jjgFR1azkPxNEDh;SR#Hw7DvU5m0wN({pTvG_N+*JgH1uYHaf-uv0bsHs zK^;A>;w+JbzHu=!PEwmxE{uHmZSv-Q-$C3&X@l35j8u3mZtP@4GTtN~$o`)CFkmX_ zjWR3u0!n|xz;pk^YlVM)1I?D2pQX}jRSn6`-u$O;de zu1{L{oIgYeQ*!~<>1}eVEv*Vgmp680AT$dp`gw>lPePoNuLYh`oyOI`)1xXNGHtC0 zOoV~V5-o@-SS|z}!>Y%dDwq*AbE=P$Cs!CoR8%1msVI!tHrPU;fQeEqtP3@* z2JZVIw$wM*V{7nd$oCmLN~U{%mOGmX`}KN1D>yKKnf zFg@J*T361rX0a`kDi|Dm(`haWEc&qKx+o2UGPctV%_JydcI`=M65RB5-k@U?Gd$n@ zD7*D@bltG0Lk=+;><%-6LO@BrEEvHYCeL>>n*%A}vU@0tr^-Td>Ax&+*}p6_u1PrU zO3YfDrz;xLJJK7i!VADyNqZQ$P ztAUbN)jutR1~`ICFiuE$VyqR>6(2Qe4+IIwWN=Rc)PLDX38)lNw~7P-m~T)bqgzI3 zvSPP7cYi`&5osr_1X3}>$N`**{6-0)$R^XhMK8#~^uz)!CU4|)F`f#AE^94Nq5Xb- z5FI&!iY=sD{pn_WaOoV4gGC+$Mqvg%9F3E|w07Fo!-yJ^*ydbd4XXwMR>FEPekTGGR#==3XddtnJ7D38|$U~{>+YcL`}X+bcMH+Zo(hJ3><7qas>q2 zKj;A@9WI&$K-95yh7)M8Tnm;bXpR!YHSKjmZIMd7w1TzbjjHMlOv1{PhD{ccGFEJ5#`=lZZKlmQ6~D3Ki>CaUe$91dz1vv_R6* z+SM(no->tDkxzvM=}c&QpoQ6D?s2mNX|HtW!^8J4*1H{Bdp2 z9&f=tA1Bua&fX27Qy0nGwfz*QdL!i{oaGAulWeky6{)V(wy|y0lj~Yko5eU$E;A_s zgL4+h9LxGv4np}&jNMnG%TQWy?I5hqVm6P&4Gp4GKdJKzI0?w}iROvN^b{=;3G$}d zA7#q09PH$#bMg{k$9s0|dFgaN+O@Y@@^_d5Jx}D~r+<#1AW>e7R;Jmh-l!B>G3JoD71XKF4J`jg0i|RpE2YFNBSqLn zD^);k>%G5#JD*r#Moa*)bZIaVJjph%H?S@vH1y;hg+^Sqp9FYPn(f(y6v$#;@4~|1 z7=qCjikWMjd-aa5+$0n`nw?`g)XJ%C3CU!jcTRHW(lAzOZabhS$U0g{V$+eYL&M|N zD7*bS3Iw^snOM$iawS(i|I_3nUW_PFZ-Va_S%M0-4Kc+9YYbA)>CKr2cEnZ)`Z7?IJ^1(;zj>YiH~YBC8z`xVLh_#2)qFYcIUG6%A}wss55 zKVCk7bl-2o!u_??o*y-lJ&F{8>7C~wbxA>2NS)V%J~tfZfP6K zBSXGi$!oPNbc^Ji09MvR4RF-IE~@dp$LEULdew&ykU0DWU_nxzvIgu(%6A7e&W=z* zKCvu(7;s#$);8xQmT3J45LN(CwAA=W0*HC_l7$5-0*kW)`;q|j9hS89?^!(WLi~fN z6k4znOVkS>|3+bvXCmEi{M~k>5A?s7Sxd@Wi-Mb`#-LAZ0%nog&c>1tk++D+_Dv^P z1U`x>MC<=U)mN;;c9ZOV=j&eBXC2G(`*=PY8SA(DyIJFrHA}VvEZfo6Hvm&HcTc+c zZ}c1aX?e)a3VG*7t+i`A4@==)@%pwagWJ>ciiIXLfOxejUDD)WW^0h3LS*CMCQk}% z=iR*!jd9_%bRnhbfF zc-$|?rst+74LP)f(gd}@ng(7&UiH9u>b_|_9T%&0dNY>OU(}FJ)4bCg-Ptf0*b*7H z_1;{oOEu;gtbC#|T{TMU*|c`o-9*4*e2zBPn&c+Bmpx8*{{2vdGTjI#JpvARl5UDe zt3Av8erjnC;=07Iz*e$)mpg{V$a^8Y`pRbFdvEbhmG0ZkqGdCs!qnRn{oeNKj6KWN zyEAiiTzYhV)Cj033V%#D`9AwjnE@=4w#@Kgm>3PAJ^V4jO5z^!>Rt58X5@p=>g20X zxvrZl1|tV3IpgH(ZNrp?mWcG_;DxzFrZ`HIhLo*e5A@)Swhs14W5IRoH0W#_kD-&YVKat|M+lAR z;5vAz*VfF;cZ(m9U`IFU?^D@7$|rqr63aSqA;KM~`45ds)yFipQDjf5N{4 zuHL=vIb%cD#?~h9m0Qme+XH^n--++uKz~7C9GbJ%qbtRqHYwPVsP6SpVuij-BStOU zqlZ$ghysgg^-W{n$Xz*csIDz9f(-=*R-hQ#d8hS!Vdu#)pqBE9#WHK_8|rRKut(g& zH7YdRfb!HUIBYisFV}Z{*Yxx_-woCDIR8c!4a_k#t4RTx93lF{2@WcIJLZr99Nkjh4K`uO|m=#9xQVHC{5*D8nXj>q?PXAe`fnyEMkJW&ex8*%sl|a;U za=urg9D+FsPW33zCn*$h)N|DuJl@0MlNL;T9kC+it#{1OcfMT%riZDi^-ka&DLzIy zkqn@$95X$mbpT{N+`mP2sW(#+DjAxixUo~PP#>{C(Puz0Sb1kC370en6WD-1HCWg# zzw}vlEz$bu6mB;LYvrdQ$QLmyr9OV*pMe4kZbip{3aEsTVnU4zuXwbr0!2+l6@wM| zIrQaYMa|LEy@wnBcT#SH8&;+pHDhPZEYE?*Y-E=7@?AW3K#|HRw1v6Vr?$1SOQOQI{(*X8f38+ z;2x>&77ZH1kkWrutJ6}cl792C-hxdK4?AWl~?+f!s!tE=KTk2-baaE zn0qPZ+gum1tetk;HG@&d;fK}?&K?CV3ikUKA79BcMQb=WBv5(;rrv1Ta=e`L^Z;|_iqAuEo>2dYfj z#@tF8GB9i(ml0E`yyb720Is9mQOktfCat?^?4P$e7U@xNM%oghk(Im+Ub%bAFxJgSkXp98H zO}NlKr3AzS%;YDp0*0->0vPua(oxn*@kip2xYbH^Uzvn0rGn&DOtx9=Sk?p?b=j@D zLZk6j5?No+V6me0DxdTQF9@{(GP}*p2b<^j8w;DK2CCt1F~R<%=aFpfF^QgiL|7gZ zZvw+8B#ois2P>}rL4waXU`k#*%qO4Ku(`gb1DFaI+C<4K>JV&4O|lPmpdmL0OrlaTG`k?9rf{RT zE|owe6l&buzqVJPy4+ARUFBz&I|^=583@=1lMBt#L2hpXWUmC{s211{Kr2c~^Uri{ zgHl4EoX1F7~RKlADwm<`g94Kr3yI-W&3M3WC1-oynbo!P`&O$Be_i z0+!C>JLS~Rsz1yOXMG<0ih)!z$gnE8UpK*cER`|LTIcKzbIsgC)i>ZQadpg&leY`@ zP>W;c%MHB0E8#b0;1|y<>DM+Qc#?K8Z>N1aIdlABklEpqUkk77^E^x&>GbD*m{)tR zfhN?wL@_z0o=RDwD*vUKQdx-$gv5#X90WsJvYH8mxv@ccg;U$58aO@qs2>&!Wvypj z2hF2JDqFJu_>V_h0*RHeCeH)8oSY=v-><<@y4Kv0!E16s46?t8y}h5UY`$J!AA8fa z-}iU1a@Do2@2-OC(V;KXy*ppCp=`RmAJ3L}6h<~y*mT;HU;0N zguI3JseD!Y#H3OOOeJE42ZievB%8ul$Vrzg@9uQM5{BF4DdtH{D?$?IMFDSz8IuYH ziSmRVzkR_-)DcL0sKH2tA0N?^JicRg9tiTt@{KTBZLMdx0J#DZ<*)5C4ryg$-TPfX zMtTrZpLU?$D-&0?rl&iH8z$ZNp?clFUD_|9YQhk6{1o#*_8pS`5-08Sv}z6wlh@aT zBA!)(zIkFu9;P;-CSBwQxkogMcO-8fk!Pb9=GZ${M!Mn-U5xBc^8jW=j3H?;5W*F0 ztraApW~XpeW@+V2}w0BaEo0^ydyADd|!?BG_e_^U-d_^;__^^qw$;^$$MuA@jm_@ zU8q2y;-Vx_#u3iNkVg$?wsHh8D4I6%*_&6osKn62P|NA|k}9aYgOh`%nlbdn4TO-? zBHtolPfk0AWAf8{Q(R|y$V|lyQHAl&Iof}|~Y#kpiEFzBac{?=qwTV=Gao>j>Oq1+5)A{7Nz>sJL|qLT7#jn%f~&#`!JzPFIPhp2zO z7eF|;0K66kGr-dj91ZXry3t<-;xLcq<}w97m%~8A0JB-;)8^j_QQ2~@SzN#h`eKj$ z;M|n)TTukFeK@Uv{NW(GmTI5f0;c~$lQr)J{6zX$RXJ&!MFX;*LA8rg9SOeDR1+)# z$Gmr&v-9fQ{a0){?ZCVOLK&yj35=EEDbtJVpoBkko?=iluQn7)aauJ|xE}^XbB}?j z-mvmg77B!!+22#~lkHKs-tW;&x?b)kkH4RH7gM1rg4`XHub(jvcGxUh0zMx<4F~W0 z4i6T|KkVan_H#Ezw&Wk#V$*l~>+gka@6OJ*`+F~*P0zRq-GT|fxYn|BfqqwQErdM<6|JHtU#PLh!kx;@C zJqbY}pe9rezO@*^?k5yB{dHyVB{7??!=cXh8}O{8v1Klw!nh3%N^#aDoMstrMiv;0 z8JLY=LoPQ4#B2I+r##2bV$h*91nzGgnqqoJzc-n0R6&^`B|^c)0+jTw##fLq12u!$&1;12c(mp-XcF748 z;_A=CjzAgjhJR9%C@j@@8tyr_!{J$ zia~kugSz+xSTLf(vihG(Gx@xV1QJtRuyAD&I3wYmngkMxoBo@c6cU9|(z$;MDG2e9 zRTDE*8`7(|3|kqqhQ~E*bx$wO#zO<%6Y+B(L;%llPBox<4y%5oo^~x3cX;v%r(q67 zp6$Z;;$cI-D~z%7PJ>8z9=ZnFuO34aKF`~2pwy4sk@y$snc+!$XqOyM3g2kP_Z5O{ zqng-pmZW;{srDJH33i_5#ufNfBTQn3Fy~jnKMBBft zwze}WOMc$L1z?w6{TuL?Z%}9MIE99h=q&#LwlxxQ5KAN zBQ8zKlx9u2X4MzvfT5IZn^^zxNCq(>gJ=dexM)5X=bIsLl_ORN>c9##RyAGFX2W0! z))r*A6y!;uuF;{ArQL(05ecSw5z=~%E#Txg3+GF6h91Yyb((y>D5-U0$Sw~-5{53B zLYoBtHtG%EmOV4OeAy!`ytwDD=AbwNF{=D}mtuvvoJCycA4_*tGGN)J7eW@@P3RLz zyDYBvNIcv$kxckkFD3A}oa`OA0Ab|AwKgLhh(gO+HuWvS>4gadWD=A-6mJ_CDLXp`6Ef(Rjr-z!~a@MIAp<)U|IX>70 ziPAt=xCn$yH_e3^fb4vp7lGbH;hEM9#=aSILRcp)bInW;F6@>Fc|<<*NiHa%oGFOk zj4K8W(Q(p_EMFJYsi!9iyI$mvk?)uaJ3KC$nFrnlO(5a&(2_%^uwR4Rm0(o}A|cJ< zR04At4YG9o3GRQwGg}ZR>@6h5KZ&?5?w=U}(*>beVAJGha9RzcwlVwu6lMW++W88j zH101JdRrD3O^~MisD^A8Uhq=OGHJoql6gbC0HfBH%4^Cmx~T@l(0D^Jh9xF1#dCTA zqk#G0jJ(|jlxWU`wQ76v=^=cy<;e6X=7P6^7GbzD0$S7*#HG@QT{H`6!A5jE9|bW+ zXs0%6UVQ$!Me*Aq?@kYiO$E-OA0ik|jaXiEf`56aX-y44A_l=0czKcPYs16&Je^F z{Tl>9g`6U-ILw`8CUnclk_`j6)RgA~o^@qu?gI^Lqv`jcf7v|&Q-YkW{wS7l<-2vJ+c3YL*xu1(4=R=*24t|v?k$J|la4sa)M0uM1BwGoS`8{VEPcj?K7 z^dE^y_8*DqI)s+Iv_by@OF6*X7HB4)F94kP(bP_O@shnSiT%wS(+x%9kt#{xkopxmdi>!3@%t zR@n)HKRI(bG>|0Ja;N=)PElb0BOnorJj)?12ow{^jTwxIMmyPaw>?>kwJqeBQQ;cg zkgG8Glh5C~q@m38-fN0qu6$RVAsVnYb;A|dgYa3@OaJ&wE@Dz)?<|Zap#D>3V5=I0 z(VjYWi1VSTeG#H!I+F~1_hn&_qdjQWR#bi4i7Kou4)%r@&1-A8P=oR8*sgjmQ!C=} zWa4`FYvKy{OWaAsG?>4L^9Ytjhdc4}^hB@hBp zw|Tyhd+K3t9q~kvncA7 zzkt>Agg_JuwoxlNZEPBa;7ui=LH+4zBQB9meacItA(7brSDWAhoQZE9^~@PFut9tUh(Ij& z1)~?r!0LfYj#wn7gTOArN;k@t9&xM9_+;kkbEXPqzUXs`4c%uUO$LizG<{%BDp)r9 zGuKVeFbc|SE;43T0jo|0Un~e7LtJN!{L&bX%OHJg5-d?A-~y%XA=gUg$3C09vGNcmzwn4s@{e^`ITAWAb*@M9yk0D?T*(tM>(0Z4} znoPH^s@k}H!oZupnQ$Jj8dNz=O3*b`KVojo0*yVj5F{EX zdoPohBWqH_qe4={hlBo~_~codJ`ToL`y@p-`KMXb~waXJKq zY`GL_)4U)lm948yuTBUOAD@j)6Ej=Q1O}78>H!I_KuKlareCspucMs?p-jEMO>pWB zhLz5Fhg)3w_t0o?y(S}C*@(iJDj2EGm2M{zN25nP< zZnFe-bB|;@2i$opoe6Q!-b2jZXQ7E%>dQ=^oe9~TI?5e`FeecR6iP%0M{ot1kWN@; z5GR0w;}AxQkSY8w43M12KyP1F;%^~tE`CCRfE?aDKou9AkGOMf^E1L=U6+dG`J?^d zml|WHp@pE0p-@Xza8cut`g10%P{q*3nr~w+m}FxGOqPt_vBnTSaH+HuL;drDw&;4wS*U)950@CyX2+NiX%nodO>!PM351n(TRH9wjs41r!nI=&TM@*s(bZ zP@FaYbz=a3D!PM@4^t!=s_QH)WN336=Do>+LI8SUoJ=6bQ>^6VCZTgx_hvCkX+L=0 ze?rsqAp>&Ytl7d^U@zjNEL>j0*uh%x^LQBZO_M~N-W75O%%Yw9NSJ5X9b|BTovtSE zP1I|mTqW9`OworMiN5Whw-0o>Z?K|j$37{Rf&9dRM`xA5lAI3Cw++EjhwrcZyT=on zJW&}RYx8DwHV$vJfq!pHF4OBXS^I19@Gkd*$z1R3`)JuNdEY(doy^yHu5g<^+U=zl z8@&2xjt?i3!&BcsYzdN8+Je1!r&fxvzxg~@Td>#?jC_md-Wz_^865cBal_Wh;p+K+ z0&OOkdbFB$%r62@&8*gnOIVq-XGkWi8L!hG1s282do|a;&RmG+Z8~b2qLdfP+v>5M}s-{LOt) zp!7;o=JAPISi4}rn0VT!_Y8H3TD-^s4kB9a&`YlA#oHpw_ntSAd?dsloD}sTEtb92 zL^#R^K^zTiPH#6)kMqpPN=&!2f>q1Mj>fGeFNNyZ41ErQ3e$M};IrnV$j}$CU8OAn z9`#n)V+ISQ%ZlrG(ae#b6!|b$kyf3=`aKhGyW5GBoYZZ1vu;+`F^~DQ zvf-1ka5PP`bf1;r6jUEbXquJCnm;TLPt|`ACVnM4@#~dl^A0*v!V2(5#nsuV2gH1YgrQ-H^;I95?}8*-)YIc z3f$(GESvU!x-?P^6GJS;kpNCTr;<349fxRvEs?5owf%Y&}>qk}ijrF_)iHW`x2A&);nJIEX5FXhaZ^c$rF?_O@axzq9#gYo*@LX_( ze%aotKc4BS=slAf2uWZ6Z(W9dSxj>b4rdCHcrVic$q$`rZ>|)k1wlF4xzfwW?7tzJ zrV}DgtQU~EQ<&7Q#ne4Bb~9uDhPbS!D4dC!pvL*&P9ahoWKuKs(pjFXbIo_guE14a zL~kDo{adiXwyB`~QB~L;{Ws8f2EjaP{IW{)|MV-nh3a6&AW#;fUp8nxs&qof@wa0p zAY8e}T87!nzaC1eCMqI8OQ=W82ChA~e7QCHMr|4H?pvPv_V25E#o|mYas!YhS6?4n za4OysUv*(oZQuGhjuoPd1La4n+x&H2#0etnTuGgg$?}(Y_g?YjunXKtD_Ahc(Jg-P z{Tq*nIjbLd-OyZcntqtUhwFm(vFWJ@s9Qk%5Iv0O?8Y^#0Mo)RXVXAo@vXciryZxI|CW26 zo6mlGMyp-bZ`FeOxtmK|a?%?#- zD9_(D9EM+uyuICc$$;SW{sZ9h4b|UlMi({wibM2u{X$NOwt|qr?xt3GVfw}lEjIAb zoj}GQhP;zPs*_aeZLf{f7YGU^pG7>%*m4bcb|c{-o6uoXjDQjk*BDeWTmClVA`;J~4 zzL*GuiP`7}w~m8B0?J2cwPsSOKR2xp-3{yaCNcKq_3%+~ocq!d%owi{vdmbo5@$hP z)lB(BrV~Po`g@rBO1uYv%~vyBdoB=5mMH8JmtFWiox!TiQ6)RL9HRs z^~Z0a>M#NbMXA&Py0ms&JE5G}L9On+0|8 zh0jLrc5oBXs)&mA;m99_=-_Jsokvr^W15uU@qroEJ?2t6a;|6jPq+xjLOZHjiFU5F zW;beUK+ED%6U!-X1Di5L6Lc094Ar1-+v+I8sAYP#1w)ZGu)!r@x%+yJYa2Z5f#5O6 z{2h1;2(Ff@=f0Tt4+e00cm}Mpy>z?u-faT*TUdjSnsWTnEYM541o`rFk0Tk~Gj1R5k-rP>4Rd`y9S-|_wrB{6R9=^UX1C<- z11Wmm?s{4rJ|5<`?TLN2m2z)>1PY_+sNd5N%e2nlO)?9;?>lhG?S5`#*V`8Rz3)!R zy+8GD3OU@VxZhq~`*}W&GhctyfZ-QEz8-VInIZ2LX8z$@`)FK8M|U(q)H4dH?tI;+ zF=ydA_D5d9Ee}%wYC)I+n3Yxj;Gd9Y&h@Kz~ zrbqsz`fJ7<<*Nm4PmdLyIO+`vSjZ`DbnUN#Ea0pG>YTc5dl|WO-ulkkPqQ!KZB01o zc~NMM7+3*Vu!9AjsN&qRS6fV&6_AT);N@K!VWCG;4(`AXvDh=L-&l1@czr@U_9vb%=fj ziF8&8iqoFmjyr<=>7GE-Z=%_Mu!<_I{v+*n*;GLmFQ)>#<>W2tsKhyzlrjAyC9 z=O1Jkd&x*L$>>4iT07TXNe5F@pxVIl-3!fV%xZmHU?wUN87-${KQcvOdQ@a_)XgY( zLNsbK2X-TCRMHrg=Qvw=x9(mZ|5)5&jRbP9`Y7=qVi@PO#d5Tyiemou6ZA`wf)^*i zB!1mN6z`un=hq(tNg#E~rQ#iG_m427DdbCsM~^KibGm z)8!)kPn#3@Pn*kwA1jagiW)}O`}Z<EmR3fO=? z*EY55&KBt1QM?HL!wYf#;e{PtsA(!@2zqhyXYR}dUfPnJTU>r|tpc(i9?bD(`@QHJ zdR7bn)H!RIf9f3Hh6l^35sS}(G@=@!Cyale{3su8V7kUsUmb^{h3AY8IO{5n1xYtL zZ&~c`ai(xC0l!xgRP7U1PK2hUS@}qH9x50`EWGgYTD6Wu%7K0Y?TP?l3pIWu?D(NT zCav(3d6L?K*?8mU>|-lc`svy3GY?&`tDHusPRv(?KPjAESkyN%S!DmTIZoyOv^iGg z|Fk())&J4v`u}Njh9MQ&tqAJ3P-|KeCCced2e!W(>p+4@hWdD#Q;L5u7M3F$K#qR`9^bG!==L@BoHXg*$HY!F=4f zqezk6yIFewC^`a>-@nk0dr8t*mOP+C$K;KiER`q#emUxF=@v_DG8)L0oT+RJ+zp;R z3OQ*)VDri|wzPm#n%c>bu}h2ac|c#o6c0%%ooqi+!xSO@VTwLI;j7B2t7R`#jpYz7CF=c|m@K*`jh!MIFaY+>Nw*G9 z7p!Bv=3V&8)Ec?Wbn;dp9+xYom`%pXF$Y^zWx7Bla|ey#KWT5Nci8|YfO~-thELt+ zRQ)rccY?6K4@p`Ua^ZJH2!&X!`0`R&*_Uzh3)st3w0!TSNE%@+em>~j{{%kH2aUy2 z0pr|<(jGhM9Z5yK{UqNmZwY2Y>@4~al&s`SJtt^_(VY--R+@y6f|9d}o2AmuF{or@ zLQJygC1HdhcnO`u^6+H^5Jy+Bl0&{-3Mnju##g*}VV?YEEG1!S^|i7=NG+Yky6Fqp zW?6D6ev*GbGGK`;S9mdcQ#NHTRE;O#{q)ybOt2BYNPk|e#j`YT654h9X>RmQr=_s8wB z(51S-{w4!CP}};YcTyfqE{W3=Ld+=h_)TjOSz&Qs^69oCGe-|eSR3a)?vM2ckoOcP zpJM*|1|>slbE}W_Y+ICzQ2HxTQ(;uxiNWP_jn6;i6Z!QY^0{iCQG*ZpkMuM}9rzhx z9N8Y7%nDx`o@2#p?1c zC<>%$IY!5HVpSoUraptnPN#`PDyZsSCqXtAQu+H*I!p_NEGUpB8l3@-Qn8T+bgd{Y zVcQaBNg-PiT9)XYl(}v#K1z$_Hh*Bdl~X20+_Z&XNv=^ZYBK(FW#!hswNvCGpm5ti z5;1&_h-N`Pln3Kcbbwjk|CSOTDA>+;px4^73kW+ojF%T|h>^&EP7Oi@s# zND?vRJah>5fD%lN61>88pW_1y$%>7=T-c3z(b~~>hEK-(L&egavg8;TwS!AQFlS9p z=v0NQ=}k9l&5&7QE@|MWLXP3}J*4zF=!se&dDH(G&dxV1y>=WxZu}fk{#^Ae$RYaD z%0sGhoKyRgBeVa#wR!C_i<$D$~*XyewxC~mNYqv>klN5UjSs?`wGCt5WjT~uWrSWQ_{{+5Kw z)v)TTab8tt!zE_{PNXF0yDrrjD}65JfNfO98Om$)@A?)Kn z+s<%73KL07Rg?0CxR#=!3?;VE8E9mEX&L_Z=ZbUYn-=!Cj#w6M0?eZB#))9P7}@5| zzhp;GA^g=7#1V_)%G22|`hSM^-#Cx<7OR~wjP_EBNvJI+1S zf2J}#L@#W{3@O5XwH+l5V1Y)Qr6Fl^C5T)i)R84pc|BTzMFPkImV8jY9R#Nx|IG?4 zBK0U6K_mj&O<4kAEm`0}2O{gz;6GED=s#0A^`EIs9-*wdSdAiWcQ6YcK;+5fL$OXPf(B5CriJjN26Geo5ZQUo zYoMW+)tW_}sTX%w-69>ds_f3?ddl@0V0o6V+YN$2cx zdT-ozz*e2o&MX(Ge`W7cCTMVHA}QYYr~^MT^HEfO6fiNk3;W3cUh0{pQ6cz{%}Pm) zt7PnCd2fXsrTjD^0d8I-uc{y)nGF>u{!C%&RKu6ZfcC$K zScO4%cY>=N=)ql~<&L4dD7EIC=bbHUKDEAL+C|ZC$nWOqS!;C4N3kb3a@k$caEz5V zZ0v`iO3Q!~oeDMK<(tvdRhGC4vWoMS%M0U1CEpsYxdEX#RQ79@FFbWBU+K1zT5PN{ z-y_dE7L&m`j}L8w#}v=|%hR6&mltv^fpdh5$=5h0ZeFD0MoJX{!Lfsl<2zk$FT3Nr zV)=htuuJZ|!|oX-uS+>m!O4HmcwTwl&)4Iqw@_6Xdf|mSR2Y^bbG|?MJ#;rq#gI$g z)=*do!QxNuzKY?sLSS(dIR5f(e|02AuBY&dYSIj`z3zN_IS;F{r`0WXUrkxdSWRFo zi@>dtPCyQf8ZkP!_*Qd|w7ePje^TzIz4Y-?`x2jb1x(G$9jd{N%sHV&tQ+Wi>;GA# zPX=;+L-M!Mh~HVnY<-50%Wu$fPxHq*6U$?Xz{Am|n*$wBXAu8$7QIqd=Dm*R&9{9! zHv!L1&_gW1b5Ae(|83T$k@Lnj9aVWIL$73?R1Q#&DXpbWY;Yc`dl(3h-+ONc5v+YQ z3tY*0cillPC_Q0`Bg>+j6DU>0Ql%;j(OCDkM)k)YZ&3rhtVZ^4$eH7}7k)1UOQG!D z9Py4&qBX94!~{!CLG@q}y_5Nz7QeJFwRBZ-cK2PRp3tAm+%HNbpbS90w0|QF>$~mj z6O4Fz#_gWtN~}OdPEwP<7`X~e2%wFakIhSh7pelx+#V~+D;tyrS9QEI}ZpXR05)Cd+`gt_F|CLK~ zSN~whsia1!T>NW)#w678H}LGU+Av^Z>TEQoR15Anw!92}h^A5SZ_7%)&yAQ;N6BZX zhzjreeOit0_s@t&!uka?zWXM(3FRka0YB^_4(g(42 z*!Q;UTtGs`#wwl`b!qw#c?)6xI8k87FjkBgS%4k-?>OrAGtJ$3E&G zHI?5|`5!cv7oXEx+I?AZ%ufs1STJtEBtbnFA~&ew%ZP zvaPr(`p*x5?5bhd^KtafBb8-5pY+6xSRGnpGp$rj%S(d*`M+g$7KYB&-nsMO7L{Pi zM8{2k(y_&bRhV#{>8!08sAsbmIZRm@Vi|>Bh(MpF2t(^exy8h# z%~~3bZ)s9Jf0NYO`ol1$RH^hua>=y9;TLiR7b$$`qR2hVUfdji*~f~z%5;-{_l4S- zueJP6L=~RsnMGSOZ3wjoG7?lvA4|za{hibP0HMhrMRXIUEnKFk- z0Y?0(bd-0V?Cejci(77N5v&pdh4{&uL5addPDD1&!l-Bp~?oaz3OvqQA4A-YlnMO&6qTn37el?TAPj znUFjSpYB;dWE7wo8f|o@I(WB55;GFXHS&?etMnkKSSvn)g2;EWk-%Rdhs^swQ^EF! zlzG0*OYPt;;fSH%Is4$CvCFK81Sdfa<;Xl?Bm^VJencMW14FC?CDYMLfYYRUONiU# zisY$`+=Aph9uac1*Dd{wIHetj7l4e9%RjRC)|>NHp~8KoF5zI|4)8-I{j^XKqmP(T zZ$rRR$x;J>hzl%$T`i`LL^y#oVt*o8W{mx8r+m0M@<;V$MjKqQ&P&dyf>oFI{UY-D zJaUbp@9q2LHuJ~+^Y|qI|>#dUaGI zJGj^Sucwoly62nTuWt@D_U783BjvMpPTPjvz76~j&n*C2sio8!!?(N5gLmt%BaePQ zD<-Vl-p_~UJyVk!LR~)|E&X1O4l9Y>Z^WwI?CP?6K2jY%_BFV?%J)G5n@XBGrYZc+`7bZBZwv{5;;tB`FoZ5-SIqr2= zwmB?=4Vkef7dC&wgx7GBIXXuCM0T%RUv4=MF&k57wIFR|cr@74d1SK^@%7pQ2E_xa zg^XytYPC7SHr(BXuD~b`Y%ZFjWPK?L>y$h$CleY9Nh*noU!3Z2Wp#*R#u+A>U_6~zql=k~Ej6t&4-}xwOAG768vrlG86c(=-BjYA%3j?#_G4Z43I#(ny z)pHIcAprzbJKO9rZx!n=OKAjoePp$!1I{t8dbHirN> zD%rEpDmq&x0A&WHi*4c088hhE<;{x;vVe>!*t$C6eoVtwA>t~@fU#J>44vvE=y%a5A;JI+ zhY?Tt7Sm#;k?&sC8Vl{>mKsb4e+i_Jb$?o;1n^lrDRT8lehQBx3wDw*6Z=n$0drqA zCV82h0t@&+6+?4zf=tHJNL~`kP-FA&dWfXC+aNGyE(#YC8C8i|^ThV>vtLQuy@J-I zuS}lfT{B4rf@9&uMV9@FDh-G784($ce7}cuPb`(cYmQn`1&O-xqR))gZy?R0`%1Q- zcf2sRe5ITrC=|xMGRdSY*ZOixB^C^o*^Q|?vJXj;ZbgeoY>h!x&5^HRtu-<&{bwaY zkLtG%>F37~t**LQ2z)vFLUSIZ)VXgC6uWK<$@i6jbo8rQ{Gv04Zsl2`u?BOIF+D1e zzTRL)CHwuaX_R$gDNGf7atA2~DNxIcs$=MuB!c;V_%KMZ3D>zGKotPB`w813(fj^) zSkV3bq|$aZ0PVv!Gu7v5Cg>?iiju(LG{suzU^knxvW50f>@k)BUPUw7S&JbJoo@Zt z#KE^WTgiJdX&-sZ+Yctqm7dP0G2IK7*>o?F9Ku@&d85-C4f1J?JEF3Rv_eTPu%&QN zMpV3o803PjU8W-{wk9$v^@;CAr8F9!6cQ@AScq)_u!2*7yPQOIMLZ&-$;Ax78+yNI z;Y@$MtF=2`n~WNI>)Ka>A`_0Ns1I{7&TI{qjr28PK?8r6A`UkMDH(`Jb!QHs#(oBnfHw{!giO=dGwWqnp% z`Y6;QNBQJvEh34c<=}6!`H`~VFNafU>|xx;L?r|1i&z>Yh}pX=<859+aS>(%DT<_L zq~s6$05c(*<*Z0eXKN!lTiT#1@fa&v40%hwl;-AmS;DpGY`&y%s=Po-cFi3&MnY*( zPnc!~=i0pCgl*ThtT@GImqyh#xzi8|RK-eC2FUD!Bvr}+XBcej_ER-&Kt<^4RhT}b zF1AGTNfBlf+p)8js}>`*2Gi)FvuxF=pm+jnn<=^zt6TMbWP*J&!Fs!T2n?V@m*I*w zHWS$xWdX#gLWOuxgd1ErN<~LcO02JTs9FhhQ%y-yQHZx1#-rEb^)Zqyb24#P8yzV) zLK(3xvTkU!2H8YDDBujN;?6Ho5ygQ-V6py$!#bHMU1`|VdMds-wujiOo1si{ynI31 zJXYpq8<%-3-$j+hq}`iGlPG|VmXYZ2oQz@6_J`$ghZtXK6Y8r(Rh(cnE^TPn)pr(W zNR(hcZ{#qeNK|(=fi=L|f{@qVTlu<0aiF!#LA4dQV(TXFU_otvtX zq)+pcDzT73S+QG(xm_5W$CqhG?=_A^=qai3EqN`OUz9{-*3_)2`%vH6iL9T>I zdFKJP6H6@{>|~YXIG8&m_mONX%DpAB#KFLuyIc(uJseq*Ch_++T3*`0DAExxc5{p@ z+aGVCZ(3dvL1Y|NQ+hd(nWPIphhI~-H=M;_4#5RnJe}FhsWFDR>5R>C;x0dqTm06q z{D2*n>mG^gpUqTx41ghX1WT`{S8~s3M0C9Bz0wKl0tvG)PB*J1mNv{idGF<(M>|qFqYDtm!L*PLJuEijl$x2mY{ho?*Byo96dZ!U7d+O(Rs|W_~s$ zT_jf>KA{(Qbh1jE=WzmRU!mdWY}*ACewGAW^o5BK9GZH*W+B2+Md31~oAjm6Ci(km zhEuUe1yS*XZcWA}yO%S6+k>36pFGPidTNtK9bZ~{Y<6CmfwXLtQpwSoC2&RCI%mRI z#RyGlcMX%%nRL}9FC!&$cYH!Bu&fsbZbj5G%q_g@A60cIPWP3uc2zLlE=j7gTZHG* z$j*X1OV1C-(f8sxZlidcf41oQw{+ndU9JesG3=U4bY$?#^9wWSFlK>GgSYmW#R_)0 z7dm7vhW;|;9Z+!l%DQa2*g>GfX!%isfmjNx9K+STHlF(iS%ZKs4$N5U^4d1&%3JkU;?^!{uVk};Ns3n@d@72%}tw6a1}p-Q&j{=$0k_i9oF z_3Z?Yr!UQAF3+}Dtaa4bI8vj200B*)juWUEqv$NrVf!W6g+}u5ZD12$F(do(+Fp}Z z-^)-_JiOI@bpUD!&-!3Yzq=UyvEK5seeE6t5fwK+$w0k%u+frzxRLsM%b1t47O)(Z zd}~Ycr`n1Qs8!ArXj>Qy#%Z^wW#vgDcYbQ6PmTPd5KcdPY2gS9n-8py&-a;mP$MJGaa;)lt4(Lz5MHEB zXAawH#kJnZi=8Z?7vzos!?>721TMxDphE}+6}a_W1CchH#>Ai_JYi9ZI$@Z~J6O?2 z8vPa7==bOLM1MpvcG>}X&TDJB-oDh7Ci`j(u<%ndd8V0+5pBU=v!?e$zb7*gOqR%_ zcl_7*M^`9;{*Y6G@$(c%0eGYhu?yioi(`Z78~$twAH2U^n|<7G%izhFIuE+S&P!X< zU9la5cksd`Oo0Ye7}ismhKXY8DTLytEq!LL`LbAl&qmdZgv`mKVkYv;MviuDJE)}Y z^SQ)?$wsM~-c@+|9MQbTSM)f1+u$>%i0_h%74;e7*3-?1BE4JTvw0U+D{;V|zzt*$ z7&>8XNjA5#jA>#qo$@H>v8W0{w%5t6$8?1ukP5j7SvRzLaf<~ej7_|+Mc%V_cYPf9ElX?~2$#53h^#xQ-j8JUPB<;^I%$|x_ZgqE8%H%_~i z@Wya*pc@lN_09AF)mU?Y;0oA*XG{_7g&3?0##*A5_PmtnyrV9V%r(2g(GyhGaP8;GpTQycX%tZ8n^{;rhgvb|6?ycK1;I?YmF9d87Y z!F8<^byCW!Sy9y3hl}c3hchUJ6R;Z+JN~vT0o_yic zuZml0Qlv^6WhzG%T>cD09TP#@;OK>n9MPz;N-zA2wxT~lHoa|GTKUAt4!Q(iOp!6>(Q*MJ6WrpE^=Cf5*=l^~;@?213n$_7|046qu1VLcRUrkP565#!khO@TOn3D2@|NR#CeEK?{|-y-wue2z#EIdOF( zEGa6$YNBkb>@Wo{H9NGE0qJD?_^G9u1UYO2i|Vk-@@)aFEpH<$`*_Faibu~QLr?2O z`7j^%>33od^jpI?Zfq}838%Od9hp_0I{{u4DLRt=SX;vP7)PTdG^x}BXv(E3Sob(` zW8SvtKK#SNNVwj4nZT+hl)~sSb~aA8irO-;ObgLF0p2ODw;-sOIo}~ z_YrwZ_(BSBC$=zVuKzByKIEnT#7L#v5FH5qK zY|BFEq9PMZ!05UW zSzRdWN+XCD{?QG4F04*zx5`f4PEGPu*_q>_30z(^G4(AbIa4dy1$?}f%oQCP>@1Ng z1}>cKOBT;!k%hcX9JA^5M8P5X2%26o^(x>F0Me{qP&>CrmQQh711QKEP<)(I{Qji@-q3bZ{qi0SxN%A zW`t?M`H}MYipV2T8U-dTdiJ0(?Kp(opvKyM1xWY4x;889_2fV=@XYj;bZWNPSQ8F^{()xtYTbJo0E zY~`SAGvl&r{g%jfyXRR0Hgj|qNrO`ykyEHh4`jdN<*!xz&&SJ*i(k5sI+y()d4C&x z-8%pE3WVM=9s9^<-(+b2^q;#M&lP3C{ap)@!jm`GMm2q6 z)20#7RLj^>CVNswF*UM)D7t4iPS3C4f^3{sjY^)`ne5M)U^LZKfyOxJ!Dv)cA&0TieN;nD}ixzKh9AdYOw1}Z*)W|juWYRlS@-G3x12&g zj0jOP_cabSVNeQn1l2i$yW2l8HcN2*td}f(!orRu<~!Kqv^+d$DGZ>j!Vp1)*Cw)O zQdQsPfri(`TSR!LAa(&S(>mKTIzd&NaH@Pr<<8hxQ}l(XQQ@;qhW{n~mv^W!nP%%i z6!oJEpmcG@WbvEBgv(D-@AM~{tcGx+1L%=fR?pBvO;#jYG3@`LmZDj0MiVMLchelfAm&^WmWD zn8O3G#0<^@vVp#b0f3do)F2wfKD%dYtHb~jUNkTz+YYA#lf?B%D<>Pmjsu>tEN7MX zJ4|$ER6M}csaZQ&oxv6$^#CT#KC&jbG*G5b*A}g4aE1i}4^5R1vS1+o^Uc&RF({CM z#Ce~(yo1FoNYmuIdrma6@Qbp?rM&N^%wX)N_h`{3p?VZ*bHm#}gaw7e=rJI0LLG%p zcs-nQ@mb`>y76v55VmSn%aOEDYj`Ng^g(j^M_=nVd))l4&oJkPKM-+OqLUiU9GM>M=XQ6? zMHin#qx8|UeALsFcb(n24VoD*gm9#StSFJ6lAO7|pLdY=hK5x5Tljxcw*~z^3>TK& zdu~%Fi&mzc+Hzy#^@>|&_$dL5eH!T)ecmzWBq(C=$B*l4T{VQc?&Bh#O+Z+>RrjtA z2MAno<8H3@z%2z&_*He72f+89>)E-$r8iYAZ;$TRxB`p$jnTQSK}(|x#6=~gJ}vHSlrR4a8H_=e diff --git a/protocols/wlm/kopete_wlm.desktop b/protocols/wlm/kopete_wlm.desktop deleted file mode 100644 --- a/protocols/wlm/kopete_wlm.desktop +++ /dev/null @@ -1,129 +0,0 @@ -[Desktop Entry] -Type=Service -Icon=wlm_protocol -X-KDE-ServiceTypes=Kopete/Protocol -X-KDE-Library=kopete_wlm -X-Kopete-Version=1000900 -X-Kopete-Messaging-Protocol=messaging/wlm -X-KDE-PluginInfo-Author=Kopete Developers -X-KDE-PluginInfo-Email=kopete-devel@kde.org -X-KDE-PluginInfo-Name=kopete_wlm -X-KDE-PluginInfo-Version=0.8.0 -X-KDE-PluginInfo-Website=http://kopete.kde.org -X-KDE-PluginInfo-Category=Protocols -X-KDE-PluginInfo-Depends= -X-KDE-PluginInfo-License=GPL -X-KDE-PluginInfo-EnabledByDefault=false -Name=WLM Messenger -Name[ar]=مرسال WLM -Name[ast]=WLM Messenger -Name[bg]=Моментни съобщения WLM -Name[bs]=WLM Poruke -Name[ca]=WLM Messenger -Name[ca@valencia]=WLM Messenger -Name[cs]=WLM Messenger -Name[da]=WLM-messenger -Name[de]=WLM Messenger -Name[el]=WLM Messenger -Name[en_GB]=WLM Messenger -Name[eo]=WLM Messenger -Name[es]=WLM Messenger -Name[et]=WLM Messenger -Name[eu]=WLM mezularitza -Name[fi]=WLM Messenger -Name[fr]=Messagerie WLM -Name[ga]=WLM Messenger -Name[gl]=WLM Messenger -Name[hne]=डबल्यूएलएम मैसेंजर -Name[hr]=WLM Messenger -Name[hu]=WLM Messenger -Name[ia]=Messagero WLM -Name[it]=Messaggistica WLM -Name[ja]=WLM メッセンジャー -Name[kk]=WLM хабарласу -Name[km]=កម្មវិធី​ផ្ញើសារ​របស់ WLM -Name[ko]=WLM 메신저 -Name[lt]=WLM žinutės -Name[lv]=WLM Ziņotājs -Name[ml]=ഡബ്ലിയുഎല്‍എം ദൂതന്‍ -Name[nb]=WLM Messenger -Name[nds]=WLM-Kortnarichtenmaker -Name[nl]=WLM Messenger -Name[nn]=WLM Messenger -Name[pa]=WLM ਮੈਸੈਂਜਰ -Name[pl]=Komunikator WLM -Name[pt]=WLM Messenger -Name[pt_BR]=Windows Live Messenger -Name[ro]=Mesager WLM -Name[ru]=WLM Messenger -Name[si]=WLM පණිවුඩකරු -Name[sk]=WLM Messenger -Name[sl]=WLM Messenger -Name[sq]=WLM Messenger -Name[sr]=Виндоуз лајв месенџер -Name[sr@ijekavian]=Виндоуз лајв месенџер -Name[sr@ijekavianlatin]=Windows Live Messenger -Name[sr@latin]=Windows Live Messenger -Name[sv]=WLM Messenger -Name[tr]=WLM Messenger -Name[uk]=Кур’єр WLM -Name[wa]=WLM Messenger -Name[x-test]=xxWLM Messengerxx -Name[zh_CN]=WLM Messenger -Name[zh_TW]=WLM Messenger -Comment=Windows Live Messenger plugin -Comment[ar]=ملحق مرسال النوافذ مباشر -Comment[ast]=Complementu de Windows Live Messenger -Comment[bg]=Приставка за съобщения Windows Live -Comment[bs]=Priključak za Windows Live Messenger -Comment[ca]=Connector pel Windows Live Messenger -Comment[ca@valencia]=Connector pel Windows Live Messenger -Comment[cs]=Modul pro Windows Live Messenger -Comment[da]=Plugin til Windows Live Messenger -Comment[de]=Modul für Windows-Live-Messenger -Comment[el]=Πρόσθετο Windows Live Messenger -Comment[en_GB]=Windows Live Messenger plugin -Comment[es]=Complemento de Windows Live Messenger -Comment[et]=Windows Live Messengeri plugin -Comment[eu]=Windows Live Messenger plugina -Comment[fi]=Windows Live Messenger -liitännäinen -Comment[fr]=Module Windows Live Messenger -Comment[ga]=Breiseán le haghaidh Windows Live Messenger -Comment[gl]=Complemento para o Live Messenger de Windows -Comment[hne]=विंडोज लाइव मैसेंजर प्लगइन -Comment[hr]=Priključak za Windows Live Messenger -Comment[hu]=Modul a Windows Live Messengerhez -Comment[ia]=Plug-in de Windows Live Messenger -Comment[it]=Estensione per Windows Live Messenger -Comment[ja]=Windows Live メッセンジャー用プラグイン -Comment[kk]=Windows Live хабарласу плагині -Comment[km]=កម្មវិធី​ជំនួយ​​របស់​កម្មវិធីផ្ញើសារ​បន្តផ្ទាល់​របស់​វីនដូ -Comment[ko]=Windows Live Messenger 플러그인 -Comment[lt]=Windows Live Messenger priedas -Comment[lv]=Windows Live Messenger spraudnis -Comment[ml]=വിന്ഡോസ് ലൈവ് ദൂതന്റെ സംയോജകം -Comment[nb]=Programtillegg for Windows Live Messenger -Comment[nds]=Windows-Live-Kortnarichtenmakermoduul -Comment[nl]=Plugin voor Windows Live Messenger -Comment[nn]=Programtillegg til Windows Live Messenger -Comment[pa]=ਵਿੰਡੋਜ਼ ਲਾਈਵ ਮੈਂਸੇਜ਼ਰ ਪਲੱਗਇਨ -Comment[pl]=Kompatybilność z komunikatorem Windows Live Messenger -Comment[pt]='Plugin' do Windows Live Messenger -Comment[pt_BR]=Plugin do Windows Live Messenger -Comment[ro]=Modul Windows Live Messenger -Comment[ru]=Модуль Windows Live Messenger -Comment[si]=Windows Live Messenger ප්ලගිනය -Comment[sk]=Modul pre Windows Live Messenger -Comment[sl]=Vstavek za Windows Live Messenger -Comment[sq]=Windows Live Messenger plugin -Comment[sr]=Прикључак Виндоуз лајв месенџера -Comment[sr@ijekavian]=Прикључак Виндоуз лајв месенџера -Comment[sr@ijekavianlatin]=Priključak Windows Live Messengera -Comment[sr@latin]=Priključak Windows Live Messengera -Comment[sv]=Insticksprogram för Windows Live Messenger -Comment[th]=ส่วนเสริมเพื่อใช้บริการ Windows Live Messenger -Comment[tr]=Windows Live Messenger eklentisi -Comment[uk]=Додаток кур'єра Windows Live -Comment[x-test]=xxWindows Live Messenger pluginxx -Comment[zh_CN]=Windows Live Messenger 插件 -Comment[zh_TW]=Windows Live Messenger 外掛程式 diff --git a/protocols/wlm/ui/wlmaccountpreferences.ui b/protocols/wlm/ui/wlmaccountpreferences.ui deleted file mode 100644 --- a/protocols/wlm/ui/wlmaccountpreferences.ui +++ /dev/null @@ -1,844 +0,0 @@ - - - WlmAccountPreferences - - - - 0 - 0 - 671 - 412 - - - - Account Preferences - Wlm - - - - 0 - - - - - 3 - - - - B&asic Setup - - - - - - Account Information - - - - - - - - The account name of your account. - - - The account name of your account. - - - WLM passport: - - - false - - - m_passport - - - - - - - The account name of your account. - - - The account name of your account. - - - - - - - - - - - - If you check this checkbox, the account will not be connected when you press the "Connect All" button, or at startup when automatic connection at startup is enabled. - - - E&xclude from connect all - - - false - - - - - - - - - - Registration - - - - 6 - - - 9 - - - - - - 0 - 0 - - - - - 0 - 0 - - - - To connect to the Microsoft network, you will need a Microsoft Passport.<br><br>If you do not currently have a Passport, please click the button to create one. - - - Qt::AlignVCenter - - - true - - - - - - - Re&gister New Account - - - - - - - - - - Qt::Vertical - - - - 20 - 0 - - - - - - - - - Privacy - - - - - - 0 - - - 6 - - - - - Blocked contacts: - - - - - - - 6 - - - 0 - - - - - - - - - - - - - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 20 - - - - - - - - - - Allowed contacts: - - - - - - - Qt::ActionsContextMenu - - - - - - - Qt::ActionsContextMenu - - - - - - - - - <!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" /></head><body> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:italic;">Italics</span> contacts are not on your contact list.</p></body></html> - - - - - - - - Sans Serif - 9 - 75 - false - true - false - false - - - - WARNING: You need to be connected to modify this page - - - Qt::AlignVCenter - - - - - - - - Co&nnection - - - - - - Connection Preferences (for advanced users) - - - - - - &Override default server information - - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 16 - 20 - - - - - - - - - - false - - - Ser&ver / - - - m_serverName - - - - - - - false - - - po&rt: - - - m_serverPort - - - - - - - - - false - - - - 0 - 0 - - - - Only modify these values if you want to use a special IM proxy server, like SIMP - - - Only modify these values if you want to use a special IM proxy server, like SIMP - - - messenger.hotmail.com - - - - - - - false - - - Only modify these values if you want to use a special IM proxy server, like SIMP - - - Only modify these values if you want to use a special IM proxy server, like SIMP - - - 1 - - - 65535 - - - 1863 - - - - - - - - - Enable Proxy - - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 28 - 20 - - - - - - - - - - false - - - Host / - - - - - - - false - - - port: - - - - - - - - - false - - - - 0 - 0 - - - - 0 - - - - - - - false - - - 1 - - - 65535 - - - 8080 - - - - - - - - - - - false - - - HTTP - - - true - - - - - - - false - - - Socks5 - - - - - - - false - - - Username: - - - - - - - false - - - - - - - false - - - Password: - - - - - - - false - - - QLineEdit::Password - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - - - - - Qt::Vertical - - - - 20 - 0 - - - - - - - - - General - - - - - - General Options - - - - - - Do not send custom emoticons to other contacts - - - - - - - Do not show custom emoticons from other contacts - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - - - - Qt::AlignCenter - - - false - - - - - - - - KLineEdit - QLineEdit -
klineedit.h
-
- - Kopete::UI::PasswordWidget - -
kopetepasswordwidget.h
-
-
- - - - optionOverrideServer - toggled(bool) - labelServer - setEnabled(bool) - - - 102 - 89 - - - 104 - 123 - - - - - optionOverrideServer - toggled(bool) - labelPort - setEnabled(bool) - - - 161 - 91 - - - 152 - 122 - - - - - optionOverrideServer - toggled(bool) - m_serverName - setEnabled(bool) - - - 292 - 90 - - - 292 - 122 - - - - - optionOverrideServer - toggled(bool) - m_serverPort - setEnabled(bool) - - - 505 - 91 - - - 507 - 130 - - - - - optionEnableProxy - toggled(bool) - m_labelProxyHost - setEnabled(bool) - - - 341 - 132 - - - 75 - 161 - - - - - optionEnableProxy - toggled(bool) - m_labelProxyPort - setEnabled(bool) - - - 341 - 132 - - - 115 - 161 - - - - - optionEnableProxy - toggled(bool) - m_proxyHost - setEnabled(bool) - - - 341 - 132 - - - 365 - 161 - - - - - optionEnableProxy - toggled(bool) - m_proxyPort - setEnabled(bool) - - - 341 - 132 - - - 630 - 161 - - - - - optionEnableProxy - toggled(bool) - m_radioProxyHttp - setEnabled(bool) - - - 341 - 132 - - - 48 - 191 - - - - - optionEnableProxy - toggled(bool) - m_radioProxySocks5 - setEnabled(bool) - - - 341 - 132 - - - 115 - 191 - - - - - optionEnableProxy - toggled(bool) - m_proxyUsername - setEnabled(bool) - - - 341 - 132 - - - 319 - 191 - - - - - optionEnableProxy - toggled(bool) - m_proxyPassword - setEnabled(bool) - - - 341 - 132 - - - 571 - 191 - - - - - optionEnableProxy - toggled(bool) - m_labelProxyUsername - setEnabled(bool) - - - 341 - 132 - - - 191 - 191 - - - - - optionEnableProxy - toggled(bool) - m_labelProxyPassword - setEnabled(bool) - - - 341 - 132 - - - 447 - 191 - - - - -
diff --git a/protocols/wlm/ui/wlmaddcontactpage.h b/protocols/wlm/ui/wlmaddcontactpage.h deleted file mode 100644 --- a/protocols/wlm/ui/wlmaddcontactpage.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - wlmaddcontactpage.h - Kopete Wlm Protocol - - Copyright (c) 2008 by Tiago Salem Herrmann - Kopete (c) 2002-2003 by the Kopete developers - - ************************************************************************* - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the 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 WLMADDCONTACTPAGE_H -#define WLMADDCONTACTPAGE_H - -#include - -namespace Kopete -{ - class Account; -} -namespace Kopete -{ - class MetaContact; -} -namespace Ui -{ - class WlmAddUI; -} - -/** - * A page in the Add Contact Wizard - * @author Will Stephenson -*/ -class WlmAddContactPage:public AddContactPage -{ - Q_OBJECT -public: - WlmAddContactPage (Kopete::Account * account, QWidget * parent = 0); - ~WlmAddContactPage (); - - /** - * Make a contact out of the entered data - */ - virtual bool apply (Kopete::Account * a, Kopete::MetaContact * m); - /** - * Is the data correct? - */ - virtual bool validateData (); - -protected: - Ui::WlmAddUI * m_wlmAddUI; - Kopete::Account * m_account; -}; - -#endif diff --git a/protocols/wlm/ui/wlmaddcontactpage.cpp b/protocols/wlm/ui/wlmaddcontactpage.cpp deleted file mode 100644 --- a/protocols/wlm/ui/wlmaddcontactpage.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/* - wlmaddcontactpage.cpp - Kopete Wlm Protocol - - Copyright (c) 2008 by Tiago Salem Herrmann - Kopete (c) 2002-2003 by the Kopete developers - - ************************************************************************* - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the 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 "wlmaddcontactpage.h" - -#include -#include -#include - -#include -#include - -#include "kopeteuiglobal.h" -#include "kopeteaccount.h" -#include "kopetemetacontact.h" - -#include "wlmprotocol.h" -#include "ui_wlmaddui.h" - -WlmAddContactPage::WlmAddContactPage (Kopete::Account * account, QWidget * parent): -AddContactPage (parent), m_account(account) -{ - m_wlmAddUI = new Ui::WlmAddUI (); - m_wlmAddUI->setupUi (this); - m_wlmAddUI->m_uniqueName->setFocus(); -} - -WlmAddContactPage::~WlmAddContactPage () -{ - delete m_wlmAddUI; -} - -bool -WlmAddContactPage::apply (Kopete::Account *account, Kopete::MetaContact * metaContact) -{ - QString contactId = m_wlmAddUI->m_uniqueName->text().trimmed(); - return account->addContact( contactId, metaContact, Kopete::Account::ChangeKABC ); -} - -bool -WlmAddContactPage::validateData () -{ - if (!m_account->isConnected()) { - KMessageBox::sorry(this, i18n ("You need to be connected to be able to add contacts."), - i18n("Not Connected"), QFlags()); - return false; - } - - QString contactId = m_wlmAddUI->m_uniqueName->text().trimmed(); - if (WlmProtocol::validContactId(contactId)) - return true; - - KMessageBox::queuedMessageBox( Kopete::UI::Global::mainWidget(), KMessageBox::Sorry, - i18n( "You must enter a valid WLM passport." ), i18n( "MSN Plugin" ) ); - - return false; -} - diff --git a/protocols/wlm/ui/wlmaddui.ui b/protocols/wlm/ui/wlmaddui.ui deleted file mode 100644 --- a/protocols/wlm/ui/wlmaddui.ui +++ /dev/null @@ -1,64 +0,0 @@ - - - WlmAddUI - - - - 0 - 0 - 420 - 198 - - - - - - - The account name of the account you would like to add. - - - The account name of the account you would like to add. - - - &WLM passport: - - - false - - - m_uniqueName - - - - - - - The account name of the account you would like to add. - - - The account name of the account you would like to add. - - - - - - - <i>(for example: joe@hotmail.com)</i> - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - KLineEdit - QLineEdit -
klineedit.h
-
-
- - -
diff --git a/protocols/wlm/ui/wlmchatsessioninkpopup.ui b/protocols/wlm/ui/wlmchatsessioninkpopup.ui deleted file mode 100644 --- a/protocols/wlm/ui/wlmchatsessioninkpopup.ui +++ /dev/null @@ -1,176 +0,0 @@ - - - InkWindow - - - - 0 - 0 - 414 - 116 - - - - - 0 - - - 0 - - - - - 0 - - - QLayout::SetMaximumSize - - - - - - 0 - 0 - - - - - - - - - - Send - - - - - - - Clear - - - - - - - Color - - - - - - - - 80 - 0 - - - - true - - - 1 - - - 5 - - - 1 - - - 3 - - - true - - - Qt::Horizontal - - - false - - - - - - - - - - - - WlmChatSessionInkArea - QWidget -
wlmchatsessioninkarea.h
- 1 -
-
- - - - clear_btn - clicked() - m_inkArea - slotClear() - - - 369 - 46 - - - 163 - 57 - - - - - color_btn - clicked() - m_inkArea - slotColor() - - - 369 - 78 - - - 163 - 57 - - - - - send_btn - clicked() - m_inkArea - slotSend() - - - 369 - 14 - - - 163 - 57 - - - - - pen_size_slider - valueChanged(int) - m_inkArea - slotChangePenSize(int) - - - 369 - 105 - - - 163 - 57 - - - - -
diff --git a/protocols/wlm/ui/wlmeditaccountwidget.h b/protocols/wlm/ui/wlmeditaccountwidget.h deleted file mode 100644 --- a/protocols/wlm/ui/wlmeditaccountwidget.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - wlmeditaccountwidget.h - Kopete Wlm Protocol - - Copyright (c) 2008 by Tiago Salem Herrmann - Kopete (c) 2002-2003 by the Kopete developers - - ************************************************************************* - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the 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 WLMEDITACCOUNTWIDGET_H -#define WLMEDITACCOUNTWIDGET_H - -#include -#include -#include - -namespace Kopete -{ - class Account; -} -namespace Ui -{ - class WlmAccountPreferences; -} -class WlmAccount; - -/** - * A widget for editing this protocol's accounts - * @author Will Stephenson -*/ -class WlmEditAccountWidget:public QWidget, - public KopeteEditAccountWidget -{ - Q_OBJECT public: - WlmEditAccountWidget (QWidget * parent, Kopete::Account * account); - - ~WlmEditAccountWidget (); - - /** - * Make an account out of the entered data - */ - virtual Kopete::Account * apply (); - /** - * Is the data correct? - */ - virtual bool validateData (); - -private slots: - void slotAllow(); - void slotBlock(); - void updateActionsAL(); - void updateActionsBL(); - void deleteALItem(); - void deleteBLItem(); - void slotOpenRegister(); - -private: - QSet m_deletedContactsAL; - QSet m_deletedContactsBL; - QAction* m_deleteActionAL; - QAction* m_deleteActionBL; - WlmAccount* m_wlmAccount; - Ui::WlmAccountPreferences * m_preferencesWidget; -}; - -#endif diff --git a/protocols/wlm/ui/wlmeditaccountwidget.cpp b/protocols/wlm/ui/wlmeditaccountwidget.cpp deleted file mode 100644 --- a/protocols/wlm/ui/wlmeditaccountwidget.cpp +++ /dev/null @@ -1,286 +0,0 @@ -/* - wlmeditaccountwidget.h - Kopete Wlm Protocol - - Copyright (c) 2008 by Tiago Salem Herrmann - Kopete (c) 2002-2003 by the Kopete developers - - ************************************************************************* - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the 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 "wlmeditaccountwidget.h" - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "kopeteuiglobal.h" -#include "kopeteaccount.h" -#include "kopetecontact.h" -#include "ui_wlmaccountpreferences.h" -#include "wlmaccount.h" -#include "wlmprotocol.h" - -WlmEditAccountWidget::WlmEditAccountWidget (QWidget * parent, Kopete::Account * account) - : QWidget (parent), KopeteEditAccountWidget(account), m_wlmAccount(0) -{ - m_preferencesWidget = new Ui::WlmAccountPreferences (); - m_preferencesWidget->setupUi (this); - m_preferencesWidget->mainTabWidget->setCurrentIndex(0); - - if ( account ) - { - m_wlmAccount = static_cast(account); - - m_preferencesWidget->m_passport->setText( m_wlmAccount->accountId() ); - m_preferencesWidget->m_password->load( &m_wlmAccount->password() ); - - m_preferencesWidget->m_passport->setReadOnly( true ); - m_preferencesWidget->m_autologin->setChecked( account->excludeConnect() ); - if ( m_wlmAccount->serverName() != "messenger.hotmail.com" || m_wlmAccount->serverPort() != 1863 ) - m_preferencesWidget->optionOverrideServer->setChecked( true ); - - m_preferencesWidget->m_serverName->setText( m_wlmAccount->serverName() ); - m_preferencesWidget->m_serverPort->setValue( m_wlmAccount->serverPort() ); - - if ( m_wlmAccount->isProxyEnabled() ) - m_preferencesWidget->optionEnableProxy->setChecked( true ); - - m_preferencesWidget->m_proxyHost->setText( m_wlmAccount->proxyHost() ); - m_preferencesWidget->m_proxyPort->setValue( m_wlmAccount->proxyPort() ); - m_preferencesWidget->m_proxyUsername->setText( m_wlmAccount->proxyUsername() ); - m_preferencesWidget->m_proxyPassword->setText( m_wlmAccount->proxyPassword() ); - - m_preferencesWidget->m_doNotSendEmoticons->setChecked( m_wlmAccount->doNotSendEmoticons() ); - m_preferencesWidget->m_doNotRequestEmoticons->setChecked( m_wlmAccount->doNotRequestEmoticons() ); - - if(m_wlmAccount->proxyType() == QNetworkProxy::Socks5Proxy ) - m_preferencesWidget->m_radioProxySocks5->setChecked( true ); - else - m_preferencesWidget->m_radioProxyHttp->setChecked( true ); - - bool connected = account->isConnected(); - if ( connected ) - m_preferencesWidget->m_warning->hide(); - - m_preferencesWidget->m_allowButton->setEnabled( connected ); - m_preferencesWidget->m_blockButton->setEnabled( connected ); - - m_preferencesWidget->m_allowButton->setIcon( QIcon::fromTheme(QStringLiteral("arrow-left")) ); - m_preferencesWidget->m_blockButton->setIcon( QIcon::fromTheme(QStringLiteral("arrow-right")) ); - - QSet serverSideContacts = m_wlmAccount->serverSideContacts(); - foreach ( const QString &contact, m_wlmAccount->allowList() ) - { - QListWidgetItem *item = new QListWidgetItem( contact ); - if ( !serverSideContacts.contains( contact ) ) - { - QFont f = item->font(); - f.setItalic( true ); - item->setFont( f ); - } - m_preferencesWidget->m_AL->addItem( item ); - } - - foreach ( const QString &contact, m_wlmAccount->blockList() ) - { - QListWidgetItem *item = new QListWidgetItem( contact ); - if ( !serverSideContacts.contains( contact ) ) - { - QFont f = item->font(); - f.setItalic( true ); - item->setFont( f ); - } - m_preferencesWidget->m_BL->addItem( item ); - } - - m_deleteActionAL = new QAction( i18n( "Delete" ), m_preferencesWidget->m_AL ); - m_preferencesWidget->m_AL->addAction( m_deleteActionAL ); - - m_deleteActionBL = new QAction( i18n( "Delete" ), m_preferencesWidget->m_BL ); - m_preferencesWidget->m_BL->addAction( m_deleteActionBL ); - - connect( m_preferencesWidget->m_AL, SIGNAL(itemSelectionChanged()), this, SLOT(updateActionsAL()) ); - connect( m_preferencesWidget->m_BL, SIGNAL(itemSelectionChanged()), this, SLOT(updateActionsBL()) ); - connect( m_deleteActionAL, SIGNAL(triggered(bool)), this, SLOT(deleteALItem()) ); - connect( m_deleteActionBL, SIGNAL(triggered(bool)), this, SLOT(deleteBLItem()) ); - } - - connect( m_preferencesWidget->m_allowButton, SIGNAL(clicked()), this, SLOT(slotAllow()) ); - connect( m_preferencesWidget->m_blockButton, SIGNAL(clicked()), this, SLOT(slotBlock()) ); - connect( m_preferencesWidget->buttonRegister, SIGNAL(clicked()), this, SLOT(slotOpenRegister())); - - QWidget::setTabOrder( m_preferencesWidget->m_passport, m_preferencesWidget->m_password->mRemembered ); - QWidget::setTabOrder( m_preferencesWidget->m_password->mRemembered, m_preferencesWidget->m_password->mPassword ); - QWidget::setTabOrder( m_preferencesWidget->m_password->mPassword, m_preferencesWidget->m_autologin ); -} - -WlmEditAccountWidget::~WlmEditAccountWidget () -{ - delete m_preferencesWidget; -} - -Kopete::Account * WlmEditAccountWidget::apply () -{ - if ( !account() ) - setAccount( new WlmAccount( WlmProtocol::protocol(), m_preferencesWidget->m_passport->text().trimmed() ) ); - - KConfigGroup *config = account()->configGroup(); - WlmAccount* wlmAccount = static_cast(account()); - - account()->setExcludeConnect( m_preferencesWidget->m_autologin->isChecked() ); - m_preferencesWidget->m_password->save( &wlmAccount->password() ); - - if (m_preferencesWidget->optionOverrideServer->isChecked() ) { - config->writeEntry( "serverName", m_preferencesWidget->m_serverName->text().trimmed() ); - config->writeEntry( "serverPort", m_preferencesWidget->m_serverPort->value() ); - } - else { - config->writeEntry( "serverName", "messenger.hotmail.com" ); - config->writeEntry( "serverPort", "1863" ); - } - - if (m_preferencesWidget->optionEnableProxy->isChecked() ) { - config->writeEntry( "enableProxy", true ); - config->writeEntry( "proxyHost", m_preferencesWidget->m_proxyHost->text().trimmed() ); - config->writeEntry( "proxyPort", m_preferencesWidget->m_proxyPort->value() ); - config->writeEntry( "proxyUsername", m_preferencesWidget->m_proxyUsername->text() ); - config->writeEntry( "proxyPassword", m_preferencesWidget->m_proxyPassword->text() ); - if(m_preferencesWidget->m_radioProxyHttp->isChecked()) - config->writeEntry( "proxyType", (uint)QNetworkProxy::HttpProxy ); - else - config->writeEntry( "proxyType", (uint)QNetworkProxy::Socks5Proxy ); - } - else { - config->writeEntry( "enableProxy", false ); - } - - config->writeEntry( "doNotSendEmoticons", - m_preferencesWidget->m_doNotSendEmoticons->isChecked()); - - config->writeEntry( "doNotRequestEmoticons", - m_preferencesWidget->m_doNotRequestEmoticons->isChecked()); - - if ( wlmAccount->isConnected() ) - { - QSet allowList = wlmAccount->allowList(); - QSet blockList = wlmAccount->blockList(); - - for ( int i = 0; i < m_preferencesWidget->m_AL->count(); i++ ) - { - QString contact = m_preferencesWidget->m_AL->item(i)->text(); - if ( !allowList.contains(contact) ) - wlmAccount->server()->mainConnection->unblockContact( contact.toLatin1().constData() ); - } - - for ( int i = 0; i < m_preferencesWidget->m_BL->count(); i++ ) - { - QString contact = m_preferencesWidget->m_BL->item(i)->text(); - if ( !blockList.contains(contact) ) - wlmAccount->server()->mainConnection->blockContact( contact.toLatin1().constData() ); - } - - foreach ( const QString &contact, m_deletedContactsAL ) - wlmAccount->server()->mainConnection->removeFromList( MSN::LST_AL, contact.toLatin1().constData() ); - - foreach ( const QString &contact, m_deletedContactsBL ) - wlmAccount->server()->mainConnection->removeFromList( MSN::LST_BL, contact.toLatin1().constData() ); - } - - return account (); -} - -bool WlmEditAccountWidget::validateData () -{ - QString contactId = m_preferencesWidget->m_passport->text().trimmed(); - if ( WlmProtocol::validContactId( contactId ) ) - return true; - - KMessageBox::queuedMessageBox( Kopete::UI::Global::mainWidget(), KMessageBox::Sorry, - i18n( "You must enter a valid WLM passport." ), i18n( "WLM Plugin" ) ); - return false; -} - -void WlmEditAccountWidget::slotAllow() -{ - if ( m_preferencesWidget->m_BL->selectedItems().isEmpty() ) - return; - - QListWidgetItem *item = m_preferencesWidget->m_BL->selectedItems().at(0); - m_preferencesWidget->m_BL->takeItem( m_preferencesWidget->m_BL->row( item ) ); - m_preferencesWidget->m_AL->addItem( item ); -} - -void WlmEditAccountWidget::slotBlock() -{ - if ( m_preferencesWidget->m_AL->selectedItems().isEmpty() ) - return; - - QListWidgetItem *item = m_preferencesWidget->m_AL->selectedItems().at(0); - m_preferencesWidget->m_AL->takeItem( m_preferencesWidget->m_AL->row( item ) ); - m_preferencesWidget->m_BL->addItem( item ); -} - -void WlmEditAccountWidget::updateActionsAL() -{ - bool enableDeleteAction = false; - - if ( m_wlmAccount && !m_preferencesWidget->m_AL->selectedItems().isEmpty() ) - enableDeleteAction = !m_wlmAccount->serverSideContacts().contains( m_preferencesWidget->m_AL->selectedItems().at(0)->text() ); - - m_deleteActionAL->setEnabled( enableDeleteAction ); -} - -void WlmEditAccountWidget::updateActionsBL() -{ - bool enableDeleteAction = false; - - if ( m_wlmAccount && !m_preferencesWidget->m_BL->selectedItems().isEmpty() ) - enableDeleteAction = !m_wlmAccount->serverSideContacts().contains( m_preferencesWidget->m_BL->selectedItems().at(0)->text() ); - - m_deleteActionBL->setEnabled( enableDeleteAction ); -} - -void WlmEditAccountWidget::deleteALItem() -{ - if ( m_wlmAccount && !m_preferencesWidget->m_AL->selectedItems().isEmpty() ) - { - QListWidgetItem *item = m_preferencesWidget->m_AL->selectedItems().at(0); - if ( !m_wlmAccount->serverSideContacts().contains( item->text() ) ) - { - m_deletedContactsAL.insert( item->text() ); - m_preferencesWidget->m_AL->takeItem( m_preferencesWidget->m_AL->row( item ) ); - } - } -} - -void WlmEditAccountWidget::deleteBLItem() -{ - if ( m_wlmAccount && !m_preferencesWidget->m_BL->selectedItems().isEmpty() ) - { - QListWidgetItem *item = m_preferencesWidget->m_BL->selectedItems().at(0); - if ( !m_wlmAccount->serverSideContacts().contains( item->text() ) ) - { - m_deletedContactsBL.insert( item->text() ); - m_preferencesWidget->m_BL->takeItem( m_preferencesWidget->m_BL->row( item ) ); - } - } -} - -void WlmEditAccountWidget::slotOpenRegister() -{ - KToolInvocation::invokeBrowser( "http://register.passport.net/" ); -} - diff --git a/protocols/wlm/ui/wlminfo.ui b/protocols/wlm/ui/wlminfo.ui deleted file mode 100644 --- a/protocols/wlm/ui/wlminfo.ui +++ /dev/null @@ -1,166 +0,0 @@ - - - WLMInfo - - - - 0 - 0 - 641 - 389 - - - - - - - - - - 0 - 0 - - - - Email address: - - - - - - - true - - - - - - - - 0 - 0 - - - - Display name: - - - - - - - true - - - - - - - Personal message: - - - - - - - true - - - - - - - - - Phones - - - - - - Work: - - - - - - - true - - - - - - - Home: - - - - - - - true - - - - - - - Mobile: - - - - - - - true - - - - - - - - - - Show whether you are on the contact list of this user - - - If this box is checked, you are on this user's contact list. -If not, the user has not added you to their list, or has removed you. - - - I am on &the contact list of this contact - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 40 - - - - - - - - m_id - m_displayName - m_personalMessage - m_phw - m_phh - m_phm - m_reversed - - - - diff --git a/protocols/wlm/wlmaccount.h b/protocols/wlm/wlmaccount.h deleted file mode 100644 --- a/protocols/wlm/wlmaccount.h +++ /dev/null @@ -1,378 +0,0 @@ -/* - wlmaccount.h - Kopete Wlm Protocol - - Copyright (c) 2008 by Tiago Salem Herrmann - Kopete (c) 2002-2003 by the Kopete developers - - ************************************************************************* - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the 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 WLMACCOUNT_H -#define WLMACCOUNT_H - -#include -#include -#include "kopetechatsessionmanager.h" -#include "kopetepasswordedaccount.h" -#include "wlmserver.h" -#include "wlmchatsession.h" -#include "wlmtransfermanager.h" -#include "wlmchatmanager.h" - -class KActionMenu; -namespace Kopete -{ - class Contact; -} -namespace Kopete -{ - class MetaContact; -} - -class WlmProtocol; -class WlmServer; -class WlmTransferManager; -class WlmChatManager; - -/** - * This represents an account connected to the wlm - * @author Will Stephenson -*/ -class WlmAccount:public - Kopete::PasswordedAccount -{ - Q_OBJECT - public: - WlmAccount (WlmProtocol * parent, const QString & accountID); - ~ - WlmAccount (); - /** - * Construct the context menu used for the status bar icon - */ - virtual void - fillActionMenu (KActionMenu * actionMenu); - - /** - * Creates a protocol specific Kopete::Contact subclass and adds it to the supplie - * Kopete::MetaContact - */ - virtual bool - createContact (const QString & contactId, - Kopete::MetaContact * parentContact); - /** - * Called when Kopete status is changed globally - */ - virtual void - setOnlineStatus (const Kopete::OnlineStatus & status, - const Kopete::StatusMessage & reason = Kopete::StatusMessage (), - const OnlineStatusOptions& options = None); - virtual void - setStatusMessage (const Kopete::StatusMessage & statusMessage); - /** - * 'Connect' to the wlm server. Only sets myself() online. - */ -// virtual void connect( const Kopete::OnlineStatus& initialStatus = Kopete::OnlineStatus::OnlineStatus() ); - /** - * Disconnect from the server. Only sets myself() offline. - */ - virtual void disconnect (); - - void logOff( Kopete::Account::DisconnectReason reason ); - - /** - * Return a reference to the server stub - */ - virtual void connectWithPassword (const QString & password); - - QString serverName() const; - uint serverPort() const; - - bool isProxyEnabled() const; - QString proxyHost() const; - uint proxyPort() const; - QString proxyUsername() const; - QString proxyPassword() const; - uint proxyType() const; - bool doNotRequestEmoticons() const; - bool doNotSendEmoticons() const; - - WlmServer * server (); - - WlmChatManager * chatManager () - { - return m_chatManager; - } - WlmTransferManager * transferManager () - { - return m_transferManager; - } - - // TODO: Check BPL - bool blockUnknownUsers() const { return true; } - - bool isContactBlocked(const QString& passport) const; - - void blockContact(const QString& passport, bool block); - - bool isOnAllowList(const QString& passport) const { return m_allowList.contains( passport ); } - - bool isOnBlockList(const QString& passport) const { return m_blockList.contains( passport ); } - - bool isOnPendingList(const QString& passport) const { return m_pendingList.contains( passport ); } - - bool isOnReverseList(const QString& passport) const { return m_reverseList.contains( passport ); } - - // forward list (or also called address book) - bool isOnServerSideList(const QString& passport) const { return m_serverSideContactsPassports.contains( passport ); } - - QSet allowList() const { return m_allowList; } - - QSet blockList() const { return m_blockList; } - - QSet pendingList() const { return m_pendingList; } - - QSet serverSideContacts() const { return m_serverSideContactsPassports; } - - QMap groupToGroupId() const { return m_groupToGroupId; } - -public slots: - - void error( int errCode ); - - /** - * Called by the server when it has a message for us. - * This identifies the sending Kopete::Contact and passes it a Kopete::Message - */ - void - contactChangedStatus (const QString & buddy, - const QString & friendlyname, - const MSN::BuddyStatus & status, - const unsigned int &clientID, - const QString & msnobject); - - void - contactDisconnected (const QString & buddy); - - void - connectionCompleted (); - - void - connectionFailed (); - - void - changedStatus (MSN::BuddyStatus & state); - - void - slotGlobalIdentityChanged (Kopete::PropertyContainer *, - const QString & key, const QVariant &, - const QVariant & newValue); - - void setPersonalMessage (const Kopete::StatusMessage & reason); - - void - addressBookReceivedFromServer (std::map < std::string, - MSN::Buddy * >&list); - - void - groupListReceivedFromServer (std::map < std::string, MSN::Group > &list); - - void - gotDisplayName (const QString & displayName); - - void - gotDisplayPicture (const QString & contactId, const QString & filename); - - void - gotNewContact (const MSN::ContactList & list, const QString & contact, - const QString & friendlyname); - - void gotRemovedContactFromList (const MSN::ContactList & list, const QString & contact); - - void - receivedOIMList (std::vector < MSN::eachOIM > &oimlist); - - void - receivedOIM (const QString & id, const QString & message); - - void - gotContactPersonalInfo (const QString & fromPassport, - const MSN::personalInfo & pInfo); - - void - NotificationServerConnectionTerminated (MSN:: - NotificationServerConnection * - conn); - - void mainConnectionError (int errorCode); - - void - scheduleConnect (); - - void gotAddedGroup (bool added, - const QString & groupName, - const QString & groupId); - - void gotRemovedGroup (bool removed, - const QString & groupId); - - void - gotAddedContactToGroup (bool added, - const QString & groupId, - const QString & contactId); - - void - gotRemovedContactFromGroup (bool removed, - const QString & groupId, - const QString & contactId); - - void - gotAddedContactToAddressBook (bool added, - const QString & passport, - const QString & displayName, - const QString & guid); - - void - gotRemovedContactFromAddressBook (bool removed, - const QString & passport, - const QString & contactId); - void - deletedOIM(const QString& id, const bool deleted); - - void - downloadPendingDisplayPicture(); - - void - slotInitialEmailNotification(const int unread_inbox); - - void - slotNewEmailNotification(const QString from, const QString subject); - - void - slotInboxUrl(MSN::hotmailInfo & info); - - protected: - /** - * This simulates contacts going on and offline in sync with the account's status changes - */ - void - updateContactStatus (); - - WlmServer * - m_server; - - WlmTransferManager * - m_transferManager; - - WlmChatManager * - m_chatManager; - - protected - slots: - /** - * Change the account's status. Called by KActions and internally. - */ - void - slotGoOnline (); - /** - * Change the account's status. Called by KActions and internally. - */ - void - slotGoAway (const Kopete::OnlineStatus & status); - /** - * Change the account's status. Called by KActions and internally. - */ - void - slotGoOffline (); - - void - slotGoInvisible (); - - void - disableInitialList () - { - m_initialList = false; - } - - void - enableInitialList () - { - m_initialList = true; - } - - bool - isInitialList () - { - return m_initialList; - } - -private slots: - void addedInfoEventActionActivated(uint actionId); -// void slotStartChat(); - void slotOpenInbox(); - void slotChangePublicName(); - void slotOpenStatus(); - void slotRemoveTmpMailFile(); - void slotRemoveRecentDPRequests(); - -private: - Kopete::OnlineStatus temporaryStatus; - - QAction *m_openInboxAction; -// QAction *m_startChatAction; - QAction *m_changeDNAction; - QAction *m_openStatusAction; - - QString - m_pictureFilename; - - bool - m_initialList; - - uint - clientid; - - QMap < QString, QString > m_oimList; - - //contacts waiting on their group to be added - QMap m_contactAddQueue; - - //group name to group id map - QMap m_groupToGroupId; - - // passport set of contacts which are stored on server - QSet m_serverSideContactsPassports; - - // passport set of contacts which are on allow list - QSet m_allowList; - - // passport set of contacts which are on block list - QSet m_blockList; - - // passport set of contacts which are on pending list - QSet m_pendingList; - - // passport set of contacts which are on reverse list - QSet m_reverseList; - - // passport set of contacts which we do not have the display picture yet - QSet m_pendingDisplayPictureList; - - QTimer * m_pendingDisplayPicturesTimer; - - KTemporaryFile * tmpMailFile; - - QTimer * m_tmpMailFileTimer; - - QStringList m_recentDPRequests; - - int m_lastMainConnectionError; -}; - -#endif diff --git a/protocols/wlm/wlmaccount.cpp b/protocols/wlm/wlmaccount.cpp deleted file mode 100644 --- a/protocols/wlm/wlmaccount.cpp +++ /dev/null @@ -1,1547 +0,0 @@ -/* - wlmaccount.cpp - Kopete Wlm Protocol - - Copyright (c) 2008 by Tiago Salem Herrmann - Kopete (c) 2002-2003 by the Kopete developers - - ************************************************************************* - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the 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 "wlmaccount.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "kopetechatsessionmanager.h" -#include "kopetemetacontact.h" -#include "kopetecontactlist.h" -#include "kopetegroup.h" -#include "kopetepassword.h" -#include "kopeteuiglobal.h" -#include "kopetepicture.h" -#include "kopeteutils.h" -#include "kopetetransfermanager.h" -#include "kopeteidentity.h" -#include "kopeteavatarmanager.h" -#include "kopeteaddedinfoevent.h" - -#include "wlmcontact.h" -#include "wlmprotocol.h" -#include "wlmchatsession.h" - -WlmAccount::WlmAccount (WlmProtocol * parent, const QString & accountID): -Kopete::PasswordedAccount (parent, accountID.toLower ()), -m_server (NULL), -m_transferManager (NULL), -m_chatManager (NULL), -clientid (0), -m_lastMainConnectionError(Callbacks::NoError) -{ - // Init the myself contact - setMyself (new - WlmContact (this, accountId (), accountId (), - Kopete::ContactList::self ()->myself ())); - myself ()->setOnlineStatus (WlmProtocol::protocol ()->wlmOffline); - clientid += MSN::MSNC7; - clientid += MSN::SupportWinks; - clientid += MSN::VoiceClips; - clientid += MSN::InkGifSupport; - clientid += MSN::SIPInvitations; - clientid += MSN::SupportMultiPacketMessaging; - - m_openInboxAction = new QAction(QIcon::fromTheme(QStringLiteral("mail-folder-inbox")), i18n("Open Inbo&x..."), this); - QObject::connect(m_openInboxAction, SIGNAL(triggered(bool)), this, SLOT(slotOpenInbox())); - - m_changeDNAction = new QAction(i18n("&Change Display Name..."), this); - QObject::connect(m_changeDNAction, SIGNAL(triggered(bool)), this, SLOT(slotChangePublicName())); - -// m_startChatAction = new QAction(QIcon::fromTheme(QStringLiteral("mail-message-new")), i18n("&Start Chat..."), this); -// QObject::connect(m_startChatAction, SIGNAL(triggered(bool)), this, SLOT(slotStartChat())); - - m_openStatusAction = new QAction(i18n("Open MS&N service status site..."), this); - QObject::connect(m_openStatusAction, SIGNAL(triggered(bool)), this, SLOT(slotOpenStatus())); - - tmpMailFile = 0L; - m_tmpMailFileTimer = new QTimer(); - QObject::connect(m_tmpMailFileTimer, SIGNAL(timeout()), this, SLOT(slotRemoveTmpMailFile())); -} - -WlmAccount::~WlmAccount () -{ - slotRemoveTmpMailFile(); - delete m_tmpMailFileTimer; - disconnect (); -} - -void -WlmAccount::fillActionMenu (KActionMenu * actionMenu) -{ - Kopete::Account::fillActionMenu (actionMenu); - const bool connected = isConnected(); - m_openInboxAction->setEnabled(connected); -// m_startChatAction->setEnabled(connected); - m_changeDNAction->setEnabled(connected); - - actionMenu->addSeparator(); - - actionMenu->addAction(m_changeDNAction); -// actionMenu->addAction(m_startChatAction); - - actionMenu->addAction(m_openInboxAction); - actionMenu->addAction(m_openStatusAction); -} - -bool -WlmAccount::createContact (const QString & contactId, - Kopete::MetaContact * parentContact) -{ - if ( !m_server ) - return false; - - kDebug() << "contact " << contactId; - WlmContact *newContact = new WlmContact (this, contactId, QString(), parentContact); - - if (parentContact->isTemporary()) - return true; - - if (m_serverSideContactsPassports.contains(contactId)) - { - kDebug() << "contact " << contactId << " already on server list. Do nothing."; - return true; - } - - QString groupName; - Kopete::GroupList kopeteGroups = parentContact->groups(); //get the group list - - if (kopeteGroups.isEmpty() || kopeteGroups.first() == Kopete::Group::topLevel()) - groupName = i18n("Buddies"); - else - groupName = kopeteGroups.first() ? kopeteGroups.first()->displayName() : i18n("Buddies"); - - // emergency exit, should never occur - if (groupName.isEmpty()) - return false; - - m_contactAddQueue.insert(contactId, groupName); - if (!m_groupToGroupId.contains(groupName)) - { - kDebug() << "group \'" << groupName << "\' not found adding group"; - m_server->cb.mainConnection->addGroup (groupName.toUtf8().constData()); - } - else - { - kDebug() << "group \'" << groupName << "\' found adding contact"; - m_server->cb.mainConnection->addToAddressBook (contactId.toLatin1().constData(), contactId.toUtf8().constData()); - } - - return newContact != 0L; -} - -void WlmAccount::setPersonalMessage (const Kopete::StatusMessage & reason) -{ - kDebug (14210) << k_funcinfo; - myself()->setStatusMessage(reason); - if (isConnected ()) - { - MSN::personalInfo pInfo; - pInfo.mediaIsEnabled = 0; - if (reason.message().isEmpty ()) - pInfo.PSM = ""; - else - pInfo.PSM = reason.message().toUtf8().constData(); - - // we have both artist and title - if( reason.hasMetaData("artist") && reason.hasMetaData("title") ) - { - pInfo.mediaIsEnabled = 1; - pInfo.mediaType="Music"; - pInfo.mediaLines.push_back( reason.metaData("artist").toString().toUtf8().constData() ); - pInfo.mediaLines.push_back( reason.metaData("title").toString().toUtf8().constData() ); - pInfo.mediaFormat="{0} - {1}"; - m_server->cb.mainConnection->setPersonalStatus (pInfo); - return; - } - - // we have only the title - if( reason.hasMetaData("title") ) - { - pInfo.mediaIsEnabled = 1; - pInfo.mediaType="Music"; - pInfo.mediaFormat="{0}"; - pInfo.mediaLines.push_back( reason.metaData("title").toString().toUtf8().constData() ); - m_server->cb.mainConnection->setPersonalStatus (pInfo); - return; - } - m_server->cb.mainConnection->setPersonalStatus (pInfo); - } -} - -void -WlmAccount::setOnlineStatus (const Kopete::OnlineStatus & status, - const Kopete::StatusMessage & reason, - const OnlineStatusOptions& /*options*/) -{ - kDebug (14210) << k_funcinfo; - - setPersonalMessage(reason); - - temporaryStatus = status; - - if (status == WlmProtocol::protocol ()->wlmConnecting && - myself ()->onlineStatus () == WlmProtocol::protocol ()->wlmOffline) - slotGoOnline (); - else if (status == WlmProtocol::protocol ()->wlmOnline || status.status () == Kopete::OnlineStatus::Online) - slotGoOnline (); - else if (status == WlmProtocol::protocol ()->wlmOffline) - slotGoOffline (); - else if (status == WlmProtocol::protocol ()->wlmInvisible) - slotGoInvisible (); - else if (status.status () == Kopete::OnlineStatus::Away || - status.status () == Kopete::OnlineStatus::Busy) - slotGoAway (status); -} - -void -WlmAccount::setStatusMessage (const Kopete::StatusMessage & statusMessage) -{ - setPersonalMessage(statusMessage); -} - -void -WlmAccount::slotChangePublicName() -{ - if ( !isConnected() ) - { - return; - //TODO: change it anyway, and sync at the next connection - } - - bool ok; - const QString name = KInputDialog::getText( i18n( "Change Display Name - MSN Plugin" ), //TODO rename MSN to WLM (see also following strings) - i18n( "Enter the new display name by which you want to be visible to your friends on MSN:" ), - myself()->displayName(), &ok ); - - if ( ok ) - { - if ( name.length() > 387 ) - { - KMessageBox::error( Kopete::UI::Global::mainWidget(), - i18n( "The display name you entered is too long. Please use a shorter name.\n" - "Your display name has not been changed." ), - i18n( "Change Display Name - MSN Plugin" ) ); - return; - } - - m_server->cb.mainConnection->setFriendlyName(name.toUtf8().constData(), true); - } -} - -void -WlmAccount::slotOpenInbox() -{ - if (isConnected ()) - m_server->cb.mainConnection->getInboxUrl (); -} - -void -WlmAccount::slotOpenStatus() -{ - KToolInvocation::invokeBrowser(QLatin1String("http://messenger.msn.com/Status.aspx")) ; -} - -void -WlmAccount::connectWithPassword (const QString & pass) -{ - kDebug (14210) << k_funcinfo; - if (myself ()->onlineStatus () != WlmProtocol::protocol ()->wlmOffline) - return; - - if (pass.isEmpty ()) - { - // User has cancelled password prompt. - return; - } - - password ().setWrong (false); - - QString id = accountId (); - QString pass1 = pass; - - enableInitialList (); - - m_lastMainConnectionError = Callbacks::NoError; - m_server = new WlmServer (this, id, pass1); - m_server->WlmConnect ( serverName(), serverPort() ); - - m_transferManager = new WlmTransferManager (this); - - m_chatManager = new WlmChatManager (this); - - QObject::connect (&m_server->cb, SIGNAL (connectionCompleted()), - this, SLOT (connectionCompleted())); - QObject::connect (&m_server->cb, SIGNAL (connectionFailed()), - this, SLOT (connectionFailed())); - QObject::connect (&m_server->cb, SIGNAL(socketError(int)), - this, SLOT(error(int))); - QObject::connect (&m_server->cb, SIGNAL(mainConnectionError(int)), - this, SLOT(mainConnectionError(int))); - QObject::connect (&m_server->cb, - SIGNAL (gotDisplayName(QString)), this, - SLOT (gotDisplayName(QString))); - QObject::connect (&m_server->cb, - SIGNAL (receivedOIMList - (std::vector < MSN::eachOIM > &)), this, - SLOT (receivedOIMList - (std::vector < MSN::eachOIM > &))); - QObject::connect (&m_server->cb, - SIGNAL (receivedOIM(QString,QString)), - this, - SLOT (receivedOIM(QString,QString))); - - QObject::connect (&m_server->cb, - SIGNAL (deletedOIM(QString,bool)), this, - SLOT (deletedOIM(QString,bool))); - QObject::connect (&m_server->cb, - SIGNAL (NotificationServerConnectionTerminated - (MSN::NotificationServerConnection *)), this, - SLOT (NotificationServerConnectionTerminated - (MSN::NotificationServerConnection *))); - QObject::connect (&m_server->cb, SIGNAL (initialEmailNotification(int)), this, - SLOT (slotInitialEmailNotification(int))); - QObject::connect (&m_server->cb, SIGNAL (newEmailNotification(QString,QString)), this, - SLOT (slotNewEmailNotification(QString,QString))); - QObject::connect (&m_server->cb, SIGNAL (inboxUrl(MSN::hotmailInfo&)), this, - SLOT (slotInboxUrl(MSN::hotmailInfo&))); - - myself ()->setOnlineStatus (WlmProtocol::protocol ()->wlmConnecting); -} - -QString WlmAccount::serverName() const -{ - return configGroup()->readEntry( "serverName" , "messenger.hotmail.com" ); -} - -uint WlmAccount::serverPort() const -{ - return configGroup()->readEntry( "serverPort" , 1863 ); -} - -QString WlmAccount::proxyUsername() const -{ - return configGroup()->readEntry( "proxyUsername" ); -} - -QString WlmAccount::proxyPassword() const -{ - return configGroup()->readEntry( "proxyPassword" ); -} - -QString WlmAccount::proxyHost() const -{ - return configGroup()->readEntry( "proxyHost" ); -} - -uint WlmAccount::proxyType() const -{ - return configGroup()->readEntry( "proxyType", 0 ); -} - -uint WlmAccount::proxyPort() const -{ - return configGroup()->readEntry( "proxyPort", 8080 ); -} - -bool WlmAccount::isProxyEnabled() const -{ - return configGroup()->readEntry( "enableProxy", false ); -} - -bool WlmAccount::doNotRequestEmoticons() const -{ - return configGroup()->readEntry( "doNotRequestEmoticons", false ); -} - -bool WlmAccount::doNotSendEmoticons() const -{ - return configGroup()->readEntry( "doNotSendEmoticons", false ); -} - -void -WlmAccount::gotNewContact (const MSN::ContactList & list, - const QString & passport, - const QString & friendlyname) -{ - kDebug() << "contact " << passport; - if (list == MSN::LST_RL) - { - kDebug() << "contact " << passport << " added to reverse list"; - m_reverseList.insert(passport); - Kopete::AddedInfoEvent* event = new Kopete::AddedInfoEvent(passport, this); - QObject::connect(event, SIGNAL(actionActivated(uint)), this, SLOT(addedInfoEventActionActivated(uint))); - - Kopete::AddedInfoEvent::ShowActionOptions actions = Kopete::AddedInfoEvent::AuthorizeAction; - actions |= Kopete::AddedInfoEvent::BlockAction; - //actions |= Kopete::AddedInfoEvent::InfoAction; - - WlmContact * ct = qobject_cast(contacts().value(passport)); - if (!ct || !ct->metaContact() || ct->metaContact()->isTemporary()) - actions |= Kopete::AddedInfoEvent::AddAction; - - event->setContactNickname(friendlyname); - event->showActions(actions); - event->sendEvent(); - } - else if (list == MSN::LST_BL) - { - kDebug() << "contact " << passport << " added to block list"; - m_allowList.remove(passport); - m_blockList.insert(passport); - WlmContact * ct = qobject_cast(contacts().value(passport)); - if(ct) - ct->setOnlineStatus(ct->onlineStatus()); - } - else if (list == MSN::LST_AL) - { - kDebug() << "contact " << passport << " added to allow list"; - m_blockList.remove(passport); - m_allowList.insert(passport); - WlmContact * ct = qobject_cast(contacts().value(passport)); - if(ct) - ct->setOnlineStatus(ct->onlineStatus()); - } -} - -void WlmAccount::gotRemovedContactFromList (const MSN::ContactList & list, const QString & contact) -{ - kDebug() << "contact " << contact; - if (list == MSN::LST_BL) - { - kDebug() << "contact " << contact << " removed from block list"; - m_blockList.remove( contact ); - } - else if (list == MSN::LST_AL) - { - kDebug() << "contact " << contact << " removed from allow list"; - m_allowList.remove( contact ); - } - else if (list == MSN::LST_RL) - { - kDebug() << "contact " << contact << " removed from reverse list"; - m_reverseList.remove( contact ); - // force overlayIcons to be updated - WlmContact * ct = qobject_cast(contacts().value( contact )); - if(ct) - ct->setOnlineStatus(ct->onlineStatus()); - } -} - -void WlmAccount::addedInfoEventActionActivated(uint actionId) -{ - Kopete::AddedInfoEvent *event = qobject_cast(sender()); - if (!event || !isConnected()) - return; - - switch (actionId) - { - case Kopete::AddedInfoEvent::AddContactAction: - event->addContact(); - break; - case Kopete::AddedInfoEvent::AuthorizeAction: - blockContact(event->contactId(), false); - break; - case Kopete::AddedInfoEvent::BlockAction: - if (isOnAllowList(event->contactId())) - server()->mainConnection->removeFromList(MSN::LST_AL, event->contactId().toLatin1().constData()); - if(!isOnBlockList(event->contactId())) - server()->mainConnection->addToList(MSN::LST_BL, event->contactId().toLatin1().constData()); - break; -/* case Kopete::AddedInfoEvent::InfoAction: - break;*/ - } -} - -void -WlmAccount::mainConnectionError(int errorCode) -{ - kDebug (14210) << k_funcinfo; - m_lastMainConnectionError = errorCode; -} - -void -WlmAccount::scheduleConnect () -{ - connect (temporaryStatus); -} - -void -WlmAccount::gotDisplayPicture (const QString & contactId, - const QString & filename) -{ - // FIXME: Why we get local file and not just QByteArray data? - kDebug (14210) << k_funcinfo; - WlmContact * contact = qobject_cast(contacts().value(contactId)); - if (contact) - { - // remove from pending display pictures list if applicable - m_pendingDisplayPictureList.remove(contactId); - - // check file integrity (SHA1D) - QDomDocument xmlobj; - xmlobj.setContent (contact->getMsnObj()); - QString SHA1D_orig = xmlobj.documentElement ().attribute ("SHA1D"); - - QFile f(filename); - QByteArray avatarData; - if (f.exists() && f.size() > 0 && f.open(QIODevice::ReadOnly)) - { - avatarData = f.readAll(); - f.close(); - } - QFile::remove(filename); - - if (!avatarData.isEmpty() && !SHA1D_orig.isEmpty() && - SHA1D_orig == QCryptographicHash::hash(avatarData, QCryptographicHash::Sha1).toBase64()) - { - QImage img; - img.loadFromData(avatarData); - - Kopete::AvatarManager::AvatarEntry entry; - entry.name = contact->contactId(); - entry.category = Kopete::AvatarManager::Contact; - entry.contact = contact; - entry.image = img; - entry = Kopete::AvatarManager::self()->add(entry); - if (!entry.dataPath.isNull()) - { - contact->removeProperty(Kopete::Global::Properties::self()->photo()); - contact->setProperty(Kopete::Global::Properties::self()->photo(), entry.dataPath); - contact->setProperty(WlmProtocol::protocol()->displayPhotoSHA1, SHA1D_orig); - } - } - else - { - contact->removeProperty(WlmProtocol::protocol()->displayPhotoSHA1); - contact->removeProperty(Kopete::Global::Properties::self()->photo()); - } - } -} - -void -WlmAccount::gotDisplayName (const QString & displayName) -{ - kDebug (14210) << k_funcinfo; - myself ()->setNickName (displayName); -} - -void -WlmAccount::gotContactPersonalInfo (const QString & fromPassport, - const MSN::personalInfo & pInfo) -{ - kDebug (14210) << k_funcinfo; - WlmContact * contact = qobject_cast(contacts().value(fromPassport)); - if (contact) - { - // TODO - handle the other fields of pInfo - contact->setStatusMessage(Kopete::StatusMessage(WlmUtils::utf8(pInfo.PSM))); - QString type(WlmUtils::utf8(pInfo.mediaType)); - if (pInfo.mediaIsEnabled && type == "Music") - { - QString song_line (WlmUtils::utf8(pInfo.mediaFormat)); - int num = pInfo.mediaLines.size (); - for (int i = 0; i < num; i++) - { - song_line.replace ('{' + QString::number (i) + '}', WlmUtils::utf8(pInfo.mediaLines[i])); - } - contact->setProperty (WlmProtocol::protocol ()->currentSong, song_line); - } - else - { - contact->removeProperty (WlmProtocol::protocol ()->currentSong); - } - } -} - -void -WlmAccount::contactChangedStatus (const QString & buddy, - const QString & friendlyname, - const MSN::BuddyStatus & state, - const unsigned int &clientID, - const QString & msnobject) -{ - kDebug (14210) << k_funcinfo; - WlmContact *contact = qobject_cast(contacts().value(buddy)); - if (contact) - { - contact->setNickName (friendlyname); - - // set contact properties - contact->setProperty (WlmProtocol::protocol ()->contactCapabilities, QString::number(clientID)); - - if (state == MSN::STATUS_AWAY) - contact->setOnlineStatus (WlmProtocol::protocol ()->wlmAway); - else if (state == MSN::STATUS_AVAILABLE) - contact->setOnlineStatus (WlmProtocol::protocol ()->wlmOnline); - else if (state == MSN::STATUS_INVISIBLE) - contact->setOnlineStatus (WlmProtocol::protocol ()->wlmInvisible); - else if (state == MSN::STATUS_BUSY) - contact->setOnlineStatus (WlmProtocol::protocol ()->wlmBusy); - else if (state == MSN::STATUS_OUTTOLUNCH) - contact->setOnlineStatus (WlmProtocol::protocol ()-> - wlmOutToLunch); - else if (state == MSN::STATUS_ONTHEPHONE) - contact->setOnlineStatus (WlmProtocol::protocol ()-> - wlmOnThePhone); - else if (state == MSN::STATUS_BERIGHTBACK) - contact->setOnlineStatus (WlmProtocol::protocol ()-> - wlmBeRightBack); - else if (state == MSN::STATUS_IDLE) - contact->setOnlineStatus (WlmProtocol::protocol ()->wlmIdle); - - qobject_cast (contact)->setMsnObj(msnobject); - - if (msnobject.isEmpty () || msnobject == "0") // no picture - { - contact->removeProperty(WlmProtocol::protocol()->displayPhotoSHA1); - contact->removeProperty(Kopete::Global::Properties::self()->photo()); - return; - } - - QDomDocument xmlobj; - xmlobj.setContent (msnobject); - - // track display pictures by SHA1D field - QString SHA1D = xmlobj.documentElement ().attribute ("SHA1D"); - - if (SHA1D.isEmpty ()) - return; - - QString currentSHA1D = contact->property(WlmProtocol::protocol()->displayPhotoSHA1).value().toString(); - QString photoPath = contact->property(Kopete::Global::Properties::self()->photo().key()).value().toString(); - if (SHA1D == currentSHA1D && QFileInfo(photoPath).size() > 0) - return; - - // do not request all pictures at once when you are just connected - if (isInitialList ()) - { - // schedule to retrieve this picture later - m_pendingDisplayPictureList.insert(buddy); - return; - } - - if ((myself ()->onlineStatus () != - WlmProtocol::protocol ()->wlmOffline) - && (myself ()->onlineStatus () != - WlmProtocol::protocol ()->wlmInvisible) - && (myself ()->onlineStatus () != - WlmProtocol::protocol ()->wlmUnknown)) - { - // do not open many switchboards in a short period of time - if(!m_recentDPRequests.contains(buddy)) - { - m_recentDPRequests.append(buddy); - QTimer::singleShot(10 * 1000, this, SLOT(slotRemoveRecentDPRequests())); - chatManager ()->requestDisplayPicture(buddy); - } - } - } -} - -void -WlmAccount::contactDisconnected (const QString & buddy) -{ - kDebug (14210) << k_funcinfo; - WlmContact * contact = qobject_cast(contacts().value(buddy)); - if (contact) - { - contact->setOnlineStatus (WlmProtocol::protocol ()->wlmOffline); - } -} - -void -WlmAccount::groupListReceivedFromServer (std::map < std::string, MSN::Group > &list) -{ - kDebug (14210) << k_funcinfo; - // add server groups on local list - std::map < std::string, MSN::Group >::iterator it; - for (it = list.begin (); it != list.end (); ++it) // groups from server - { - MSN::Group * g = &(*it).second; - - QString gName = WlmUtils::utf8(g->name); - Kopete::Group * b = Kopete::ContactList::self ()->findGroup(gName); - if (!b) - { - b = new Kopete::Group(gName); - Kopete::ContactList::self ()->addGroup( b ); - } - - m_groupToGroupId.insert(gName, WlmUtils::latin1(g->groupID)); - } -/* - // remove local groups which are not on server - QPtrList::Iterator it1 = Kopete::ContactList::self()->groups().begin(); - Kopete::Group *group; - for ( group = Kopete::ContactList::self()->groups().first(); group; group = Kopete::ContactList::self()->groups().next() ) - { - bool ok=false; - std::map::iterator it; - for ( it = list.begin(); it != list.end(); ++it ) // groups from server - { - MSN::Group *g = &(*it).second; - if(Kopete::ContactList::self()->findGroup(WlmUtils::utf8(g->name))) - ok=true; - } - if(!ok) - { - if(!group->members().count()) - Kopete::ContactList::self()->removeGroup(group); - } - } -*/ -} - -void -WlmAccount::addressBookReceivedFromServer (std::map < std::string, - MSN::Buddy * >&list) -{ - kDebug (14210) << k_funcinfo; - - // Clear server side passports - m_serverSideContactsPassports.clear (); - m_allowList.clear(); - m_blockList.clear(); - m_pendingList.clear(); - m_reverseList.clear(); - - // local contacts which do not exist on server should be deleted - std::map < std::string, MSN::Buddy * >::iterator it; - for (it = list.begin (); it != list.end (); ++it) - { - Kopete::MetaContact * metacontact = 0L; - MSN::Buddy * b = (*it).second; - QString passport = WlmUtils::passport(b->userName); - - if (b->lists & MSN::LST_AB) - m_serverSideContactsPassports.insert(passport); - if ( b->lists & MSN::LST_AL ) - m_allowList.insert( passport ); - if ( b->lists & MSN::LST_BL ) - m_blockList.insert( passport ); - if ( b->lists & MSN::LST_PL ) - m_pendingList.insert( passport ); - if ( b->lists & MSN::LST_RL ) - m_reverseList.insert(passport); - - // disabled users (not in list) - if(b->properties["isMessengerUser"] == "false") - { - // disable this contact - WlmContact *contact = qobject_cast(contacts().value( passport )); - if (!contact) - { - addContact (passport, QString(), Kopete::Group::topLevel (), Kopete::Account::DontChangeKABC); - contact = qobject_cast(contacts().value( passport )); - } - if(contact) - { - contact->setContactSerial(WlmUtils::latin1(b->properties["contactId"])); - contact->setCurrentGroup(Kopete::Group::topLevel()); - contact->setDisabled(true, false); - } - continue; - } - - if ( !contacts().value( passport ) ) - { - if (!b->friendlyName.length ()) - b->friendlyName = b->userName; - - std::list < MSN::Group * >::iterator i = b->groups.begin (); - - // no groups, add to top level - if (!b->groups.size ()) - { - // only add users in forward list - if (b->lists & MSN::LST_AB) - { - metacontact = addContact (passport, QString(), Kopete::Group::topLevel (), Kopete::Account::DontChangeKABC); - - WlmContact * newcontact = qobject_cast(contacts().value(passport)); - if(!newcontact) - return; - - newcontact->setNickName (WlmUtils::utf8(b->friendlyName)); - } - - if (metacontact) - { - WlmContact *contact = qobject_cast(contacts().value( passport )); - if (contact) - { - contact->setContactSerial(WlmUtils::latin1(b->properties["contactId"])); - kDebug (14210) << "ContactID: " << WlmUtils::latin1(b->properties["contactId"]); - } - } - continue; - } - - for (; i != b->groups.end (); ++i) - { - Kopete::Group * g = Kopete::ContactList::self ()->findGroup (WlmUtils::utf8((*i)->name)); - - if (g) - metacontact = addContact (passport, QString(), g, Kopete::Account::DontChangeKABC); - else - metacontact = addContact (passport, QString(), Kopete::Group::topLevel (), Kopete::Account::DontChangeKABC); - - if (metacontact) - { - WlmContact *contact = qobject_cast(contacts().value( passport )); - if (contact) - { - contact->setNickName(WlmUtils::utf8(b->friendlyName)); - contact->setContactSerial(WlmUtils::latin1(b->properties["contactId"])); - kDebug (14210) << "ContactID: " << WlmUtils::latin1(b->properties["contactId"]); - } - } - } - } - else - { - // check if this contact has changed groups while we were offline. - // users in the toplevel group on server side - if( b->groups.size() == 0) - { - Kopete::Group *current = contacts().value( passport )->metaContact()->groups().first(); - // the contact has no group, so put it on top level group - if(current != Kopete::Group::topLevel ()) - { - contacts().value( passport )->metaContact()-> - moveToGroup(current, Kopete::Group::topLevel ()); - qobject_cast(contacts().value( passport ))->setCurrentGroup(Kopete::Group::topLevel()); - } - continue; - } - // users in only one group on server side - if( b->groups.size() == 1) - { - // users in only one group in the local list - if(contacts().value( passport )->metaContact()->groups().size() == 1) - { - Kopete::Group *current = contacts().value( passport )->metaContact()->groups().first(); - Kopete::Group *newgroup = Kopete::ContactList::self ()->findGroup(WlmUtils::utf8(b->groups.front()->name)); - - if(!current || !newgroup) - continue; - - if(current != newgroup) - { - contacts().value( passport )->metaContact()->moveToGroup(current, newgroup); - qobject_cast(contacts().value( passport ))->setCurrentGroup(newgroup); - } - } - } - } - } -} - -void -WlmAccount::slotGlobalIdentityChanged (Kopete::PropertyContainer *, - const QString & key, const QVariant &, - const QVariant & newValue) -{ - kDebug (14210) << k_funcinfo; - if (key == Kopete::Global::Properties::self ()->photo ().key ()) - { - m_pictureFilename = newValue.toString (); - // TODO - Set no photo on server - if (m_pictureFilename.isEmpty ()) - { - myself()->removeProperty(Kopete::Global::Properties::self()->photo ()); - if(m_server && isConnected ()) - { - m_server->cb.mainConnection->change_DisplayPicture (""); - setOnlineStatus (myself ()->onlineStatus ()); - } - return; - } - - QImage contactPhoto = QImage( m_pictureFilename ); - Kopete::AvatarManager::AvatarEntry entry; - entry.name = myself ()->contactId(); - entry.image = contactPhoto; - entry.category = Kopete::AvatarManager::Contact; - entry.contact = myself(); - entry = Kopete::AvatarManager::self()->add(entry); - - kDebug (14140) << k_funcinfo << m_pictureFilename; - if(!entry.path.isNull()) - { - if(m_server) - m_server->cb.mainConnection->change_DisplayPicture(QFile::encodeName(entry.path).constData()); - - myself()->setProperty(Kopete::Global::Properties::self()->photo (), entry.path); - } - setOnlineStatus (myself ()->onlineStatus ()); - } - else if (key == Kopete::Global::Properties::self ()->nickName ().key ()) - { - QString oldNick = - myself ()->property (Kopete::Global::Properties::self ()-> - nickName ()).value ().toString (); - QString newNick = newValue.toString (); - - if (newNick != oldNick) - { - if(m_server && isConnected()) - m_server->cb.mainConnection->setFriendlyName (newNick.toUtf8().constData()); - } - } -} - -void -WlmAccount::changedStatus (MSN::BuddyStatus & state) -{ - kDebug (14210) << k_funcinfo; - if (state == MSN::STATUS_AWAY) - myself ()->setOnlineStatus (WlmProtocol::protocol ()->wlmAway); - else if (state == MSN::STATUS_AVAILABLE) - myself ()->setOnlineStatus (WlmProtocol::protocol ()->wlmOnline); - else if (state == MSN::STATUS_INVISIBLE) - myself ()->setOnlineStatus (WlmProtocol::protocol ()->wlmInvisible); - else if (state == MSN::STATUS_BUSY) - myself ()->setOnlineStatus (WlmProtocol::protocol ()->wlmBusy); - else if (state == MSN::STATUS_OUTTOLUNCH) - myself ()->setOnlineStatus (WlmProtocol::protocol ()->wlmOutToLunch); - else if (state == MSN::STATUS_ONTHEPHONE) - myself ()->setOnlineStatus (WlmProtocol::protocol ()->wlmOnThePhone); - else if (state == MSN::STATUS_BERIGHTBACK) - myself ()->setOnlineStatus (WlmProtocol::protocol ()->wlmBeRightBack); - if (state == MSN::STATUS_IDLE) - myself ()->setOnlineStatus (WlmProtocol::protocol ()->wlmIdle); - -} - -void -WlmAccount::connectionFailed () -{ - kDebug (14210) << k_funcinfo; - logOff( Kopete::Account::Unknown ); - Kopete::Utils::notifyCannotConnect (this); -} - -void -WlmAccount::connectionCompleted () -{ - kDebug (14210) << k_funcinfo; - - // set all users as offline - foreach ( Kopete::Contact *kc , contacts() ) - { - WlmContact *c = static_cast( kc ); - c->setOnlineStatus (WlmProtocol::protocol ()->wlmOffline); - } - - if (identity ()->hasProperty (Kopete::Global::Properties::self ()->photo ().key())) - { - m_server->cb.mainConnection->change_DisplayPicture(QFile::encodeName(identity()->customIcon()).constData()); - QImage contactPhoto = QImage( identity ()->customIcon() ); - Kopete::AvatarManager::AvatarEntry entry; - entry.name = myself ()->contactId(); - entry.image = contactPhoto; - entry.category = Kopete::AvatarManager::Contact; - entry.contact = myself(); - entry = Kopete::AvatarManager::self()->add(entry); - if(!entry.path.isNull()) - myself()->setProperty(Kopete::Global::Properties::self()->photo (), entry.path); - } - - if ( identity()->hasProperty( Kopete::Global::Properties::self()->nickName().key() )) - { - // use the identity nickname instead of the one stored on the server side - QString nick = identity()->property( - Kopete::Global::Properties::self()->nickName()).value().toString(); - m_server->cb.mainConnection->setFriendlyName(nick.toUtf8().constData()); - } - else - { - // Set myself contact display name here - // This information come along with the address book - // Fix BUG 182366 - m_server->cb.mainConnection->setFriendlyName( m_server->mainConnection->myDisplayName ); - } - - password ().setWrong (false); - - QObject::connect (&m_server->cb, - SIGNAL (changedStatus(MSN::BuddyStatus&)), this, - SLOT (changedStatus(MSN::BuddyStatus&))); - - QObject::connect (&m_server->cb, - SIGNAL (contactChangedStatus - (const QString &, const QString &, - const MSN::BuddyStatus &, const unsigned int &, - const QString &)), this, - SLOT (contactChangedStatus - (const QString &, const QString &, - const MSN::BuddyStatus &, const unsigned int &, - const QString &))); - - QObject::connect (&m_server->cb, - SIGNAL (contactDisconnected(QString)), - this, - SLOT (contactDisconnected(QString))); - - QObject::connect (identity (), - SIGNAL (propertyChanged - (Kopete::PropertyContainer *, const QString &, - const QVariant &, const QVariant &)), - SLOT (slotGlobalIdentityChanged - (Kopete::PropertyContainer *, const QString &, - const QVariant &, const QVariant &))); - - QObject::connect (&m_server->cb, - SIGNAL (gotDisplayPicture - (const QString &, const QString &)), - SLOT (gotDisplayPicture - (const QString &, const QString &))); - - QObject::connect (&m_server->cb, - SIGNAL (gotContactPersonalInfo - (const QString &, - const MSN::personalInfo &)), - SLOT (gotContactPersonalInfo - (const QString &, - const MSN::personalInfo &))); - - QObject::connect (&m_server->cb, SIGNAL(gotNewContact(MSN::ContactList,QString,QString)), - SLOT (gotNewContact(MSN::ContactList,QString,QString))); - - QObject::connect (&m_server->cb, SIGNAL(gotRemovedContactFromList(MSN::ContactList,QString)), - this, SLOT(gotRemovedContactFromList(MSN::ContactList,QString)) ); - - QObject::connect (&m_server->cb, SIGNAL(gotAddedContactToGroup(bool,QString,QString)), - this, SLOT(gotAddedContactToGroup(bool,QString,QString)) ); - - QObject::connect (&m_server->cb, SIGNAL(gotRemovedContactFromGroup(bool,QString,QString)), - this, SLOT(gotRemovedContactFromGroup(bool,QString,QString)) ); - - QObject::connect (&m_server->cb, SIGNAL(gotAddedGroup(bool,QString,QString)), - this, SLOT(gotAddedGroup(bool,QString,QString)) ); - - QObject::connect (&m_server->cb, SIGNAL(gotRemovedGroup(bool,QString)), - this, SLOT(gotRemovedGroup(bool,QString)) ); - - QObject::connect (&m_server->cb, SIGNAL(gotAddedContactToAddressBook(bool,QString,QString,QString)), - this, SLOT(gotAddedContactToAddressBook(bool,QString,QString,QString))); - - QObject::connect (&m_server->cb, SIGNAL(gotRemovedContactFromAddressBook(bool,QString,QString)), - this, SLOT(gotRemovedContactFromAddressBook(bool,QString,QString))); - - MSN::BuddyStatus state = MSN::STATUS_AVAILABLE; - - if (temporaryStatus == WlmProtocol::protocol ()->wlmOnline) - state = MSN::STATUS_AVAILABLE; - else if (temporaryStatus == WlmProtocol::protocol ()->wlmAway) - state = MSN::STATUS_AWAY; - else if (temporaryStatus == WlmProtocol::protocol ()->wlmInvisible) - state = MSN::STATUS_INVISIBLE; - else if (temporaryStatus == WlmProtocol::protocol ()->wlmBusy) - state = MSN::STATUS_BUSY; - else if (temporaryStatus == WlmProtocol::protocol ()->wlmOutToLunch) - state = MSN::STATUS_OUTTOLUNCH; - else if (temporaryStatus == WlmProtocol::protocol ()->wlmOnThePhone) - state = MSN::STATUS_ONTHEPHONE; - else if (temporaryStatus == WlmProtocol::protocol ()->wlmBeRightBack) - state = MSN::STATUS_BERIGHTBACK; - - m_server->cb.mainConnection->setState (state, clientid); - // this prevents our client from downloading display pictures - // when is just connected. - QTimer::singleShot (10 * 1000, this, SLOT (disableInitialList())); - setPersonalMessage(myself()->statusMessage()); - - // download a pending picture every 20 seconds - m_pendingDisplayPicturesTimer = new QTimer(this); - - QObject::connect(m_pendingDisplayPicturesTimer, SIGNAL(timeout()), - this, SLOT(downloadPendingDisplayPicture())); - - m_pendingDisplayPicturesTimer->start(30 * 1000); - - // manage pending list - foreach ( const QString &contact, pendingList() ) - { - // if we do not have this contact yet, so ask for add it - if(!isOnServerSideList(contact) && - !isOnAllowList(contact) && - !isOnBlockList(contact)) - { - // fake this contact in RL to prompt the user to add it - gotNewContact (MSN::LST_RL, contact, contact); - } - } -} - -void WlmAccount::downloadPendingDisplayPicture() -{ - if(!m_pendingDisplayPicturesTimer) - return; - - if (m_pendingDisplayPictureList.isEmpty()) - { - m_pendingDisplayPicturesTimer->stop(); - m_pendingDisplayPicturesTimer->deleteLater(); - m_pendingDisplayPicturesTimer = NULL; - return; - } - - QString passport = m_pendingDisplayPictureList.toList().first(); - m_pendingDisplayPictureList.remove(passport); - - WlmContact * contact = qobject_cast(contacts().value(passport)); - if(!contact) - return; - - // we only download the display picture if we and the contact are online - if ((myself ()->onlineStatus () != WlmProtocol::protocol ()->wlmOffline) - && (myself ()->onlineStatus () != WlmProtocol::protocol ()->wlmInvisible) - && (myself ()->onlineStatus () != WlmProtocol::protocol ()->wlmUnknown) - && (contact->onlineStatus () != WlmProtocol::protocol ()->wlmOffline) - && (contact->onlineStatus () != WlmProtocol::protocol ()->wlmInvisible) - && (contact->onlineStatus () != WlmProtocol::protocol ()->wlmUnknown)) - - { - // do not open many switchboards in a short period of time - if(!m_recentDPRequests.contains(passport)) - { - m_recentDPRequests.append(passport); - QTimer::singleShot(10 * 1000, this, SLOT(slotRemoveRecentDPRequests())); - chatManager ()->requestDisplayPicture (passport); - } - } -} - -void -WlmAccount::slotInitialEmailNotification (const int unread_inbox) -{ - if ( isBusy() ) - return; - - KNotification *notification= new KNotification ("msn_mail", Kopete::UI::Global::mainWidget()); - - notification->setText(i18np( "You have one unread message in your Hotmail inbox.", - "You have %1 unread messages in your Hotmail inbox.", unread_inbox)); - notification->setActions(( QStringList() << i18nc("@action", "Open Inbox" ) << i18nc("@action", "Close" )) ); - notification->setFlags(KNotification::Persistent); - notification->setPixmap(accountIcon(KIconLoader::SizeMedium)); - QObject::connect(notification,SIGNAL(activated()), this , SLOT(slotOpenInbox()) ); - QObject::connect(notification,SIGNAL(action1Activated()), this, SLOT(slotOpenInbox()) ); - QObject::connect(notification,SIGNAL(action2Activated()), notification, SLOT(close()) ); - QObject::connect(notification,SIGNAL(ignored()), notification, SLOT(close()) ); - notification->sendEvent(); -} - -void -WlmAccount::slotNewEmailNotification (const QString from, const QString subject) -{ - if ( isBusy() ) - return; - - KNotification *notification= new KNotification ("msn_mail", Kopete::UI::Global::mainWidget()); - - notification->setText(i18n( "New message from %1 in your Hotmail inbox.

Subject: %2", from, subject)); - notification->setActions(( QStringList() << i18nc("@action", "Open Inbox" ) << i18nc("@action", "Close" )) ); - notification->setFlags(KNotification::Persistent); - notification->setPixmap(accountIcon(KIconLoader::SizeMedium)); - QObject::connect(notification,SIGNAL(activated()), this , SLOT(slotOpenInbox()) ); - QObject::connect(notification,SIGNAL(action1Activated()), this, SLOT(slotOpenInbox()) ); - QObject::connect(notification,SIGNAL(action2Activated()), notification, SLOT(close()) ); - QObject::connect(notification,SIGNAL(ignored()), notification, SLOT(close()) ); - notification->sendEvent(); -} - -void -WlmAccount::slotInboxUrl (MSN::hotmailInfo & info) -{ - //write the tmp file - QString UserID = accountId(); - - QString hotmailRequest = "\n" - "\n" - "\n" - "\n" - "\n" - "

\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "
\n\n"; - - slotRemoveTmpMailFile(); - tmpMailFile = new KTemporaryFile(); - tmpMailFile->setSuffix(".html"); - - if (tmpMailFile->open()) - { - tmpMailFile->write(hotmailRequest.toUtf8()); - tmpMailFile->flush(); - - /* tmpMailFile->close() erases tmpMailFile->fileName property(), so use it before closing file. */ - KToolInvocation::invokeBrowser( tmpMailFile->fileName(), "0" ); // "0" means we don't need startup notification - tmpMailFile->close(); - m_tmpMailFileTimer->start(30000); - m_tmpMailFileTimer->setSingleShot(true); - } - else - kDebug(14140) << "Error opening temporary file"; -} - -void WlmAccount::slotRemoveTmpMailFile() -{ - if (tmpMailFile) - { - delete tmpMailFile; - tmpMailFile = 0L; - } - - m_tmpMailFileTimer->stop(); -} - -void WlmAccount::gotAddedGroup (bool added, - const QString & groupName, - const QString & groupId) -{ - kDebug() << "groupName: " << groupName << "groupId: " << groupId << " added:" << added; - const QStringList contactIdList = m_contactAddQueue.keys (groupName); - if (!added) - { - // Remove contact from add queue. FIXME: We should somehow sync the contact list here - foreach ( const QString &contactId, contactIdList ) - m_contactAddQueue.remove(contactId); - - return; - } - - // Insert new group - m_groupToGroupId.insert(groupName, groupId); - - // Add contact to the new group - foreach ( const QString &contactId, contactIdList ) - { - kDebug() << "adding contact " << contactId; - m_server->cb.mainConnection->addToAddressBook (contactId.toLatin1().constData(), contactId.toUtf8().constData()); - } - - // Sync contact belonging to the new group - foreach ( Kopete::Contact *kc , contacts() ) - { - WlmContact *c = static_cast( kc ); - if ( c->metaContact()->groups().first()->displayName() == groupName ) - c->sync( Kopete::Contact::MovedBetweenGroup ); - } -} - -void WlmAccount::gotRemovedGroup (bool removed, - const QString & groupId) -{ - kDebug() << "groupId: " << groupId << " removed:" << removed; - if ( !removed ) - return; - - // remove group - m_groupToGroupId.remove(m_groupToGroupId.key(groupId)); -} - -void -WlmAccount::gotAddedContactToGroup (bool added, - const QString & groupId, - const QString & contactId) -{ - kDebug() << "groupId: " << groupId << " contactId: " << contactId << " added:" << added; -} - -void -WlmAccount::gotRemovedContactFromGroup (bool removed, - const QString & groupId, - const QString & contactId) -{ - kDebug() << "groupId: " << groupId << " contactId: " << contactId << " removed:" << removed; -} - -void -WlmAccount::gotAddedContactToAddressBook (bool added, const QString & passport, const QString & displayName, const QString & guid) -{ - kDebug() << "contact: " << passport << " added:" << added << " guid: " << guid; - if (added) - { - m_serverSideContactsPassports.insert (passport); - addContact (passport, QString(), Kopete::Group::topLevel (), Kopete::Account::DontChangeKABC); - - WlmContact * newcontact = qobject_cast (contacts().value(passport)); - if (!newcontact) - return; - - newcontact->setContactSerial (guid); - newcontact->setNickName (displayName); - - QString groupName = m_contactAddQueue.value (passport); - if( !groupName.isEmpty() && m_groupToGroupId.contains (groupName) ) - { - kDebug() << "Adding contact \'" << passport << "\' to group \'" << groupName << "\'"; - QString groupId = m_groupToGroupId.value (groupName); - m_server->cb.mainConnection->addToGroup (groupId.toLatin1().constData(), guid.toLatin1().constData()); - } - } - else - { - // TODO: Raise an error - } - - // Remove contact from add queue - m_contactAddQueue.remove(passport); -} - -void -WlmAccount::gotRemovedContactFromAddressBook (bool removed, const QString & passport, const QString & contactId) -{ - Q_UNUSED( contactId ); - - kDebug() << "contact: " << passport << " removed:" << removed; - if (removed) - m_serverSideContactsPassports.remove( passport ); - -} - -void -WlmAccount::NotificationServerConnectionTerminated (MSN:: - NotificationServerConnection - * conn) -{ - Q_UNUSED( conn ); - - kDebug (14210) << k_funcinfo; - - if (m_lastMainConnectionError == Callbacks::WrongPassword) - logOff( Kopete::Account::BadPassword ); - else if (m_lastMainConnectionError == Callbacks::OtherClient) - logOff( Kopete::Account::OtherClient ); - else if (myself ()->onlineStatus () == WlmProtocol::protocol ()->wlmConnecting) - connectionFailed (); - else if (isConnected ()) - logOff( Kopete::Account::Unknown ); -} - -void WlmAccount::disconnect() -{ - logOff( Kopete::Account::Manual ); -} - -void WlmAccount::error( int /*errCode*/ ) -{ - logOff( Kopete::Account::ConnectionReset ); -} - -void WlmAccount::logOff( Kopete::Account::DisconnectReason reason ) -{ - kDebug (14210) << k_funcinfo; - if (m_server) - m_server->WlmDisconnect (); - - if (myself ()) - myself ()->setOnlineStatus (WlmProtocol::protocol ()->wlmOffline); - - foreach ( Kopete::Contact *kc , contacts() ) - { - WlmContact *c = static_cast( kc ); - c->setOnlineStatus (WlmProtocol::protocol ()->wlmOffline); - } - - delete m_transferManager; - m_transferManager = NULL; - delete m_chatManager; - m_chatManager = NULL; - if (m_server) - { - QObject::disconnect (&m_server->cb, 0, 0, 0); - m_server->deleteLater(); - m_server = NULL; - } - - disconnected( reason ); -} - -WlmServer *WlmAccount::server () -{ - return m_server; -} - -bool WlmAccount::isContactBlocked(const QString& passport) const -{ - return (isOnBlockList(passport) || (blockUnknownUsers() && !isOnAllowList(passport))); -} - -void WlmAccount::blockContact(const QString& passport, bool block) -{ - if (!isConnected() || isContactBlocked(passport) == block) - return; - - if (block) - { - if (isOnAllowList(passport)) - server()->mainConnection->removeFromList(MSN::LST_AL, passport.toLatin1().constData()); - - server()->mainConnection->addToList(MSN::LST_BL, passport.toLatin1().constData()); - } - else - { - if (isOnBlockList(passport)) - server()->mainConnection->removeFromList(MSN::LST_BL, passport.toLatin1().constData()); - - server()->mainConnection->addToList(MSN::LST_AL, passport.toLatin1().constData()); - } -} - -void -WlmAccount::slotGoOnline () -{ - kDebug (14210) << k_funcinfo; - - if (!isConnected ()) - connect (WlmProtocol::protocol ()->wlmOnline); - else - m_server->cb.mainConnection->setState (MSN::STATUS_AVAILABLE, - clientid); -} - -void -WlmAccount::slotGoInvisible () -{ - kDebug (14210) << k_funcinfo; - - if (!isConnected ()) - connect (WlmProtocol::protocol ()->wlmInvisible); - else - m_server->cb.mainConnection->setState (MSN::STATUS_INVISIBLE, - clientid); -} - -void -WlmAccount::slotGoAway (const Kopete::OnlineStatus & status) -{ - kDebug (14210) << k_funcinfo; - - if (!isConnected ()) - connect (status); - else - { - if (status == WlmProtocol::protocol ()->wlmIdle) - m_server->cb.mainConnection->setState (MSN::STATUS_IDLE, - clientid); - if (status == WlmProtocol::protocol ()->wlmAway) - m_server->cb.mainConnection->setState (MSN::STATUS_AWAY, - clientid); - else if (status == WlmProtocol::protocol ()->wlmOutToLunch) - m_server->cb.mainConnection->setState (MSN::STATUS_OUTTOLUNCH, - clientid); - else if (status == WlmProtocol::protocol ()->wlmBusy) - m_server->cb.mainConnection->setState (MSN::STATUS_BUSY, - clientid); - else if (status == WlmProtocol::protocol ()->wlmOnThePhone) - m_server->cb.mainConnection->setState (MSN::STATUS_ONTHEPHONE, - clientid); - else if (status == WlmProtocol::protocol ()->wlmBeRightBack) - m_server->cb.mainConnection->setState (MSN::STATUS_BERIGHTBACK, - clientid); - } -} - -void -WlmAccount::slotGoOffline () -{ - kDebug (14210) << k_funcinfo; - - if ( isConnected() || myself ()->onlineStatus ().status () == Kopete::OnlineStatus::Connecting ) - disconnect(); -} - -void -WlmAccount::updateContactStatus () -{ -} - -void -WlmAccount::receivedOIMList (std::vector < MSN::eachOIM > &oimlist) -{ - kDebug (14210) << k_funcinfo; - std::vector < MSN::eachOIM >::iterator i = oimlist.begin (); - for (; i != oimlist.end (); i++) - { - m_oimList[WlmUtils::latin1((*i).id)] = WlmUtils::passport((*i).from); - m_server->cb.mainConnection->get_oim((*i).id, true); - } -} - -void -WlmAccount::deletedOIM(const QString& id, const bool deleted) -{ - kDebug() << " deleted OIM " << id << " " << deleted; -} - -void -WlmAccount::receivedOIM (const QString & id, const QString & message) -{ - kDebug (14210) << k_funcinfo; - QString contactId = m_oimList[id]; - WlmContact * contact = qobject_cast(contacts().value( contactId)); - - Kopete::Message msg = Kopete::Message (contact, myself ()); - msg.setPlainBody (message); - msg.setDirection (Kopete::Message::Inbound); - - if (contact) - contact->manager (Kopete::Contact::CanCreate)->appendMessage (msg); - - m_oimList.remove (id); - m_server->cb.mainConnection->delete_oim (id.toLatin1().constData ()); -} - -void WlmAccount::slotRemoveRecentDPRequests() -{ - m_recentDPRequests.pop_front(); -} - diff --git a/protocols/wlm/wlmchatmanager.h b/protocols/wlm/wlmchatmanager.h deleted file mode 100644 --- a/protocols/wlm/wlmchatmanager.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - wlmchatsession.h - Wlm Message Manager - - Copyright (c) 2008 by Tiago Salem Herrmann - Kopete (c) 2002-2005 by the Kopete developers - - ************************************************************************* - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the 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 WLMCHATMANAGER_H -#define WLMCHATMANAGER_H - -#include - -#include "kopetechatsession.h" -#include "wlmchatsession.h" -#include "wlmaccount.h" -#include - - -class WlmChatManager : public QObject -{ - Q_OBJECT - - public: - WlmChatManager (WlmAccount * account); - ~WlmChatManager (); - WlmAccount *account () - { - return m_account; - } - QMap < MSN::SwitchboardServerConnection *, WlmChatSession * >chatSessions; - - // messages waiting for emoticons to be received - class PendingMessage { - public: - PendingMessage( Kopete::Message* msg ) - : receiveTime(QTime::currentTime()), message(msg) - {} - - QTime receiveTime; - Kopete::Message* message; - }; - QMap > pendingMessages; - - void requestDisplayPicture (QString contactId); - - void createChat (MSN::SwitchboardServerConnection * conn); - - private slots: - - void receivedMessage (MSN::SwitchboardServerConnection * conn, - const QString & from, - const Kopete::Message & message); - - void joinedConversation (MSN::SwitchboardServerConnection * conn, - const QString & passport, - const QString & friendlyname); - - void leftConversation (MSN::SwitchboardServerConnection * conn, - const QString & passport); - - void removeChatSession (QObject * obj); - - void gotNewSwitchboard (MSN::SwitchboardServerConnection * conn, - const void *tag); - - void SwitchboardServerConnectionTerminated ( - MSN::SwitchboardServerConnection * conn); - - void messageSentACK (MSN::SwitchboardServerConnection * conn, - const unsigned int &trID); - - void receivedNudge (MSN::SwitchboardServerConnection * conn, - const QString & passport); - - void receivedTypingNotification (MSN::SwitchboardServerConnection * conn, - const QString & contactId); - - void slotGotVoiceClipNotification (MSN::SwitchboardServerConnection * conn, - const QString & from, - const QString & msnobject); - - void slotGotWinkNotification (MSN::SwitchboardServerConnection * conn, - const QString & from, - const QString & msnobject); - - void slotGotInk (MSN::SwitchboardServerConnection * conn, - const QString & from, - const QByteArray & image); - - void slotGotVoiceClipFile(MSN::SwitchboardServerConnection * conn, - const unsigned int & sessionID, - const QString & file); - - void slotGotEmoticonFile(MSN::SwitchboardServerConnection * conn, - const unsigned int & sessionID, - const QString & alias, - const QString & file); - - void slotGotWinkFile(MSN::SwitchboardServerConnection * conn, - const unsigned int & sessionID, - const QString & file); - - void slotGotEmoticonNotification (MSN::SwitchboardServerConnection * conn, - const QString & buddy, - const QString & alias, - const QString & msnobject); - -protected: - virtual void timerEvent(QTimerEvent *event); - bool fillEmoticons(WlmChatSession *chat, Kopete::Message* message); - -private: - WlmAccount * m_account; - int m_emoticonsTimeoutTimerId; -}; - -#endif diff --git a/protocols/wlm/wlmchatmanager.cpp b/protocols/wlm/wlmchatmanager.cpp deleted file mode 100644 --- a/protocols/wlm/wlmchatmanager.cpp +++ /dev/null @@ -1,720 +0,0 @@ -/* - wlmchatsession.cpp - MSN Message Manager - - Copyright (c) 2008 by Tiago Salem Herrmann - Kopete (c) 2002-2005 by the Kopete developers - - ************************************************************************* - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the 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 "wlmchatmanager.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "kopetecontactaction.h" -#include "kopetemetacontact.h" -#include "kopetecontactlist.h" -#include "kopetechatsessionmanager.h" -#include "kopeteuiglobal.h" -#include "kopeteglobal.h" -#include "kopeteview.h" - -#include "wlmcontact.h" -#include "wlmprotocol.h" -#include "wlmaccount.h" - -const int EmoticonsTimeoutCheckInterval = 2; //seconds -const int EmoticonsTimeoutThreshold = 5; //seconds - -WlmChatManager::WlmChatManager (WlmAccount * account1): -m_account (account1), m_emoticonsTimeoutTimerId(0) -{ - QObject::connect (&account ()->server ()->cb, - SIGNAL (messageReceived - (MSN::SwitchboardServerConnection *, - const QString &, const Kopete::Message &)), - this, - SLOT (receivedMessage - (MSN::SwitchboardServerConnection *, - const QString &, const Kopete::Message &))); - - QObject::connect (&account ()->server ()->cb, - SIGNAL (joinedConversation - (MSN::SwitchboardServerConnection *, - const QString &, const QString &)), this, - SLOT (joinedConversation - (MSN::SwitchboardServerConnection *, - const QString &, const QString &))); - - QObject::connect (&account ()->server ()->cb, - SIGNAL (leftConversation - (MSN::SwitchboardServerConnection *, - const QString &)), this, - SLOT (leftConversation - (MSN::SwitchboardServerConnection *, - const QString &))); - - QObject::connect (&account ()->server ()->cb, - SIGNAL (gotNewSwitchboard - (MSN::SwitchboardServerConnection *, - const void *)), this, - SLOT (gotNewSwitchboard - (MSN::SwitchboardServerConnection *, - const void *))); - - QObject::connect (&account ()->server ()->cb, - SIGNAL (SwitchboardServerConnectionTerminated - (MSN::SwitchboardServerConnection *)), this, - SLOT (SwitchboardServerConnectionTerminated - (MSN::SwitchboardServerConnection *))); - - QObject::connect (&account ()->server ()->cb, - SIGNAL (messageSentACK - (MSN::SwitchboardServerConnection *, - const unsigned int &)), this, - SLOT (messageSentACK - (MSN::SwitchboardServerConnection *, - const unsigned int &))); - - QObject::connect (&account ()->server ()->cb, - SIGNAL (receivedNudge - (MSN::SwitchboardServerConnection *, - const QString &)), this, - SLOT (receivedNudge - (MSN::SwitchboardServerConnection *, - const QString &))); - - QObject::connect (&account ()->server ()->cb, - SIGNAL (receivedTypingNotification - (MSN::SwitchboardServerConnection *, - const QString &)), this, - SLOT (receivedTypingNotification - (MSN::SwitchboardServerConnection *, - const QString &))); - - QObject::connect (&account ()->server ()->cb, - SIGNAL (slotGotEmoticonNotification (MSN::SwitchboardServerConnection *, - const QString &, const QString &, - const QString &)), this, - SLOT (slotGotEmoticonNotification (MSN::SwitchboardServerConnection *, - const QString &, const QString &, - const QString &))); - - QObject::connect (&account ()->server ()->cb, - SIGNAL (slotGotVoiceClipNotification (MSN::SwitchboardServerConnection *, - const QString &, - const QString &)), this, - SLOT(slotGotVoiceClipNotification (MSN::SwitchboardServerConnection *, - const QString &, - const QString &))); - - QObject::connect (&account ()->server ()->cb, - SIGNAL(slotGotWinkNotification (MSN::SwitchboardServerConnection *, - const QString &, - const QString &)), this, - SLOT(slotGotWinkNotification (MSN::SwitchboardServerConnection *, - const QString &, - const QString &))); - - QObject::connect (&account ()->server ()->cb, - SIGNAL(slotGotInk (MSN::SwitchboardServerConnection *, - const QString &, - const QByteArray &)), this, - SLOT(slotGotInk (MSN::SwitchboardServerConnection *, - const QString &, - const QByteArray &))); - - QObject::connect (&account ()->server ()->cb, - SIGNAL(slotGotVoiceClipFile(MSN::SwitchboardServerConnection *, - const unsigned int &, - const QString &)), this, - SLOT(slotGotVoiceClipFile(MSN::SwitchboardServerConnection *, - const unsigned int &, - const QString &))); - - QObject::connect (&account ()->server ()->cb, - SIGNAL(slotGotEmoticonFile(MSN::SwitchboardServerConnection *, - const unsigned int &, - const QString &, - const QString &)), this, - SLOT(slotGotEmoticonFile(MSN::SwitchboardServerConnection *, - const unsigned int &, - const QString &, - const QString &))); - - QObject::connect (&account ()->server ()->cb, - SIGNAL(slotGotWinkFile(MSN::SwitchboardServerConnection *, - const unsigned int &, - const QString &)), this, - SLOT(slotGotWinkFile(MSN::SwitchboardServerConnection *, - const unsigned int &, - const QString &))); -} - -WlmChatManager::~WlmChatManager () -{ - QMap < MSN::SwitchboardServerConnection *, - WlmChatSession * >::Iterator it; - for (it = chatSessions.begin (); it != chatSessions.end (); ++it) - { - if (it.value ()) - it.value ()->setChatService (NULL); - } - chatSessions.clear (); -} - -void -WlmChatManager::receivedNudge (MSN::SwitchboardServerConnection * conn, - const QString & passport) -{ - createChat (conn); - - if(conn) - if(chatSessions[conn]) - chatSessions[conn]->receivedNudge (passport); - -} - -void -WlmChatManager::leftConversation (MSN::SwitchboardServerConnection * conn, - const QString & passport) -{ - kDebug (14210) << k_funcinfo << " " << conn; - WlmChatSession *chat = chatSessions[conn]; - - if (chat) - { - WlmContact * contact = qobject_cast(account ()->contacts().value(passport)); - if (!contact) - return; - chat->removeContact (contact); - } -} - -void -WlmChatManager::removeChatSession (QObject * obj) -{ - QMap ::Iterator it; - for (it = chatSessions.begin (); it != chatSessions.end (); ++it) - { - if (it.value () == obj) - { - it.value ()->deleteLater(); - chatSessions.remove (it.key ()); - return; - } - } -} - -void -WlmChatManager::createChat (MSN::SwitchboardServerConnection * conn) -{ - Kopete::ContactPtrList chatmembers; - kDebug (14210) << k_funcinfo << " " << conn; - - if (chatSessions[conn]) - return; - - std::list < MSN::Passport >::iterator users = conn->users.begin (); - for (; users != conn->users.end (); ++users) - { - QString userPassport = WlmUtils::passport(*users); - Kopete::Contact * contact = account ()->contacts().value(userPassport); - if (!contact) - { - account ()->addContact (userPassport, QString(), 0L, Kopete::Account::Temporary); - contact = account ()->contacts().value(userPassport); - contact->setOnlineStatus (WlmProtocol::protocol ()->wlmUnknown); - } - chatmembers.append (contact); - } - - Kopete::ChatSession * _manager = - Kopete::ChatSessionManager::self ()->findChatSession (account ()->myself (), - chatmembers, - account ()->protocol ()); - if (_manager) - chatSessions[conn] = qobject_cast < WlmChatSession * >(_manager); - else - // create a new chat window - chatSessions[conn] = new WlmChatSession (account ()->protocol (), - account ()->myself (), chatmembers, conn); - if(chatSessions[conn]) - chatSessions[conn]->setChatService (conn); -} - -void -WlmChatManager::joinedConversation (MSN::SwitchboardServerConnection * conn, - const QString & passport, - const QString & friendlyname) -{ - Q_UNUSED( friendlyname ); - - Kopete::ContactPtrList chatmembers; - Kopete::Contact * contact = account ()->contacts().value(passport); - if (!contact) - { - account ()->addContact (passport, QString(), 0L, Kopete::Account::Temporary); - contact = account ()->contacts().value(passport); - contact->setOnlineStatus (WlmProtocol::protocol ()->wlmUnknown); - } - // populate chatmembers from SwitchboardServerConnection - std::list < MSN::Passport >::iterator users = conn->users.begin (); - for (; users != conn->users.end (); ++users) - { - QString userPassport = WlmUtils::passport(*users); - Kopete::Contact * contact = account ()->contacts().value(userPassport); - if (!contact) - { - account ()->addContact (userPassport, QString(), 0L, Kopete::Account::Temporary); - contact = account ()->contacts().value(userPassport); - contact->setOnlineStatus (WlmProtocol::protocol ()->wlmUnknown); - } - chatmembers.append (contact); - } - - // check if we already have a similar connection - WlmChatSession *_manager = - qobject_cast (Kopete::ChatSessionManager::self ()-> - findChatSession (account ()->myself (), chatmembers, - account ()->protocol ())); - - if (_manager) - { - // drop the old and replace by the new one - MSN::SwitchboardServerConnection * conn_current = - chatSessions.key (_manager); - if (conn_current && conn_current != conn) - { - chatSessions.remove (conn_current); - chatSessions[conn] = _manager; - chatSessions[conn]->setChatService(conn); - delete conn_current; - return; - } - } - - createChat (conn); - chatSessions[conn]->addContact (contact); - // the session is ready when there are at least 2 contacts, me and somebody - if (!chatSessions[conn]->isReady ()) - chatSessions[conn]->setReady (true); -} - -void -WlmChatManager::receivedMessage (MSN::SwitchboardServerConnection * conn, - const QString & from, - const Kopete::Message & message) -{ - kDebug (14210) << k_funcinfo << " " << conn; - - createChat (conn); - - WlmChatSession *chat = chatSessions[conn]; - - // Pass it on to the contact to process and display via a KMM - if (chat) - { - Kopete::Contact * contact = account ()->contacts().value(from); - if(!contact) - { - account ()->addContact (from, QString(), 0L, - Kopete::Account::Temporary); - contact = account ()->contacts().value(from); - } - Kopete::Message * newMessage = - new Kopete::Message (contact, chat->members ()); - newMessage->setPlainBody (message.plainBody ()); - newMessage->setFont (message.font ()); - newMessage->setForegroundColor (message.foregroundColor ()); - newMessage->setDirection (Kopete::Message::Inbound); - - WlmContact *contact_from = qobject_cast(contact); - if(!contact_from) - return; - - if(!contact_from->dontShowEmoticons()) - { - if (!fillEmoticons(chat, newMessage)) - { - pendingMessages[conn].append(PendingMessage(newMessage)); - if (m_emoticonsTimeoutTimerId == 0) - m_emoticonsTimeoutTimerId = startTimer(EmoticonsTimeoutCheckInterval * 1000); - return; - } - } - // Add it to the manager - chat->appendMessage (*newMessage); - - delete newMessage; - // send keepalive each 50 seconds. - chat->startSendKeepAlive(); - } - else - { - kWarning (14210) << k_funcinfo << - "unable to look up contact for delivery"; - } -} - -void -WlmChatManager::SwitchboardServerConnectionTerminated ( - MSN::SwitchboardServerConnection * conn) -{ - if(!conn) - return; - - WlmChatSession *chat = chatSessions[conn]; - if (chat) - { - chat->setChatService (NULL); - chatSessions.remove (conn); -/* if(chat->view()) - { - if(!chat->view()->isVisible()) - delete chat; - } - else - delete chat; -*/ - } -} - -void -WlmChatManager::gotNewSwitchboard (MSN::SwitchboardServerConnection * conn, - const void *tag) -{ - Kopete::ContactPtrList chatmembers; - const std::pair < std::string, std::string > *ctx = - static_cast < const std::pair < std::string, std::string > *>(tag); - - if (!ctx) - return; - - conn->inviteUser (ctx->first); - delete ctx; - conn->auth.tag = NULL; - kDebug (14210) << k_funcinfo << " " << conn; -} - -void -WlmChatManager::messageSentACK (MSN::SwitchboardServerConnection * conn, - const unsigned int &trID) -{ - WlmChatSession *chat = chatSessions[conn]; - if (chat) - { - chat->messageSentACK (trID); - } -} - -void -WlmChatManager::requestDisplayPicture (QString contactId) -{ - Kopete::Contact * contact = account ()->contacts().value(contactId); - - if (!contact) - return; - - WlmChatSession *session = - qobject_cast (contact->manager (Kopete::Contact::CanCreate)); - - if (session) - session->requestDisplayPicture (); - -} - -void -WlmChatManager::receivedTypingNotification (MSN::SwitchboardServerConnection * - conn, const QString & contactId) -{ - Kopete::Contact * contact = account ()->contacts().value(contactId); - - if (!contact) - return; - - WlmChatSession *chat = chatSessions[conn]; - if (chat) - { - chat->receivedTypingMsg (contact, true); - } -} - -void -WlmChatManager::slotGotVoiceClipNotification (MSN::SwitchboardServerConnection * conn, - const QString & from, - const QString & msnobject) -{ - Q_UNUSED( from ); - WlmChatSession *chat = chatSessions[conn]; - if (!chat) - return; - unsigned int sessionID = chat->generateSessionID(); - - KTemporaryFile voiceClip; - voiceClip.setPrefix("kopete_voiceclip-"); - voiceClip.setSuffix(".wav"); - voiceClip.setAutoRemove(false); - voiceClip.open(); - chat->addFileToRemove(voiceClip.fileName()); - conn->requestVoiceClip(sessionID, QFile::encodeName(voiceClip.fileName()).constData(), - msnobject.toUtf8().constData()); -} - -void -WlmChatManager::slotGotWinkNotification (MSN::SwitchboardServerConnection * conn, - const QString & from, - const QString & msnobject) -{ - Q_UNUSED( conn ); - Q_UNUSED( from ); - Q_UNUSED( msnobject ); -} - -void -WlmChatManager::slotGotInk (MSN::SwitchboardServerConnection * conn, - const QString & from, - const QByteArray & image) -{ - QByteArray ink; - WlmChatSession *chat = chatSessions[conn]; - if (!chat) - { - return; - } - Kopete::Contact * contact = account ()->contacts().value(from); - if(!contact) - { - account ()->addContact (from, QString(), 0L, Kopete::Account::Temporary); - contact = account ()->contacts().value(from); - } - if(!contact) - return; - - ink = QByteArray::fromBase64(image); - KTemporaryFile *inkImage = new KTemporaryFile(); - inkImage->setPrefix("inkformatgif-"); - inkImage->setSuffix(".gif"); - inkImage->open(); - inkImage->write(ink.constData(), ink.size()); - QString msg=QString ("").arg ( inkImage->fileName() ); - inkImage->close(); - - Kopete::Message kmsg( contact, chat->members() ); - kmsg.setHtmlBody( msg ); - kmsg.setDirection( Kopete::Message::Inbound ); - chat->appendMessage ( kmsg ); - chat->addFileToRemove(inkImage->fileName()); - //TODO mem leak ? inkImage ? - inkImage = 0l; - -} - -void -WlmChatManager::slotGotVoiceClipFile(MSN::SwitchboardServerConnection * conn, - const unsigned int & sessionID, - const QString & file) -{ - Q_UNUSED( sessionID ); - - WlmChatSession *chat = chatSessions[conn]; - if(!chat) - return; - - Kopete::Message kmsg( chat->members().first(), chat->members() ); - kmsg.setType(Kopete::Message::TypeVoiceClipRequest); - kmsg.setDirection( Kopete::Message::Inbound ); - kmsg.setFileName(file); - chat->appendMessage ( kmsg ); -} - -void WlmChatManager::slotGotEmoticonNotification (MSN::SwitchboardServerConnection * conn, - const QString & buddy, - const QString & alias, - const QString & msnobject) -{ - WlmContact *contact = qobject_cast(m_account->contacts().value(buddy)); - - if(!contact) - return; - - if(m_account->doNotRequestEmoticons() || contact->dontShowEmoticons()) - return; - - WlmChatSession *chat = chatSessions[conn]; - if(!chat) - return; - - unsigned int sessionID = chat->generateSessionID(); - - QDomDocument xmlobj; - xmlobj.setContent (msnobject); - - // track display pictures by SHA1D field - QString SHA1D = xmlobj.documentElement ().attribute ("SHA1D"); - if (SHA1D.isEmpty ()) - return; - - QString newlocation = - KGlobal::dirs ()->locateLocal ("appdata", - "wlmpictures/" + - QString (SHA1D.replace ('/', '_'))); - QFile f(newlocation); - if (f.exists () && f.size ()) - { - chat->emoticonsList[alias] = newlocation; - return; - } - - // pending emoticon - chat->emoticonsList[alias].clear(); - - conn->requestEmoticon(sessionID, QFile::encodeName(newlocation).constData(), - msnobject.toUtf8().constData(), alias.toUtf8().constData()); -} - -void -WlmChatManager::slotGotEmoticonFile(MSN::SwitchboardServerConnection * conn, - const unsigned int & sessionID, - const QString & alias, - const QString & file) -{ - Q_UNUSED( sessionID ); - - WlmChatSession *chat = chatSessions[conn]; - if(!chat) - return; - - chat->emoticonsList[alias] = file; - - if(pendingMessages.value(conn).isEmpty()) - return; - - { - QMutableLinkedListIterator it(pendingMessages[conn]); - while (it.hasNext()) - { - PendingMessage pendingMsg = it.next(); - if (fillEmoticons(chat, pendingMsg.message)) - { - chat->appendMessage(*pendingMsg.message); - it.remove(); - delete pendingMsg.message; - } - } - } - - if (pendingMessages.value(conn).isEmpty()) - pendingMessages.remove(conn); -} - -void -WlmChatManager::slotGotWinkFile(MSN::SwitchboardServerConnection * conn, - const unsigned int & sessionID, - const QString & file) -{ - Q_UNUSED( conn ); - Q_UNUSED( sessionID ); - Q_UNUSED( file ); -} - -void WlmChatManager::timerEvent(QTimerEvent *event) -{ - if (m_emoticonsTimeoutTimerId == event->timerId() ) - { - QTime thresholdTime = QTime::currentTime().addSecs(-EmoticonsTimeoutThreshold); - QMutableMapIterator > connIt(pendingMessages); - while (connIt.hasNext()) - { - connIt.next(); - - { - QMutableLinkedListIterator it(connIt.value()); - while (it.hasNext()) - { - PendingMessage pendingMsg = it.next(); - if (pendingMsg.receiveTime < thresholdTime) - { - kDebug(14210) << "Did not get emoticons in time!"; - WlmChatSession *chat = chatSessions[connIt.key()]; - if (chat) - chat->appendMessage(*pendingMsg.message); - - it.remove(); - delete pendingMsg.message; - } - } - } - if (connIt.value().isEmpty()) - connIt.remove(); - } - - if (pendingMessages.isEmpty()) - { - killTimer(m_emoticonsTimeoutTimerId); - m_emoticonsTimeoutTimerId = 0; - } - } -} - -bool WlmChatManager::fillEmoticons(WlmChatSession *chat, Kopete::Message* message) -{ - QString escapedMessage = message->escapedBody(); - - // for each emoticon in our list - QMap::iterator it2 = chat->emoticonsList.begin(); - for (;it2!=chat->emoticonsList.end(); ++it2) - { - QString es = it2.key().toHtmlEscaped(); - if (escapedMessage.contains(es)) - { - if (!QFile::exists(it2.value())) - { // an emoticon is still missing, so wait for it - message->setHtmlBody(escapedMessage); - return false; - } - - QImage iconImage = QImageReader(it2.value()).read(); - - escapedMessage.replace( QRegExp(QString::fromLatin1("%1(?![^><]*>)").arg(QRegExp::escape(es))), - QString::fromLatin1("\"")" ) ); - } - } - message->setHtmlBody(escapedMessage); - return true; -} diff --git a/protocols/wlm/wlmchatsession.h b/protocols/wlm/wlmchatsession.h deleted file mode 100644 --- a/protocols/wlm/wlmchatsession.h +++ /dev/null @@ -1,145 +0,0 @@ -/* - wlmchatsession.h - Wlm Message Manager - - Copyright (c) 2008 by Tiago Salem Herrmann - Kopete (c) 2002-2005 by the Kopete developers - - ************************************************************************* - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the 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 WLMCHATSESSION_H -#define WLMCHATSESSION_H - -#include -#include -#include -#include - -#include -#include -#include - -#include "kopetechatsession.h" -#include "wlmchatsessioninkaction.h" - -#include - -#ifdef HAVE_MEDIASTREAMER -#include -#include -#include -#include -#endif - - -class WlmChatSession: public Kopete::ChatSession -{ - Q_OBJECT - public: - WlmChatSession (Kopete::Protocol * protocol, const Kopete::Contact * user, - Kopete::ContactPtrList others, - MSN::SwitchboardServerConnection * conn = NULL); - virtual ~WlmChatSession (); - void setReady (bool value); - bool isReady (); - void addFileToRemove(QString path); - void setChatService (MSN::SwitchboardServerConnection * conn); - bool isConnecting(); - MSN::SwitchboardServerConnection * getChatService () - { - return m_chatService; - } - void messageSentACK (unsigned int trID); - bool requestChatService (); - void requestDisplayPicture (); - void - setDownloadDisplayPicture (bool a) - { - m_downloadDisplayPicture = a; - } - bool - isDownloadDisplayPicture () - { - return m_downloadDisplayPicture; - } - void - setSendNudge (bool a) - { - m_sendNudge = a; - } - bool - isSendNudge () - { - return m_sendNudge; - } - void receivedNudge (QString passport); - void sendFile (const QString & fileLocation, long unsigned int fileSize); - virtual void inviteContact (const QString &); - void startSendKeepAlive(); - void stopSendKeepAlive(); - unsigned int generateSessionID(); - QMap < QString, QString > emoticonsList; - void convertToGif( const QPixmap & ink, QString filename); - - private slots: - void slotMessageSent (Kopete::Message & message, Kopete::ChatSession * kmm); - void sendTypingMsg (bool istyping); - void sendNudge (); - void switchboardConnectionTimeout (); - void slotActionInviteAboutToShow (); - void slotInviteContact (Kopete::Contact * contact); - void slotSendInk ( const QPixmap &); - void slotSendVoiceStartRec(); - void slotSendVoiceStopRec(); - void slotSendVoiceStopRecTimeout(); - void slotSendFile (); - void sendKeepAlive (); - void messageTimeout(); - - private: - MSN::Message parseMessage(Kopete::Message & msg); - - MSN::SwitchboardServerConnection * m_chatService; - bool m_downloadDisplayPicture; - bool m_sendNudge; - bool m_chatServiceRequested; - int m_tries; - int m_oimid; - int m_sessionID; - QString m_lastMsnObj; - QLinkedList < Kopete::Message > m_messagesQueue; - QMap < unsigned int, Kopete::Message > m_messagesSentQueue; - QLinkedList < int > m_messagesTimeoutQueue; - QLinkedList < QString > m_pendingInvitations; - QLinkedList < QString > m_pendingFiles; - QLinkedList < QByteArray > m_pendingInks; - QAction * m_actionNudge; - WlmChatSessionInkAction * m_actionInk; - KActionMenu * m_actionInvite; - QList < QAction * > m_inviteactions; - QTimer * m_keepalivetimer; - QStringList m_filesToRemove; - -#ifdef HAVE_MEDIASTREAMER - KActionMenu * m_actionVoice; - QString m_currentVoiceClipName; - QTimer *m_voiceTimer; - QLinkedList < QString > m_pendingVoices; - - MSFilter *m_voiceFilter; - MSSndCard *m_voiceCardCapture; - MSTicker *m_voiceTicker; - MSFilter *m_voiceRecorder; -#endif - -}; - -#endif - diff --git a/protocols/wlm/wlmchatsession.cpp b/protocols/wlm/wlmchatsession.cpp deleted file mode 100644 --- a/protocols/wlm/wlmchatsession.cpp +++ /dev/null @@ -1,1183 +0,0 @@ -/* - wlmchatsession.cpp - MSN Message Manager - - Copyright (c) 2008 by Tiago Salem Herrmann - Kopete (c) 2002-2005 by the Kopete developers - - ************************************************************************* - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the 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 "wlmchatsession.h" - -#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 -#include -#include - -#include "kopetecontactaction.h" -#include "kopeteonlinestatus.h" -#include "kopetemetacontact.h" -#include "kopetecontactlist.h" -#include "kopetechatsessionmanager.h" -#include "kopeteuiglobal.h" -#include "kopeteglobal.h" -#include "kopeteview.h" -#include "kopeteutils.h" -#include "private/kopeteemoticons.h" -#include "kopetetransfermanager.h" - -#include "wlmcontact.h" -#include "wlmprotocol.h" -#include "wlmaccount.h" -#include "wlmchatsessioninkaction.h" -#ifdef HAVE_GIFLIB -#include -#include -/* old giflib has no GIFLIB_MAJOR, define to avoid cpp warnings */ -#ifndef GIFLIB_MAJOR -#define GIFLIB_MAJOR 4 -#endif -#endif - -WlmChatSession::WlmChatSession (Kopete::Protocol * protocol, - const Kopete::Contact * user, - Kopete::ContactPtrList others, - MSN::SwitchboardServerConnection * conn): -Kopete::ChatSession (user, others, protocol), -m_chatService (conn), -m_downloadDisplayPicture (false), -m_sendNudge (false), -m_chatServiceRequested (false), -m_tries (0), -m_oimid (1), -m_sessionID(1) -{ -#ifdef HAVE_MEDIASTREAMER - m_voiceFilter = NULL; - m_voiceCardCapture = NULL; - m_voiceTicker = NULL; - m_voiceRecorder = NULL; - m_voiceTimer = NULL; -#endif - - Kopete::ChatSessionManager::self ()->registerChatSession (this); - - setComponentData (protocol->componentData ()); - - connect (this, SIGNAL (messageSent (Kopete::Message &, - Kopete::ChatSession *)), - this, SLOT (slotMessageSent (Kopete::Message &, - Kopete::ChatSession *))); - - connect (this, SIGNAL (myselfTyping(bool)), - this, SLOT (sendTypingMsg(bool))); - - m_keepalivetimer = new QTimer (this); - connect (m_keepalivetimer, SIGNAL (timeout()), SLOT (sendKeepAlive())); - - if (getChatService () - && getChatService ()->connectionState () == - MSN::SwitchboardServerConnection::SB_READY) - { - setReady (true); - } - - m_actionNudge = new QAction (QIcon::fromTheme(QStringLiteral("preferences-desktop-notification-bell")), i18n ("Send Nudge"), this); - actionCollection ()->addAction ("wlmSendNudge", m_actionNudge); - connect (m_actionNudge, SIGNAL (triggered(bool)), this, - SLOT (sendNudge())); - - m_actionInvite = - new KActionMenu (QIcon::fromTheme(QStringLiteral("system-users")), i18n ("&Invite"), this); - actionCollection ()->addAction ("wlmInvite", m_actionInvite); - m_actionInvite->setDelayed(false); - connect (m_actionInvite->menu (), SIGNAL (aboutToShow()), this, - SLOT (slotActionInviteAboutToShow())); - - unsigned int userCaps = qobject_cast(members ().first ())->property(WlmProtocol::protocol()->contactCapabilities).value().toString().toUInt(); - - // if the official client supports Isf, for some reason it won't accept gif's. - if(userCaps & MSN::InkGifSupport && - !(userCaps & MSN::InkIsfSupport)) - { - m_actionInk = new WlmChatSessionInkAction; -#ifdef HAVE_GIFLIB - actionCollection ()->addAction ("wlmSendInk", m_actionInk); -#endif - m_actionInk->setDelayed(false); - connect(m_actionInk, SIGNAL(sendInk(QPixmap)), this, SLOT(slotSendInk(QPixmap))); - } - -#ifdef HAVE_MEDIASTREAMER - if(userCaps & MSN::VoiceClips) - { - m_actionVoice = new KActionMenu (QIcon::fromTheme(QStringLiteral("preferences-desktop-sound")), i18n ("Send &Voice"), this); - actionCollection ()->addAction ("wlmSendVoice", m_actionVoice); - ms_init(); - m_voiceCardCapture = ms_snd_card_manager_get_default_capture_card(ms_snd_card_manager_get()); - if (!m_voiceCardCapture) - { - actionCollection()->action("wlmSendVoice")->setEnabled(false); - actionCollection()->action("wlmSendVoice")->setToolTip(i18n("Sound card not detected")); - } - connect (m_actionVoice->menu(), SIGNAL (aboutToShow()), this, - SLOT (slotSendVoiceStartRec())); - - connect (m_actionVoice->menu(), SIGNAL (aboutToHide()), this, - SLOT (slotSendVoiceStopRec())); - - QAction *stopRec = new QAction(QIcon::fromTheme(QStringLiteral("wlm_fakefriend")), i18n("Stop &recording"), actionCollection ()); - m_actionVoice->addAction (stopRec); - m_actionVoice->setDelayed(false); - } -#endif - - setXMLFile ("wlmchatui.rc"); - setMayInvite (true); -} - -void -WlmChatSession::sendKeepAlive () -{ - if(isReady ()) - getChatService ()->sendKeepAlive (); -} - -void -WlmChatSession::inviteContact (const QString & passport) -{ - if (!isReady () && !isConnecting ()) - { - m_pendingInvitations.append (passport); - requestChatService (); - return; - } - WlmContact * c = qobject_cast(account ()->contacts().value(passport)); - if (c) - slotInviteContact (c); -} - -unsigned int -WlmChatSession::generateSessionID() -{ - m_sessionID++; - QTime midnight(0, 0, 0); - qsrand(midnight.secsTo(QTime::currentTime())); - return (unsigned int) (qrand() + m_sessionID) & 0xFFFFFFFF; -} - -void -WlmChatSession::sendFile (const QString & fileLocation, long unsigned int fileSize) -{ - Q_UNUSED( fileSize ); - - QFileInfo fileInfo(fileLocation); - - MSN::fileTransferInvite ft; - ft.type = MSN::FILE_TRANSFER_WITHOUT_PREVIEW; - ft.sessionId = generateSessionID(); - ft.filename = QFile::encodeName(fileLocation).constData(); - ft.friendlyname = fileInfo.fileName().toUtf8().constData(); - ft.filesize = fileInfo.size (); - ft.userPassport = members ().first ()->contactId ().toLatin1 ().constData (); - - // do not generate preview for big pictures - if(ft.filesize < 2097152) - { - QImage tryImage( fileLocation ); - if(tryImage.format() != QImage::Format_Invalid) - { - ft.type = MSN::FILE_TRANSFER_WITH_PREVIEW; - QByteArray ba; - QBuffer buffer(&ba); - buffer.open(QIODevice::WriteOnly); - tryImage = tryImage.scaled(64,64, Qt::KeepAspectRatio); - // some clients are stretching the image, so make sure it is really 64x64 - if (tryImage.size() != QSize(64,64)) - { - QImage temp(64,64, QImage::Format_ARGB32_Premultiplied); - temp.fill(Qt::transparent); - QRect r = tryImage.rect(); - r.moveCenter(temp.rect().center()); - QPainter p(&temp); - p.drawImage(r.topLeft(), tryImage); - tryImage = temp; - } - tryImage.save(&buffer, "PNG"); - ft.preview = KCodecs::base64Encode(ba).constData(); - } - } - - // TODO create a switchboard to send the file is one if not available. - if (isReady ()) - { - if (!account ()) - return; - WlmAccount *acc = qobject_cast < WlmAccount * >(account ()); - if (!acc) - return; - Kopete::Transfer * transf = - Kopete::TransferManager::transferManager ()-> - addTransfer (members ().first (), fileLocation, - QFile (fileLocation).size (), - members ().first ()->contactId (), - Kopete::FileTransferInfo::Outgoing); - - connect (transf, SIGNAL (transferCanceled()), - acc->transferManager (), SLOT (slotCanceled())); - acc->transferManager ()->addTransferSession (ft.sessionId, transf, - account ()->myself ()-> - contactId (), - members ().first ()-> - contactId ()); - - setCanBeDeleted (false); - getChatService ()->sendFile (ft); - } - else - { - m_pendingFiles.append (fileLocation); - if (!isConnecting ()) - requestChatService (); - } -} - -void -WlmChatSession::slotSendVoiceStartRec () -{ -#ifdef HAVE_MEDIASTREAMER - if (members ().count () < 0) - return; - - if(members ().first ()->onlineStatus () == - WlmProtocol::protocol ()->wlmOffline || - members ().first ()->onlineStatus () == - WlmProtocol::protocol ()->wlmUnknown) - { - Kopete::Message msg = Kopete::Message (); - msg.setPlainBody (i18n ("The other contact needs to be online to receive voice clips.")); - msg.setDirection (Kopete::Message::Internal); - appendMessage (msg); - // we cannot call hide() directly because the menu is not shown yet. - QTimer::singleShot(0, m_actionVoice->menu(), SLOT(hide())); - return; - } - - if(myself()->onlineStatus () == - WlmProtocol::protocol ()->wlmInvisible) - { - Kopete::Message msg = Kopete::Message (); - msg.setPlainBody (i18n ("You cannot send voice clips in invisible status")); - msg.setDirection (Kopete::Message::Internal); - appendMessage (msg); - // we cannot call hide() directly because the menu is not shown yet. - QTimer::singleShot(0, m_actionVoice->menu(), SLOT(hide())); - return; - } - - KTemporaryFile voiceClip; - voiceClip.setPrefix("kopete_voiceClip-"); - voiceClip.setSuffix(".wav"); - voiceClip.open(); - voiceClip.setAutoRemove(false); - m_currentVoiceClipName = voiceClip.fileName(); - addFileToRemove(m_currentVoiceClipName); - - int rate = 16000; - - m_voiceFilter=ms_snd_card_create_reader(m_voiceCardCapture); - - ms_filter_call_method (m_voiceFilter, MS_FILTER_SET_SAMPLE_RATE, &rate); - m_voiceTicker=ms_ticker_new(); - - m_voiceRecorder = ms_filter_new(MS_FILE_REC_ID); - ms_filter_call_method(m_voiceRecorder,MS_FILE_REC_OPEN, QFile::encodeName(m_currentVoiceClipName).data ()); - ms_filter_call_method_noarg(m_voiceRecorder,MS_FILE_REC_START); - ms_filter_call_method (m_voiceRecorder, MS_FILTER_SET_SAMPLE_RATE, &rate); - - ms_filter_link(m_voiceFilter,0,m_voiceRecorder,0); - - ms_ticker_attach(m_voiceTicker,m_voiceFilter); - if(!m_voiceTimer) - { - m_voiceTimer = new QTimer(this); - connect(m_voiceTimer, SIGNAL(timeout()), this, SLOT(slotSendVoiceStopRecTimeout())); - m_voiceTimer->start (15 * 1000); - } -#endif -} - -void -WlmChatSession::slotSendVoiceStopRecTimeout() -{ -#ifdef HAVE_MEDIASTREAMER - if(m_voiceTimer) - { - Kopete::Message msg = Kopete::Message (); - msg.setPlainBody (i18n ("The maximum recording time is 15 seconds")); - msg.setDirection (Kopete::Message::Internal); - appendMessage (msg); - slotSendVoiceStopRec(); - } -#endif -} - -void -WlmChatSession::slotSendVoiceStopRec() -{ -#ifdef HAVE_MEDIASTREAMER - if(m_actionVoice) - m_actionVoice->menu()->hide(); - if(m_voiceTimer) - { - m_voiceTimer->stop(); - m_voiceTimer->deleteLater(); - m_voiceTimer = NULL; - } - if(m_voiceRecorder) - ms_filter_call_method_noarg(m_voiceRecorder,MS_FILE_REC_CLOSE); - if(m_voiceTicker && m_voiceFilter) - ms_ticker_detach(m_voiceTicker,m_voiceFilter); - if(m_voiceFilter && m_voiceRecorder) - ms_filter_unlink(m_voiceFilter,0,m_voiceRecorder,0); - if(m_voiceFilter) - ms_filter_destroy(m_voiceFilter); - if(m_voiceTicker) - ms_ticker_destroy(m_voiceTicker); - if(m_voiceRecorder) - ms_filter_destroy(m_voiceRecorder); - - m_voiceRecorder=NULL; - m_voiceTicker=NULL; - m_voiceFilter=NULL; - - if(m_currentVoiceClipName.isEmpty()) - return; - - // average size of a 0.5 second voice clip - if(QFile(m_currentVoiceClipName).size() < 15000) - { - Kopete::Message msg = Kopete::Message (); - msg.setPlainBody (i18n ("The voice clip must be longer")); - msg.setDirection (Kopete::Message::Internal); - appendMessage (msg); - m_currentVoiceClipName = QString(); - return; - } - - if(getChatService () && isReady()) - { - std::string obj; - - // keep a local file without the conversion to siren. - // we use KTemporaryFile to generate a random file name - KTemporaryFile voiceClip; - voiceClip.setPrefix("kopete_voiceClip-"); - voiceClip.setSuffix(".wav"); - voiceClip.setAutoRemove(false); - voiceClip.open(); - QString localVoice = voiceClip.fileName(); - addFileToRemove(voiceClip.fileName()); - voiceClip.close(); - // copy will not overwrite the file, so we need to delete it - voiceClip.remove(); - QFile::copy(m_currentVoiceClipName, localVoice); - - QByteArray localFileName = QFile::encodeName(m_currentVoiceClipName); - getChatService ()->myNotificationServer()->msnobj.addMSNObject(localFileName.constData (),11); - getChatService ()->myNotificationServer()->msnobj.getMSNObjectXML(localFileName.constData (), 11, obj); - getChatService ()->sendVoiceClip(obj); - - Kopete::Message kmsg( myself(), members() ); - kmsg.setType(Kopete::Message::TypeVoiceClipRequest); - kmsg.setDirection( Kopete::Message::Outbound ); - kmsg.setFileName(localVoice); - appendMessage ( kmsg ); - } - else if (!isReady () && !isConnecting ()) - { - m_pendingVoices.append (m_currentVoiceClipName); - requestChatService (); - } - else if(isConnecting ()) - { - m_pendingVoices.append (m_currentVoiceClipName); - } - m_currentVoiceClipName = QString(); -#endif -} - -void -WlmChatSession::slotSendFile () -{ - qobject_cast < WlmContact * >(members ().first ())->sendFile (); -} - -void -WlmChatSession::slotInviteContact (Kopete::Contact * contact) -{ - // if we have a session, just invite the new contact - if (isReady ()) - { - getChatService ()->inviteUser (contact->contactId ().toLatin1 ().constData ()); - return; - } - // if we are not in a session or connecting, add this contact to be invited later - if (!isReady () && !isConnecting ()) - { - m_pendingInvitations.append (contact->contactId ()); - requestChatService (); - return; - } - // finally if we have a connection in progress, only add this user to be invited later - if (isConnecting ()) - m_pendingInvitations.append (contact->contactId ()); -} - -static void -printGifErrorMessage() -{ -#ifdef HAVE_GIFLIB -#ifdef HAVE_GIF_ERROR_STRING // giflib 4.2.0+ -#if GIFLIB_MAJOR >= 5 - fprintf(stderr, "GIF-LIB error (exact reporting not implemented)\n"); -#else - const char * errorString = GifErrorString(); - if (errorString) - fprintf(stderr, "GIF-LIB error: %s\n", errorString); - else - fprintf(stderr, "GIF-LIB undefined error: %d\n", GifError()); -#endif -#else // older giflib versions, libungif - PrintGifError(); -#endif // HAVE_GIF_ERROR_STRING -#endif // HAVE_GIFLIB -} - -static int -closeGif(GifFileType* file) -{ -#if ((GIFLIB_MAJOR == 5 && GIFLIB_MINOR >= 1) || GIFLIB_MAJOR > 5) - return EGifCloseFile(file, NULL); -#else - return EGifCloseFile(file); -#endif -} - -/* stolen from kpaint write_to_gif() */ -void -WlmChatSession::convertToGif( const QPixmap & ink, QString filename) -{ -#ifdef HAVE_GIFLIB -#if GIFLIB_MAJOR >= 5 -#define FreeMapObject GifFreeMapObject -#define MakeMapObject GifMakeMapObject -#endif - int i, status; - GifFileType *GifFile; - ColorMapObject *screenColourmap; - ColorMapObject *imageColourmap; - QImage img = ink.toImage().convertToFormat(QImage::Format_Indexed8); - - imageColourmap= MakeMapObject(256, NULL); - if (!imageColourmap) { - return; - } - - screenColourmap= MakeMapObject(256, NULL); - if (!screenColourmap) { - return; - } - - for (i= 0; i < 256; i++) { - if (i Colors[i].Red= qRed(img.color(i)); - imageColourmap->Colors[i].Green= qGreen(img.color(i)); - imageColourmap->Colors[i].Blue= qBlue(img.color(i)); - } - else { - imageColourmap->Colors[i].Red= 0; - imageColourmap->Colors[i].Green= 0; - imageColourmap->Colors[i].Blue= 0; - } - } - - for (i= 0; i < 256; i++) { - if (i Colors[i].Red= qRed(img.color(i)); - screenColourmap->Colors[i].Green= qGreen(img.color(i)); - screenColourmap->Colors[i].Blue= qBlue(img.color(i)); - } - else { - screenColourmap->Colors[i].Red= 0; - screenColourmap->Colors[i].Green= 0; - screenColourmap->Colors[i].Blue= 0; - } - } - -#if GIFLIB_MAJOR >= 5 - GifFile= EGifOpenFileName(QFile::encodeName(filename).constData(), 0, NULL); -#else - GifFile= EGifOpenFileName(QFile::encodeName(filename).constData(), 0); -#endif - if (!GifFile) { - FreeMapObject(imageColourmap); - FreeMapObject(screenColourmap); - return; - } - - status= EGifPutScreenDesc(GifFile, - img.width(), - img.height(), - 256, - 0, - screenColourmap); - - if (status != GIF_OK) { - closeGif(GifFile); - return; - } - - status= EGifPutImageDesc(GifFile, - 0, 0, - img.width(), - img.height(), - 0, - imageColourmap); - - if (status != GIF_OK) { - return; - } - - for (i = 0; status && (i < img.height()); i++) { - status= EGifPutLine(GifFile, - img.scanLine(i), - img.width()); - } - - if (status != GIF_OK) { - printGifErrorMessage(); - closeGif(GifFile); - return; - } - - if (closeGif(GifFile) != GIF_OK) { - printGifErrorMessage(); - return; - } - return; -#endif -} - -void -WlmChatSession::slotSendInk ( const QPixmap & ink) -{ - KTemporaryFile inkImage; - inkImage.setPrefix("inkformatgif-"); - inkImage.setSuffix(".gif"); - inkImage.open(); - // if we autoremove the image, it will be deleted before - // khtml have the chance to show it on the screen. - inkImage.setAutoRemove(false); - QString name = inkImage.fileName(); - addFileToRemove(name); - convertToGif(ink, name); - - // encode to base64 and send it to libmsn - QByteArray draw = KCodecs::base64Encode(inkImage.readAll()); - if(!isReady() && !isConnecting()) - { - m_pendingInks << draw; - requestChatService (); - } - else if (isConnecting ()) - m_pendingInks << draw; - else - getChatService ()->sendInk(draw.constData()); - - QString msg=QString ("").arg ( name ); - - Kopete::Message kmsg( myself(), members() ); - kmsg.setHtmlBody( msg ); - kmsg.setDirection( Kopete::Message::Outbound ); - appendMessage ( kmsg ); - - inkImage.deleteLater(); -} - -void -WlmChatSession::slotActionInviteAboutToShow () -{ - // We can't simply insert QAction in this menu bebause we don't know when to delete them. - // items inserted with insert items are automatically deleted when we call clear - - qDeleteAll (m_inviteactions); - m_inviteactions.clear (); - - m_actionInvite->menu ()->clear (); - - QHash < QString, Kopete::Contact * >contactList = account ()->contacts(); - QHash < QString, Kopete::Contact * >::Iterator it, itEnd = - contactList.end (); - for (it = contactList.begin (); it != itEnd; ++it) - { - if (!members ().contains (it.value ()) && it.value ()->isOnline ()) - { - QAction *a = - new Kopete::UI::ContactAction (it.value (), - actionCollection ()); - connect( a, SIGNAL(triggered(Kopete::Contact*,bool)), - this, SLOT(slotInviteContact(Kopete::Contact*)) ); - - m_actionInvite->addAction (a); - m_inviteactions.append (a); - } - } - - // We can't simply insert QAction in this menu bebause we don't know when to delete them. - // items inserted with insert items are automatically deleted when we call clear -/* - m_inviteactions.setAutoDelete(true); - m_inviteactions.clear(); - - m_actionInvite->popupMenu()->clear(); - - QListIterator it( account()->contacts() ); - for( ; it.current(); ++it ) - { - if( !members().contains( it.current() ) && it.current()->isOnline() && it.current() != myself() ) - { - QAction *a=new KopeteContactAction( it.current(), this, - SLOT(slotInviteContact(Kopete::Contact*)), m_actionInvite ); - m_actionInvite->insert( a ); - m_inviteactions.append( a ) ; - } - } -// QAction *b=new QAction( i18n ("Other..."), 0, this, SLOT(slotInviteOtherContact()), m_actionInvite, "actionOther" ); -// m_actionInvite->insert( b ); -// m_inviteactions.append( b ) ; -*/ -} - -void -WlmChatSession::sendNudge () -{ - if (isReady ()) - { - getChatService ()->sendNudge (); - Kopete::Message msg = Kopete::Message (myself (), members ()); - msg.setDirection (Kopete::Message::Outbound); - msg.setType (Kopete::Message::TypeAction); - msg.setPlainBody (i18n ("has sent a nudge")); - - appendMessage (msg); - return; - } - - if (!isConnecting ()) - { - setSendNudge (true); - requestChatService (); - } -} - -WlmChatSession::~WlmChatSession () -{ - if (!account ()) - return; - - WlmAccount *acc = qobject_cast < WlmAccount * >(account ()); - - if (!acc) - return; - - WlmChatManager *manager = acc->chatManager (); - - if (manager && getChatService ()) - manager->chatSessions.remove (getChatService ()); - - stopSendKeepAlive(); - - if (isReady () && getChatService ()) - { - delete getChatService (); - setChatService(NULL); - } - for (int i = 0; i < m_filesToRemove.size(); ++i) - QFile::remove(m_filesToRemove.at(i)); -} - -void -WlmChatSession::addFileToRemove (QString path) -{ - m_filesToRemove << path; -} - -bool -WlmChatSession::isConnecting() -{ - if(!getChatService ()) - return false; - - if(getChatService()->connectionState () != - MSN::SwitchboardServerConnection::SB_READY && - getChatService ()->connectionState () != - MSN::SwitchboardServerConnection::SB_DISCONNECTED) - return true; - return false; -} - -void -WlmChatSession::setChatService (MSN::SwitchboardServerConnection * conn) -{ - m_chatService = conn; - if (!getChatService()) - { - setReady (false); - return; - } - if (getChatService () - && getChatService ()->connectionState () == - MSN::SwitchboardServerConnection::SB_READY) - { - setReady (true); - } -} - -MSN::Message WlmChatSession::parseMessage(Kopete::Message & msg) -{ - // send the message and wait for the ACK - int fontEffects = 0; - MSN::Message mmsg(msg.plainBody().toUtf8().constData()); - - // FIXME: Can we add FontFamily FF_DONTCARE ? - if (msg.format() == Qt::RichText) - { - mmsg.setFontName(msg.font().family().toLatin1().constData()); - if (msg.font().bold()) - fontEffects |= MSN::Message::BOLD_FONT; - if (msg.font().italic()) - fontEffects |= MSN::Message::ITALIC_FONT; - if (msg.font().underline()) - fontEffects |= MSN::Message::UNDERLINE_FONT; - if (msg.font().strikeOut()) - fontEffects |= MSN::Message::STRIKETHROUGH_FONT; - - mmsg.setFontEffects(fontEffects); - QColor color = msg.foregroundColor(); - mmsg.setColor(color.red(), color.green(), color.blue()); - } - - WlmAccount *acc = qobject_cast < WlmAccount * >(account ()); - if(!acc) - return mmsg; - - if(!acc->doNotSendEmoticons()) - { - // stolen from msn plugin - const QHash emap = Kopete::Emoticons::self()->theme().emoticonsMap(); - - // Check the list for any custom emoticons - for (QHash::const_iterator itr = emap.begin(); itr != emap.end(); ++itr) - { - for (QStringList::const_iterator itr2 = itr.value().constBegin(); itr2 != itr.value().constEnd(); ++itr2) - { - if (msg.plainBody().contains(*itr2)) - { - getChatService()->sendEmoticon((*itr2).toUtf8().constData(), QFile::encodeName(itr.key()).constData()); - } - } - } - } - return mmsg; -} - -void -WlmChatSession::setReady (bool value) -{ - Q_UNUSED( value ); - - if (isReady ()) - { - m_tries = 0; - if (isDownloadDisplayPicture ()) - { - setDownloadDisplayPicture (false); - requestDisplayPicture (); - } - if (isSendNudge ()) - { - sendNudge (); - setSendNudge (false); - } - - // invite pending contacts - QLinkedList < QString >::iterator it; - for (it = m_pendingInvitations.begin (); - it != m_pendingInvitations.end (); ++it) - { - WlmContact * c = qobject_cast(account ()->contacts().value(*it)); - if (c) - slotInviteContact (c); - } - m_pendingInvitations.clear (); - - // send queued messages first - QLinkedList < Kopete::Message >::iterator it2; - for (it2 = m_messagesQueue.begin (); it2 != m_messagesQueue.end (); - ++it2) - { - MSN::Message mmsg = parseMessage(*it2); - - int trid = getChatService ()->sendMessage (&mmsg); - - m_messagesSentQueue[trid] = (*it2); - } - m_messagesQueue.clear (); - - // send pending files - QLinkedList < QString >::iterator it3; - for (it3 = m_pendingFiles.begin (); it3 != m_pendingFiles.end (); - ++it3) - { - sendFile ((*it3), 0); - } - m_pendingFiles.clear (); - - QLinkedList < QByteArray >::iterator it4; - for (it4 = m_pendingInks.begin (); it4 != m_pendingInks.end (); ++it4) - { - getChatService ()->sendInk((*it4).constData()); - } - m_pendingInks.clear (); - -#ifdef HAVE_MEDIASTREAMER - QLinkedList < QString >::iterator it5; - for (it5 = m_pendingVoices.begin (); it5 != m_pendingVoices.end (); - ++it5) - { - std::string obj; - - // keep a local file without the conversion to siren. - KTemporaryFile voiceClip; - voiceClip.setPrefix("kopete_voiceClip-"); - voiceClip.setSuffix(".wav"); - voiceClip.setAutoRemove(false); - voiceClip.open(); - addFileToRemove(voiceClip.fileName()); - QString localVoice = voiceClip.fileName(); - voiceClip.close(); - // copy will not overwrite the file, so we need to delete it - voiceClip.remove(); - QFile::copy((*it5), localVoice); - - QByteArray localFileName = QFile::encodeName( (*it5) ); - getChatService ()->myNotificationServer()->msnobj.addMSNObject(localFileName.constData (),11); - getChatService ()->myNotificationServer()->msnobj.getMSNObjectXML(localFileName.constData (), 11, obj); - getChatService ()->sendVoiceClip(obj); - - Kopete::Message kmsg( myself(), members() ); - kmsg.setType(Kopete::Message::TypeVoiceClipRequest); - kmsg.setDirection( Kopete::Message::Outbound ); - kmsg.setFileName(localVoice); - appendMessage ( kmsg ); - } - m_pendingVoices.clear (); - m_currentVoiceClipName = QString(); -#endif - } - else - { - stopSendKeepAlive(); - } -} - -bool -WlmChatSession::requestChatService () -{ - // check if the other contact is offline - if (members ().count () > 0 && - members ().first ()->onlineStatus () == - WlmProtocol::protocol ()->wlmOffline) - return false; - - if (!isReady () && account ()->isConnected () && !isConnecting () && !m_chatServiceRequested) - { - const std::string rcpt_ = members().first()->contactId().toLatin1().constData(); - const std::string msg_ = ""; - const std::pair *ctx = new std::pair(rcpt_, msg_); - // request a new switchboard connection - static_cast (account ())->server ()->cb.mainConnection->requestSwitchboardConnection (ctx); - QTimer::singleShot (30 * 1000, this, SLOT (switchboardConnectionTimeout())); - // if the user attempts to send more than one message a new sb - // is requested every time unless we received one in the mean - // time and the other client has already joined - m_chatServiceRequested = true; - return true; - } - // probably we are about to connect - return true; -} - -void -WlmChatSession::switchboardConnectionTimeout () -{ - if (!isReady ()) - { - // allow a new chat service request - m_chatServiceRequested = false; - // try 3 times - if (m_tries < 3) - { - m_tries++; - requestChatService (); - return; - } - Kopete::Utils::notifyCannotConnect(account(), "Could not open switchboard connection"); - - QMap::const_iterator i; - for (i = m_messagesSentQueue.constBegin(); i != m_messagesSentQueue.constEnd(); ++i) - this->receivedMessageState(i->id(), Kopete::Message::StateError ); - - messageSucceeded (); - } -} - -void -WlmChatSession::messageTimeout () -{ - int trid = m_messagesTimeoutQueue.takeFirst(); - if(m_messagesSentQueue.contains(trid)) - this->receivedMessageState(m_messagesSentQueue[trid].id(), Kopete::Message::StateError ); -} - -void -WlmChatSession::slotMessageSent (Kopete::Message & msg, - Kopete::ChatSession * chat) -{ - Q_UNUSED( chat ); - if (!account ()->isConnected ()) - { - KMessageBox::queuedMessageBox (Kopete::UI::Global::mainWidget (), - KMessageBox::Information, - "You cannot send a message while in offline status", - "Information"); - messageSucceeded (); - return; - } - - if (isReady ()) - { - MSN::Message mmsg = parseMessage(msg); - - int trid = getChatService ()->sendMessage (&mmsg); - - // Show the message we just sent in the chat window as sending - msg.setState( Kopete::Message::StateSending ); - this->appendMessage(msg); - this->messageSucceeded(); - - m_messagesSentQueue[trid] = msg; - m_messagesTimeoutQueue.append(trid); - QTimer::singleShot (60 * 1000, this, - SLOT (messageTimeout())); - return; - } - - if (!isConnecting () && !isReady ()) - { - // request switchboard - if (!requestChatService ()) - { - MSN::Soap::OIM oim; - oim.myFname = myself ()->displayName ().toUtf8().constData(); - oim.toUsername = members ().first ()->contactId ().toLatin1 ().constData(); - oim.message = msg.plainBody ().toUtf8 ().constData(); - oim.myUsername = myself ()->contactId ().toLatin1 ().constData(); - oim.id = m_oimid++; - - static_cast (account ())->server ()->cb.mainConnection->send_oim (oim); - appendMessage (msg); - messageSucceeded (); - return; - } - - // Show the message we just sent in the chat window as sending - msg.setState( Kopete::Message::StateSending ); - this->appendMessage(msg); - this->messageSucceeded(); - - // put the message in a queue - m_messagesQueue.append (msg); - return; - } - - if (isConnecting ()) - { - // Show the message we just sent in the chat window as sending - msg.setState( Kopete::Message::StateSending ); - this->appendMessage(msg); - this->messageSucceeded(); - - // put the message in the queue, we are trying to connect to the - // switchboard server - m_messagesQueue.append (msg); - return; - } - -} -bool -WlmChatSession::isReady () -{ - if(!getChatService ()) - return false; - - // check in libmsn if we are really ready - if(getChatService ()->connectionState () == - MSN::SwitchboardServerConnection::SB_READY) - return true; - else - return false; -} - -void -WlmChatSession::sendTypingMsg (bool istyping) -{ - if (!istyping || isConnecting ()) - return; - - // do not send notification if we - // are alone in the session - if (!isReady ()) - return; - - getChatService ()->sendTypingNotification (); - - startSendKeepAlive(); -} - -void -WlmChatSession::messageSentACK (unsigned int trID) -{ - this->receivedMessageState(m_messagesSentQueue[trID].id(), Kopete::Message::StateSent ); - - m_messagesSentQueue.remove (trID); - // remove the blinking icon when there are no messages - // waiting for delivery - if (m_messagesSentQueue.empty ()) - messageSucceeded (); -} - -void -WlmChatSession::startSendKeepAlive() -{ - // send keepalive each 50 seconds. - if(m_keepalivetimer && isReady()) - m_keepalivetimer->start (50 * 1000); -} - -void -WlmChatSession::stopSendKeepAlive() -{ - if(m_keepalivetimer) - m_keepalivetimer->stop (); -} - -void -WlmChatSession::receivedNudge (QString passport) -{ - WlmContact * c = qobject_cast(account ()->contacts().value(passport)); - if (!c) - c = qobject_cast(members ().first ()); - - Kopete::Message msg = Kopete::Message (c, myself ()); - msg.setPlainBody (i18n ("has sent you a nudge")); - msg.setDirection (Kopete::Message::Inbound); - msg.setType (Kopete::Message::TypeAction); - appendMessage (msg); - emitNudgeNotification (); // notifies with system message close to tray icon - startSendKeepAlive(); - -} - -void -WlmChatSession::requestDisplayPicture () -{ - // only request picture in a 2 session people only - if (members ().count () != 1) - return; - - WlmContact *contact = qobject_cast < WlmContact * >(members ().first ()); - - if (!contact) - return; - - if (contact->getMsnObj ().isEmpty () || contact->getMsnObj () == "0") - return; - - QString msnobj = contact->getMsnObj (); - - QDomDocument xmlobj; - xmlobj.setContent (msnobj); - - // track display pictures by SHA1D field - QString SHA1D = xmlobj.documentElement ().attribute ("SHA1D"); - - if (SHA1D.isEmpty ()) - return; - - QString currentSHA1D = contact->property(WlmProtocol::protocol()->displayPhotoSHA1).value().toString(); - QString photoPath = contact->property(Kopete::Global::Properties::self()->photo().key()).value().toString(); - if (SHA1D == currentSHA1D && QFileInfo(photoPath).size() > 0) - return; - - // request switchboard connection - // and ask for the display picture - if (!isReady () && !isConnecting ()) - { - requestChatService (); - setDownloadDisplayPicture (true); - return; // TODO - schedule this action - } - if (isReady ()) - { - QString newlocation = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1Char('/') + "wlmpictures/" + QString(SHA1D.replace ('/', '_')); - getChatService()->requestDisplayPicture(generateSessionID(), QFile::encodeName(newlocation).constData(), - contact->getMsnObj().toUtf8().constData()); - setDownloadDisplayPicture (false); - } -} - diff --git a/protocols/wlm/wlmchatsessioninkaction.h b/protocols/wlm/wlmchatsessioninkaction.h deleted file mode 100644 --- a/protocols/wlm/wlmchatsessioninkaction.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - wlmchatsessioninkaction.h - Kopete Wlm Protocol - - Copyright (c) 2009 by Tiago Salem Herrmann - Kopete (c) 2002-2003 by the Kopete developers - - ************************************************************************* - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the 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 WLMCHATSESSIONINKACTION_H -#define WLMCHATSESSIONINKACTION_H - -#include -#include -#include - -class WlmChatSessionInkAction : public KActionMenu -{ - Q_OBJECT - public: - WlmChatSessionInkAction(QObject * parent = 0); - virtual ~WlmChatSessionInkAction(); - signals: - void sendInk( const QPixmap & ink ); - private: - class WlmChatSessionInkActionPrivate; - WlmChatSessionInkActionPrivate *d; - public slots: - void raiseInkWindow(); -}; -#endif diff --git a/protocols/wlm/wlmchatsessioninkaction.cpp b/protocols/wlm/wlmchatsessioninkaction.cpp deleted file mode 100644 --- a/protocols/wlm/wlmchatsessioninkaction.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* - wlmchatsessioninkaction.cpp - Kopete Wlm Protocol - - Copyright (c) 2009 by Tiago Salem Herrmann - Kopete (c) 2002-2003 by the Kopete developers - - ************************************************************************* - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the 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 "wlmchatsessioninkaction.h" - -#include - -#include -#include -#include - -#include "wlmchatsessioninkarea.h" -#include "ui_wlmchatsessioninkpopup.h" - -class WlmChatSessionInkAction::WlmChatSessionInkActionPrivate -{ -public: - WlmChatSessionInkActionPrivate() - { - m_popup = new QMenu(0L); - m_sessionInk = new QWidget; - Ui::InkWindow ui; - ui.setupUi(m_sessionInk); - m_sessionInk->setObjectName( QLatin1String("WlmChatSessionInkActionPrivate::m_sessionInk") ); - QWidgetAction *act = new QWidgetAction(m_popup); - act->setDefaultWidget(m_sessionInk); - m_popup->addAction(act); - } - - ~WlmChatSessionInkActionPrivate() - { - delete m_popup; - m_popup = 0; - delete m_sessionInk; - m_sessionInk = 0; - } - - QMenu *m_popup; - QWidget *m_sessionInk; -}; - -WlmChatSessionInkAction::WlmChatSessionInkAction( QObject* parent ) - : KActionMenu( i18n( "Send Ink" ), parent ) -{ - d = new WlmChatSessionInkActionPrivate; - setMenu( d->m_popup ); - - setIcon( QIcon::fromTheme(QStringLiteral("application-pgp-signature")) ); - QList sessionInkList = d->m_sessionInk->findChildren(); - WlmChatSessionInkArea *inkArea = sessionInkList.first(); - if(inkArea) - { - connect( inkArea, SIGNAL(sendInk(QPixmap)), - this, SIGNAL(sendInk(QPixmap)) ); - connect( inkArea, SIGNAL(raiseInkWindow()), - this, SLOT(raiseInkWindow()) ); - } -} - -void WlmChatSessionInkAction::raiseInkWindow() -{ - menu()->exec(); -} - -WlmChatSessionInkAction::~WlmChatSessionInkAction() -{ - delete d; - d = NULL; -} - diff --git a/protocols/wlm/wlmchatsessioninkarea.h b/protocols/wlm/wlmchatsessioninkarea.h deleted file mode 100644 --- a/protocols/wlm/wlmchatsessioninkarea.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - wlmchatsessioninkarea.h - Kopete Wlm Protocol - - Copyright (c) 2009 by Tiago Salem Herrmann - Kopete (c) 2002-2003 by the Kopete developers - - ************************************************************************* - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the 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 WLMCHATSESSIONINKAREA_H -#define WLMCHATSESSIONINKAREA_H - -#include -#include -#include -#include - -class WlmChatSessionInkArea : public QWidget -{ - Q_OBJECT - public: - WlmChatSessionInkArea(QWidget * parent = 0); - virtual ~WlmChatSessionInkArea(); - private: - void paintEvent(QPaintEvent * ); - protected: - void mousePressEvent( QMouseEvent *e ); - void mouseReleaseEvent( QMouseEvent *e ); - void mouseMoveEvent( QMouseEvent *e ); - QPen m_pen; - QPolygon m_polyline; - QPixmap m_buffer; - - bool mousePressed; -signals: - void sendInk( const QPixmap &); - void raiseInkWindow(); - void closeWindow(); -public slots: - void slotChangePenSize(int size); - void slotClear(); - void slotSend(); - void slotColor(); -}; -#endif - diff --git a/protocols/wlm/wlmchatsessioninkarea.cpp b/protocols/wlm/wlmchatsessioninkarea.cpp deleted file mode 100644 --- a/protocols/wlm/wlmchatsessioninkarea.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/* - wlmchatsessioninkarea.cpp - Kopete Wlm Protocol - - Copyright (c) 2009 by Tiago Salem Herrmann - Kopete (c) 2002-2003 by the Kopete developers - - ************************************************************************* - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the 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 "wlmchatsessioninkarea.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -WlmChatSessionInkArea::WlmChatSessionInkArea(QWidget * parent) -: QWidget(parent), - m_pen(Qt::black, 3), - m_buffer(350, 100), - mousePressed( FALSE ) -{ - setFixedSize(350,100); - m_buffer.fill(Qt::white); -} - -void WlmChatSessionInkArea::slotChangePenSize(int size) -{ - m_pen.setWidth(size); -} - -void WlmChatSessionInkArea::slotClear() -{ - m_polyline.clear(); - m_buffer.fill(Qt::white); - update(); -} - -void WlmChatSessionInkArea::slotColor() -{ - m_pen.setColor(QColorDialog::getColor(m_pen.color(), this, i18n("Select the pen's color"))); - emit raiseInkWindow(); -} - -void WlmChatSessionInkArea::slotSend() -{ - QRect r = QRegion(QBitmap::fromImage(m_buffer.toImage())).boundingRect(); - QPixmap buffer_tmp = m_buffer.copy(r); - emit sendInk(buffer_tmp); - slotClear(); - if ( isVisible() && parentWidget() && - parentWidget()->inherits("QMenu") ) - { - parentWidget()->close(); - } -} - -void WlmChatSessionInkArea::paintEvent(QPaintEvent *) -{ - QPainter painter(&m_buffer); - painter.setPen( m_pen ); - painter.drawPolyline(m_polyline); - - QPainter paint(this); - paint.drawPixmap(0, 0, 350, 100, m_buffer); -} - -void WlmChatSessionInkArea::mousePressEvent( QMouseEvent *e ) -{ - mousePressed = TRUE; - m_polyline << e->pos(); - update(); -} - -void WlmChatSessionInkArea::mouseReleaseEvent( QMouseEvent * ) -{ - mousePressed = FALSE; - m_polyline.clear(); - update(); -} - -void WlmChatSessionInkArea::mouseMoveEvent( QMouseEvent *e ) -{ - if ( mousePressed ) { - m_polyline << e->pos(); - update(); - } -} - -WlmChatSessionInkArea::~WlmChatSessionInkArea() -{ -} - diff --git a/protocols/wlm/wlmchatui.rc b/protocols/wlm/wlmchatui.rc deleted file mode 100644 --- a/protocols/wlm/wlmchatui.rc +++ /dev/null @@ -1,17 +0,0 @@ - - - - - &Chat - - - - - - - - - - - - diff --git a/protocols/wlm/wlmcontact.h b/protocols/wlm/wlmcontact.h deleted file mode 100644 --- a/protocols/wlm/wlmcontact.h +++ /dev/null @@ -1,141 +0,0 @@ -/* - wlmcontact.h - Kopete Wlm Protocol - - Copyright (c) 2008 by Tiago Salem Herrmann - Kopete (c) 2002-2003 by the Kopete developers - - ************************************************************************* - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the 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 WLMCONTACT_H -#define WLMCONTACT_H - -#include -#include -#include -#include -#include "kopetecontact.h" -#include "kopetemessage.h" - -#include "wlmchatsession.h" - -class QAction; -class KToggleAction; -namespace Kopete -{ - class Account; -} -namespace Kopete -{ - class ChatSession; -} -namespace Kopete -{ - class MetaContact; -} - -class WlmAccount; - -/** -@author Will Stephenson -*/ -class WlmContact : public Kopete::Contact -{ - Q_OBJECT -public: - WlmContact (Kopete::Account * _account, const QString & uniqueName, - const QString & contactSerial, Kopete::MetaContact * parent); - - ~WlmContact (); - - virtual bool isReachable (); - /** - * Serialize the contact's data into a key-value map - * suitable for writing to a file - */ - virtual void serialize (QMap < QString, QString > &serializedData, - QMap < QString, QString > &addressBookData); - /** - * Return the actions for this contact - */ - virtual QList *customContextMenuActions (); - using Kopete::Contact::customContextMenuActions; - /** - * Returns a Kopete::ChatSession associated with this contact - */ - virtual Kopete::ChatSession * manager (CanCreateFlags canCreate = CannotCreate); - - void setContactSerial (QString contactSerial) { m_contactSerial = contactSerial; } - - QString contactSerial () const { return m_contactSerial; } - Kopete::Group* currentGroup () const { return m_currentGroup; } - void setCurrentGroup (Kopete::Group *currentGroup) { m_currentGroup = currentGroup; } - - void setOnlineStatus(const Kopete::OnlineStatus&); - -public slots: - /** - * Transmits an outgoing message to the server - * Called when the chat window send button has been pressed - * (in response to the relevant Kopete::ChatSession signal) - */ - void sendMessage (Kopete::Message & message); - /** - * Called when an incoming message arrived - * This displays it in the chatwindow - */ - void receivedMessage (const QString & message); - - QString getMsnObj () const { return m_msnobj; } - - void setMsnObj (QString msnobj) { m_msnobj = msnobj; } - - virtual void slotUserInfo(); - virtual void deleteContact (); - - virtual void sendFile (const KUrl & sourceURL = KUrl (), - const QString & fileName = QString(), uint fileSize = 0L); - - void blockContact ( bool block ); - void slotShowProfile(); - void slotUpdateDisplayPicture(); - virtual void sync( unsigned int flags ); - bool isDisabled() const { return m_disabled; } - void setDisabled( bool disabled, bool updateServer ); - void slotDontShowEmoticons(bool block); - bool dontShowEmoticons(); - -protected slots: - /** - * Show the settings dialog - */ - void showContactSettings (); - /** - * Notify the contact that its current Kopete::ChatSession was - * destroyed - probably by the chatwindow being closed - */ - void slotChatSessionDestroyed (); - -protected: - WlmChatSession * m_msgManager; - WlmAccount * m_account; - KToggleAction* m_actionBlockContact; - KToggleAction* m_actionDontShowEmoticons; - QAction * m_actionShowProfile; - QAction * m_actionUpdateDisplayPicture; - QAction * m_actionPrefs; - QString m_msnobj; - QString m_contactSerial; - Kopete::Group *m_currentGroup; - bool m_disabled; - bool m_dontShowEmoticons; -}; - -#endif diff --git a/protocols/wlm/wlmcontact.cpp b/protocols/wlm/wlmcontact.cpp deleted file mode 100644 --- a/protocols/wlm/wlmcontact.cpp +++ /dev/null @@ -1,491 +0,0 @@ -/* - wlmcontact.cpp - Kopete Wlm Protocol - - Copyright (c) 2008 by Tiago Salem Herrmann - Kopete (c) 2002-2003 by the Kopete developers - - ************************************************************************* - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the 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 "wlmcontact.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "kopeteaccount.h" -#include "kopetechatsessionmanager.h" -#include "kopetemetacontact.h" -#include "kopeteuiglobal.h" -#include "kopetegroup.h" - -#include "ui_wlminfo.h" -#include "wlmaccount.h" -#include "wlmprotocol.h" - -WlmContact::WlmContact (Kopete::Account * _account, - const QString & uniqueName, - const QString & contactSerial, - Kopete::MetaContact * parent): -Kopete::Contact (_account, uniqueName, parent) -{ - kDebug (14210) << k_funcinfo << " uniqueName: " << uniqueName; - m_msgManager = 0L; - m_account = qobject_cast(account()); - setFileCapable (true); - setOnlineStatus (WlmProtocol::protocol ()->wlmOffline); - m_contactSerial = contactSerial; - m_disabled = false; - m_dontShowEmoticons = false; - - if ( metaContact() ) - m_currentGroup = metaContact()->groups().first(); - - m_actionBlockContact = new KToggleAction(QIcon::fromTheme(QStringLiteral("wlm_blocked")), i18n("Block Contact"), this ); - QObject::connect( m_actionBlockContact, SIGNAL(triggered(bool)), this, SLOT(blockContact(bool)) ); - - m_actionShowProfile = new QAction(i18n("Show Profile"), this); - QObject::connect(m_actionShowProfile, SIGNAL(triggered(bool)), this, SLOT(slotShowProfile())); - - m_actionUpdateDisplayPicture = new QAction(i18n("Update Photo"), this); - QObject::connect(m_actionUpdateDisplayPicture, SIGNAL(triggered(bool)), this, SLOT(slotUpdateDisplayPicture())); - - m_actionDontShowEmoticons = new KToggleAction (QIcon::fromTheme(QStringLiteral("wlm_fakefriend")), - i18n ("&Block custom emoticons"), this); - QObject::connect (m_actionDontShowEmoticons, SIGNAL(triggered(bool)), this, SLOT(slotDontShowEmoticons(bool))); -} - -void WlmContact::slotDontShowEmoticons(bool block) -{ - m_actionDontShowEmoticons->setChecked(block); - m_dontShowEmoticons = block; -} - -bool WlmContact::dontShowEmoticons() -{ - return m_dontShowEmoticons; -} - -void WlmContact::setDisabled(bool disabled, bool updateServer) -{ - WlmAccount* acc = qobject_cast(account()); - if(!acc) - return; - - if(disabled) - { - // already disabled - if(isDisabled()) - return; - - m_disabled = true; - - if(!metaContact()) - return; - - metaContact()->setTemporary(m_disabled); - - setOnlineStatus(WlmProtocol::protocol()->wlmOffline); - - if(updateServer && account ()->isConnected ()) - acc->server ()->mainConnection->disableContactOnAddressBook( m_contactSerial.toLatin1().constData(), contactId ().toLatin1().constData() ); - } - else - { - // already enabled - if(!isDisabled()) - return; - - m_disabled = false; - - if(!metaContact()) - return; - - metaContact()->setTemporary(m_disabled); - setOnlineStatus(WlmProtocol::protocol()->wlmOffline); - - if(updateServer && account ()->isConnected ()) - acc->server()->mainConnection->enableContactOnAddressBook(m_contactSerial.toLatin1().constData(), contactId().toLatin1().constData()); - } -} - -WlmContact::~WlmContact () -{ -} - -bool -WlmContact::isReachable () -{ - // always true, as we can send offline messages - return true; -} - -void -WlmContact::slotShowProfile() -{ - KToolInvocation::invokeBrowser(QString::fromLatin1("http://members.msn.com/default.msnw?mem=") + contactId()) ; -} - -void -WlmContact::slotUpdateDisplayPicture() -{ - if(!account()->isConnected()) - return; - - WlmAccount* acc = qobject_cast(account()); - if(!acc) - return; - - if ((onlineStatus() != WlmProtocol::protocol ()->wlmOffline) - && (onlineStatus() != WlmProtocol::protocol ()->wlmInvisible) - && (onlineStatus() != WlmProtocol::protocol ()->wlmUnknown)) - { - acc->chatManager ()->requestDisplayPicture (contactId()); - } - -} - -void -WlmContact::sendFile (const KUrl & sourceURL, const QString & fileName, - uint fileSize) -{ - Q_UNUSED( fileName ); - Q_UNUSED( fileSize ); - - QString filePath; - - if (!sourceURL.isValid ()) - filePath = - KFileDialog::getOpenFileName (KUrl (), "*", 0l, - i18n ("Kopete File Transfer")); - else - filePath = sourceURL.path (KUrl::RemoveTrailingSlash); - - if (!filePath.isEmpty ()) - { - quint32 fileSize = QFileInfo (filePath).size (); - //Send the file - static_cast - (manager (Kopete::Contact::CanCreate))->sendFile (filePath, - fileSize); - } -} - -void -WlmContact::serialize (QMap < QString, QString > &serializedData, - QMap < QString, QString > & /* addressBookData */ ) -{ - serializedData["displayPicture"] = - property (Kopete::Global::Properties::self ()->photo ()).value (). - toString (); - serializedData["contactSerial"] = m_contactSerial; - serializedData["dontShowEmoticons"] = m_dontShowEmoticons ? "true" : "false"; -} - -Kopete::ChatSession * - WlmContact::manager (Kopete::Contact::CanCreateFlags canCreate) -{ - Kopete::ContactPtrList chatmembers; - chatmembers.append (this); - - Kopete::ChatSession * _manager = - Kopete::ChatSessionManager::self ()-> - findChatSession (account ()->myself (), chatmembers, protocol ()); - WlmChatSession *manager = qobject_cast (_manager); - if (!manager && canCreate == Kopete::Contact::CanCreate) - { - manager = - new WlmChatSession (protocol (), account ()->myself (), - chatmembers); - } - return manager; -} - -QList < QAction * >* WlmContact::customContextMenuActions () //OBSOLETE -{ - QList *actions = new QList(); - - m_actionBlockContact->setEnabled(m_account->isConnected()); - m_actionBlockContact->setChecked(m_account->isContactBlocked(contactId())); - actions->append(m_actionBlockContact); - actions->append(m_actionShowProfile); - actions->append(m_actionUpdateDisplayPicture); - actions->append(m_actionDontShowEmoticons); - - // temporary action collection, used to apply Kiosk policy to the actions - KActionCollection tempCollection((QObject*)0); - tempCollection.addAction(QLatin1String("contactBlock"), m_actionBlockContact); - tempCollection.addAction(QLatin1String("contactViewProfile"), m_actionShowProfile); - tempCollection.addAction(QLatin1String("updateDisplayPicture"), m_actionUpdateDisplayPicture); - tempCollection.addAction(QLatin1String("dontShowEmoticons"), m_actionDontShowEmoticons); - - return actions; -} - -void WlmContact::sync(unsigned int flags) -{ - if (!account ()->isConnected ()) - return; - /* - * If the contact has changed groups, then we update the server. - */ - if( !metaContact() ) - return; - - // Don't add the contact if it's myself. - if(contactId() == account()->accountId()) - return; - - if ( (flags & Kopete::Contact::MovedBetweenGroup) == Kopete::Contact::MovedBetweenGroup ) - { - Kopete::Group* newGroup = metaContact()->groups().first(); - WlmAccount* acc = qobject_cast(account()); - if(!acc) - return; - - // if this contact is not in the contact list, add it - if(!acc->isOnServerSideList(contactId())) - { - acc->createContact(contactId(), metaContact()); - m_currentGroup = newGroup; - return; - } - - if(isDisabled()) - { - // enable this contact and update on server side - setDisabled(false,true); - } - - if(newGroup == m_currentGroup) - return; - - if(newGroup == Kopete::Group::topLevel()) - { - acc->server ()->mainConnection->removeFromGroup ( - acc->groupToGroupId().value(m_currentGroup->displayName()).toLatin1().constData(), - m_contactSerial.toLatin1().constData ()); - m_currentGroup = newGroup; - return; - } - - // if the group don't exist on server side, we create it - if(!acc->groupToGroupId().contains(newGroup->displayName())) - { - acc->server ()->mainConnection->addGroup(newGroup->displayName().toUtf8().constData()); - return; - } - - // if we have both groups on server side, just move this contact - if(acc->groupToGroupId().contains(newGroup->displayName()) - && acc->groupToGroupId().contains(m_currentGroup->displayName())) - { - acc->server ()->mainConnection->removeFromGroup ( - acc->groupToGroupId().value(m_currentGroup->displayName()).toLatin1().constData(), - m_contactSerial.toLatin1().constData ()); - acc->server ()->mainConnection->addToGroup ( - acc->groupToGroupId().value(newGroup->displayName()).toLatin1().constData(), - m_contactSerial.toLatin1().constData ()); - m_currentGroup = newGroup; - return; - } - if(m_currentGroup == Kopete::Group::topLevel() && - acc->groupToGroupId().contains(newGroup->displayName())) - { - acc->server ()->mainConnection->addToGroup ( - acc->groupToGroupId().value(newGroup->displayName()).toLatin1().constData(), - m_contactSerial.toLatin1().constData ()); - m_currentGroup = newGroup; - return; - } - } -} - -void WlmContact::blockContact(bool block) -{ - if (!m_account->isConnected()) - return; - - m_account->blockContact(contactId(), block); -} - -void WlmContact::slotUserInfo() -{ - QPointer infoDialog = new KDialog; - infoDialog->setButtons( KDialog::Close); - infoDialog->setDefaultButton(KDialog::Close); - const QString name = displayName(); - const QString personalMessage = statusMessage().message(); - Ui::WLMInfo info; - info.setupUi(infoDialog->mainWidget()); - info.m_id->setText(contactId()); - info.m_displayName->setText(name); - info.m_personalMessage->setText(personalMessage); -// info.m_phh->setText(m_phoneHome); //TODO enable and fill -// info.m_phw->setText(m_phoneWork); -// info.m_phm->setText(m_phoneMobile); -// info.m_reversed->setChecked(m_reversed); - -// connect( info.m_reversed, SIGNAL(toggled(bool)) , this, SLOT(slotUserInfoDialogReversedToggled())); - - info.groupBox->setVisible(false); - info.m_reversed->setVisible(false); - - infoDialog->setCaption(name); - infoDialog->exec(); - delete infoDialog; -} - -void -WlmContact::showContactSettings () -{ - //WlmContactSettings* p = new WlmContactSettings( this ); - //p->show(); -} - -void -WlmContact::sendMessage (Kopete::Message & message) -{ - kDebug (14210) << k_funcinfo; - // give it back to the manager to display - manager ()->appendMessage (message); - // tell the manager it was sent successfully - manager ()->messageSucceeded (); -} - -void -WlmContact::deleteContact () -{ - if (account ()->isConnected ()) - { - qobject_cast (account ())->server ()->mainConnection-> - delFromAddressBook (m_contactSerial.toLatin1 ().constData (), contactId ().toLatin1 ().constData ()); - deleteLater (); - } - else - { - KMessageBox::error (Kopete::UI::Global::mainWidget (), - i18n - ("You need to go online to remove a contact from your contact list. This contact will appear again when you reconnect."), - i18n ("WLM Plugin")); - } -} - -void -WlmContact::receivedMessage (const QString & message) -{ - // Create a Kopete::Message - Kopete::ContactPtrList contactList; - account (); - contactList.append (account ()->myself ()); - Kopete::Message newMessage (this, contactList); - newMessage.setPlainBody (message); - newMessage.setDirection (Kopete::Message::Inbound); - - // Add it to the manager - manager ()->appendMessage (newMessage); -} - -void -WlmContact::slotChatSessionDestroyed () -{ - //FIXME: the chat window was closed? Take appropriate steps. - m_msgManager = 0L; -} - -void -WlmContact::setOnlineStatus(const Kopete::OnlineStatus& status) -{ -#if 0 - bool isBlocked = qobject_cast (account())->isOnBlockList(contactId()); - bool isOnForwardList = qobject_cast (account())->isOnServerSideList(contactId()); - bool isOnReverseList = qobject_cast (account())->isOnReverseList(contactId()); - - // if this contact is blocked, and currently has a regular status, - // create a custom status and add wlm_blocked to ovelayIcons - if(isBlocked || (isOnForwardList && !isOnReverseList)) - { - QStringList overelayIconsList; - QString reason; - if(isOnForwardList && !isOnReverseList) - { - overelayIconsList << "wlm_fakefriend"; - reason = i18n("This contact does not have you in his/her list"); - } - - if(isBlocked) - { - overelayIconsList << "wlm_blocked"; - if(reason.isEmpty()) - reason = i18n("This contact is blocked"); - else - reason = i18n("This contact does not have you in his/her list and is blocked"); - } - // set the new status - Kopete::Contact::setOnlineStatus( - Kopete::OnlineStatus(status.status() , - (status.weight()==0) ? 0 : (status.weight() -1), - protocol(), - status.internalStatus()+15, - status.overlayIcons() + overelayIconsList, - reason ) ); - return; - } - - if (status.internalStatus() >= 15) - { - // if this contact was previously blocked, set a regular status again - switch(status.internalStatus()-15) - { - case 1: - Kopete::Contact::setOnlineStatus(WlmProtocol::protocol()->wlmOnline); - break; - case 2: - Kopete::Contact::setOnlineStatus(WlmProtocol::protocol()->wlmAway); - break; - case 3: - Kopete::Contact::setOnlineStatus(WlmProtocol::protocol()->wlmBusy); - break; - case 4: - Kopete::Contact::setOnlineStatus(WlmProtocol::protocol()->wlmBeRightBack); - break; - case 5: - Kopete::Contact::setOnlineStatus(WlmProtocol::protocol()->wlmOnThePhone); - break; - case 6: - Kopete::Contact::setOnlineStatus(WlmProtocol::protocol()->wlmOutToLunch); - break; - case 7: - Kopete::Contact::setOnlineStatus(WlmProtocol::protocol()->wlmInvisible); - break; - case 8: - Kopete::Contact::setOnlineStatus(WlmProtocol::protocol()->wlmOffline); - break; - case 9: - Kopete::Contact::setOnlineStatus(WlmProtocol::protocol()->wlmIdle); - break; - default: - Kopete::Contact::setOnlineStatus(WlmProtocol::protocol()->wlmUnknown); - break; - } - - } - else -#endif - Kopete::Contact::setOnlineStatus(status); -} - diff --git a/protocols/wlm/wlmlibmsn.h b/protocols/wlm/wlmlibmsn.h deleted file mode 100644 --- a/protocols/wlm/wlmlibmsn.h +++ /dev/null @@ -1,348 +0,0 @@ -/* - wlmlibmsn.h - Kopete Wlm Protocol - - Copyright (c) 2008 by Tiago Salem Herrmann - Kopete (c) 2002-2003 by the Kopete developers - - ************************************************************************* - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the 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 WLMLIBMSN_H -#define WLMLIBMSN_H - -#include -#include "wlmsocket.h" -#include "kopetemessage.h" - -#include - -class WlmServer; - -namespace WlmUtils { -// MSN::Passport/std::string to QString encoding functions -QString passport(const MSN::Passport& pass); -QString latin1(const std::string& s); -QString utf8(const std::string& s); -} - -class Callbacks:public QObject, public MSN::Callbacks -{ - Q_OBJECT - -private: - virtual void registerSocket (void *s, int read, int write, bool isSSL); - - virtual void unregisterSocket (void *s); - - virtual void closeSocket (void *s); - - virtual void showError (MSN::Connection * conn, std::string msg); - - virtual void buddyChangedStatus (MSN::NotificationServerConnection * conn, - MSN::Passport buddy, std::string friendlyname, - MSN::BuddyStatus state, unsigned int clientID, - std::string msnobject); - - virtual void buddyOffline (MSN::NotificationServerConnection * conn, MSN::Passport buddy); - - virtual void log (int writing, const char *buf); - - virtual void buddyChangedPersonalInfo (MSN::NotificationServerConnection * conn, - MSN::Passport fromPassport, MSN::personalInfo); - - virtual void gotMessageSentACK (MSN::SwitchboardServerConnection * conn, int trID); - - virtual void gotFriendlyName (MSN::NotificationServerConnection * conn, std::string friendlyname); - - virtual void gotBuddyListInfo (MSN::NotificationServerConnection * conn, MSN::ListSyncInfo * data); - - virtual void gotLatestListSerial (MSN::NotificationServerConnection * conn, std::string lastChange); - - virtual void gotGTC (MSN::NotificationServerConnection * conn, char c); - - virtual void gotBLP (MSN::NotificationServerConnection * conn, char c); - - virtual void gotContactDisplayPicture (MSN::SwitchboardServerConnection *, - MSN::Passport, std::string); - - virtual void addedListEntry (MSN::NotificationServerConnection * conn, - MSN::ContactList list, MSN::Passport buddy, - std::string friendlyname); - - virtual void removedListEntry (MSN::NotificationServerConnection * conn, - MSN::ContactList list, MSN::Passport buddy); - - virtual void addedGroup (MSN::NotificationServerConnection * conn, bool added, - std::string groupName, std::string groupID); - - virtual void removedGroup (MSN::NotificationServerConnection * conn, bool removed, - std::string groupID); - - virtual void renamedGroup (MSN::NotificationServerConnection * conn, bool renamed, - std::string newGroupName, std::string groupID); - - virtual void addedContactToGroup (MSN::NotificationServerConnection * conn, bool added, - std::string groupId, std::string contactId); - - virtual void removedContactFromGroup (MSN::NotificationServerConnection * conn, - bool removed, std::string groupId, - std::string contactId); - - virtual void addedContactToAddressBook (MSN::NotificationServerConnection * conn, - bool added, std::string passport, - std::string displayName, std::string guid); - - virtual void removedContactFromAddressBook (MSN::NotificationServerConnection * conn, - bool removed, std::string contactId, - std::string passport); - - virtual void fileTransferInviteResponse (MSN::SwitchboardServerConnection * conn, - unsigned int sessionID, bool response); - - virtual void enabledContactOnAddressBook (MSN::NotificationServerConnection * conn, - bool enabled, std::string contactId, - std::string passport); - - virtual void disabledContactOnAddressBook (MSN::NotificationServerConnection * conn, - bool disabled, std::string contactId); - - virtual void gotSwitchboard (MSN::SwitchboardServerConnection * conn, const void *tag); - - virtual void buddyJoinedConversation (MSN::SwitchboardServerConnection * conn, - MSN::Passport buddy, std::string friendlyname, - int is_initial); - - virtual void buddyLeftConversation (MSN::SwitchboardServerConnection * conn, - MSN::Passport buddy); - - virtual void gotInstantMessage (MSN::SwitchboardServerConnection * conn, - MSN::Passport buddy, std::string friendlyname, - MSN::Message * msg); - - virtual void gotEmoticonNotification (MSN::SwitchboardServerConnection * conn, - MSN::Passport buddy, std::string alias, - std::string msnobject); - - virtual void failedSendingMessage (MSN::Connection * conn); - - virtual void buddyTyping (MSN::SwitchboardServerConnection * conn, MSN::Passport buddy, - std::string friendlyname); - - virtual void gotNudge (MSN::SwitchboardServerConnection * conn, MSN::Passport from); - - virtual void gotVoiceClipNotification (MSN::SwitchboardServerConnection * conn, MSN::Passport from, - std::string msnobject); - - virtual void gotWinkNotification (MSN::SwitchboardServerConnection * conn, MSN::Passport from, - std::string msnobject); - - virtual void gotInk (MSN::SwitchboardServerConnection * conn, MSN::Passport from, - std::string image); - - virtual void gotActionMessage (MSN::SwitchboardServerConnection * conn, - MSN::Passport username, std::string message); - - virtual void gotInitialEmailNotification (MSN::NotificationServerConnection * conn, - int msgs_inbox, int unread_inbox, - int msgs_folders, int unread_folders); - - virtual void gotNewEmailNotification (MSN::NotificationServerConnection * conn, - std::string from, std::string subject); - - virtual void fileTransferProgress (MSN::SwitchboardServerConnection * conn, - unsigned int sessionID, - long long unsigned transferred, - long long unsigned total); - - virtual void fileTransferFailed (MSN::SwitchboardServerConnection * conn, - unsigned int sessionID, MSN::fileTransferError error); - - virtual void fileTransferSucceeded (MSN::SwitchboardServerConnection * conn, - unsigned int sessionID); - - virtual void gotNewConnection (MSN::Connection * conn); - - virtual void gotOIMList (MSN::NotificationServerConnection * conn, - std::vector < MSN::eachOIM > OIMs); - - virtual void gotOIM (MSN::NotificationServerConnection * conn, bool success, - std::string id, std::string message); - - virtual void gotOIMSendConfirmation (MSN::NotificationServerConnection * conn, - bool success, int id); - - virtual void gotOIMDeleteConfirmation (MSN::NotificationServerConnection * conn, - bool success, std::string id); - - virtual void closingConnection (MSN::Connection * conn); - - virtual void changedStatus (MSN::NotificationServerConnection * conn, - MSN::BuddyStatus state); - - virtual void gotVoiceClipFile(MSN::SwitchboardServerConnection * conn, - unsigned int sessionID, - std::string file); - - virtual void gotEmoticonFile(MSN::SwitchboardServerConnection * conn, - unsigned int sessionID, - std::string alias, - std::string file); - - virtual void gotWinkFile(MSN::SwitchboardServerConnection * conn, - unsigned int sessionID, - std::string file); - - virtual void* connectToServer (std::string server, int port, bool * connected, bool isSSL); - - virtual size_t getDataFromSocket (void *sock, char *data, size_t size); - - virtual size_t writeDataToSocket (void *sock, char *data, size_t size); - - virtual void connectionReady (MSN::Connection * conn); - - virtual void askFileTransfer (MSN::SwitchboardServerConnection * conn, - MSN::fileTransferInvite ft); - - virtual int listenOnPort (int port); - - int getSocketFileDescriptor (void *sock); - - virtual std::string getOurIP (); - - virtual std::string getSecureHTTPProxy (); - - virtual void gotInboxUrl (MSN::NotificationServerConnection *conn, MSN::hotmailInfo info); - - public: - WlmServer * m_server; - QList socketList; - MSN::NotificationServerConnection * mainConnection; - enum MSNErrorCode { - NoError = 0, - WrongPassword, - OtherClient, - Unknown - }; - - signals: - void messageReceived (MSN::SwitchboardServerConnection * conn, - const QString & from, const Kopete::Message & message); - void joinedConversation (MSN::SwitchboardServerConnection * conn, - const QString & user, const QString & friendlyname); - void leftConversation (MSN::SwitchboardServerConnection * conn, - const QString & user); - void gotNewSwitchboard (MSN::SwitchboardServerConnection * conn, - const void *tag); - void SwitchboardServerConnectionTerminated (MSN::SwitchboardServerConnection *conn); - void NotificationServerConnectionTerminated (MSN::NotificationServerConnection *conn); - void messageSentACK (MSN::SwitchboardServerConnection * conn, const unsigned int &trID); - void incomingFileTransfer (MSN::SwitchboardServerConnection * conn, const MSN::fileTransferInvite & ft); - void gotFileTransferProgress (MSN::SwitchboardServerConnection * conn, const unsigned int &sessionID, - const unsigned long long &transferred); - void gotFileTransferFailed (MSN::SwitchboardServerConnection * conn, - const unsigned int &sessionID, - const MSN::fileTransferError & error); - - void gotFileTransferSucceeded (MSN::SwitchboardServerConnection * conn, - const unsigned int &sessionID); - - void gotDisplayName (const QString & displayName); - - void gotDisplayPicture (const QString & contact, const QString & filename); - - void gotNewContact (const MSN::ContactList & list, const QString & contact, - const QString & friendlyname); - - void gotRemovedContactFromList (const MSN::ContactList & list, const QString & contact); - - void gotAddedGroup (bool added, const QString & groupName, const QString & groupId); - - void gotRemovedGroup (bool removed, const QString & groupId); - - void gotAddedContactToGroup (bool added, const QString & groupId, const QString & contactId); - - void gotRemovedContactFromGroup (bool removed, const QString & groupId, const QString & contactId); - - void gotAddedContactToAddressBook (bool added, const QString & passport, const QString & displayName, - const QString & guid); - - void gotRemovedContactFromAddressBook (bool removed, const QString & passport, const QString & contactId); - - void receivedNudge (MSN::SwitchboardServerConnection * conn, const QString & contactId); - - void receivedTypingNotification (MSN::SwitchboardServerConnection * conn, const QString & contactId); - - void gotContactPersonalInfo (const QString & fromPassport, const MSN::personalInfo & pInfo); - - void receivedOIMList (std::vector < MSN::eachOIM > &oimlist); - - void receivedOIM (const QString & id, const QString & message); - - void deletedOIM (const QString & id, const bool & deleted); - - void contactChangedStatus (const QString & buddy, const QString & friendlyname, - const MSN::BuddyStatus & status, const unsigned int &clientID, const QString & msnobject); - - void contactDisconnected (const QString & buddy); - - void connectionCompleted (); - - void connectionFailed (); - - void changedStatus (MSN::BuddyStatus & state); - - void slotfileTransferInviteResponse (MSN::SwitchboardServerConnection * conn, - const unsigned int &sessionID, - const bool & response); - void slotGotEmoticonNotification (MSN::SwitchboardServerConnection * conn, - const QString & buddy, - const QString & alias, - const QString & msnobject); - - void slotGotVoiceClipNotification (MSN::SwitchboardServerConnection * conn, - const QString & from, - const QString & msnobject); - - void slotGotWinkNotification (MSN::SwitchboardServerConnection * conn, - const QString & from, - const QString & msnobject); - - void slotGotInk (MSN::SwitchboardServerConnection * conn, - const QString & from, - const QByteArray & image); - - void slotGotVoiceClipFile(MSN::SwitchboardServerConnection * conn, - const unsigned int & sessionID, - const QString & file); - - void slotGotEmoticonFile(MSN::SwitchboardServerConnection * conn, - const unsigned int & sessionID, - const QString & alias, - const QString & file); - - void slotGotWinkFile(MSN::SwitchboardServerConnection * conn, - const unsigned int & sessionID, - const QString & file); - - void mainConnectionError( int error ); - - void socketError( int error ); - - void initialEmailNotification(const int unread_inbox); - - void newEmailNotification(const QString from, const QString subject); - - void inboxUrl(MSN::hotmailInfo & info); - -private slots: - void emitSocketError( QAbstractSocket::SocketError error ); -}; - -#endif diff --git a/protocols/wlm/wlmlibmsn.cpp b/protocols/wlm/wlmlibmsn.cpp deleted file mode 100644 --- a/protocols/wlm/wlmlibmsn.cpp +++ /dev/null @@ -1,914 +0,0 @@ -/* - * msntest.cpp - * libmsn - * - * Created by Meredydd Luff. - * Refactored by Tiago Salem Herrmann - * Copyright (c) 2004 Meredydd Luff. All rights reserved. - * Copyright (c) 2007 Tiago Salem Herrmann. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the 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; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include "wlmlibmsn.h" -#include "wlmserver.h" -#include "wlmaccount.h" - -#include "kopetemessage.h" -#include "kopetecontact.h" -#include "kopeteuiglobal.h" - -// include first to not get compile errors on windows -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -namespace WlmUtils { -QString passport(const MSN::Passport& pass) -{ - return QString::fromLatin1(pass.c_str()); -} - -QString latin1(const std::string& s) -{ - return QString::fromLatin1(s.c_str()); -} - -QString utf8(const std::string& s) -{ - return QString::fromUtf8(s.c_str()); -} -} - -void -Callbacks::registerSocket (void *s, int reading, int writing, bool isSSL) -{ - Q_UNUSED( writing ); - Q_UNUSED( isSSL ); - - WlmSocket *a = (WlmSocket*)s; - if (!a) - return; - - if (reading) - { - QObject::disconnect(a, SIGNAL (readyRead()),0,0); - QObject::connect (a, SIGNAL (readyRead()), a, - SLOT (incomingData())); - } -} - -void -Callbacks::closeSocket (void *s) -{ - WlmSocket *a = (WlmSocket*)s; - if (a) - { - a->close (); - socketList.removeAll (a); - a->deleteLater(); - } -} - -void -Callbacks::unregisterSocket (void *s) -{ - WlmSocket *a = (WlmSocket*)s; - if (a) - { - QObject::disconnect(a, SIGNAL (readyRead()),0,0); - } -} - -void -Callbacks::gotFriendlyName (MSN::NotificationServerConnection * conn, - std::string friendlyname) -{ - Q_UNUSED( conn ); - emit gotDisplayName( WlmUtils::utf8(friendlyname) ); -} - -void -Callbacks::fileTransferInviteResponse (MSN::SwitchboardServerConnection * conn, - unsigned int sessionID, bool response) -{ - emit slotfileTransferInviteResponse (conn, sessionID, response); -} - -void -Callbacks::gotContactDisplayPicture (MSN::SwitchboardServerConnection * conn, - MSN::Passport passport, - std::string filename) -{ - Q_UNUSED( conn ); - emit gotDisplayPicture(WlmUtils::passport(passport), WlmUtils::utf8(filename)); -} - -void -Callbacks::gotMessageSentACK (MSN::SwitchboardServerConnection * conn, - int trID) -{ - emit messageSentACK (conn, trID); -} - -void -Callbacks::gotBuddyListInfo (MSN::NotificationServerConnection * conn, - MSN::ListSyncInfo * info) -{ - // IMPORTANT - // Here you need to fill a vector with all your contacts - // both received by the server and previous ones. - // Next pass this vector to the function completeConnection() - // if you do not call completeConnection(), the service will - // not work. - std::map < std::string, MSN::Buddy * >::iterator i = - info->contactList.begin (); - std::map < std::string, int >allContacts; - - for (; i != info->contactList.end (); ++i) - { - MSN::Buddy * contact = (*i).second; - if (contact->lists & MSN::LST_AB // only if it is the address book - && contact->properties["isMessengerUser"] == "true") - { - allContacts[contact->userName.c_str ()] = 0; - allContacts[contact->userName.c_str ()] |= MSN::LST_AB; - std::list < MSN::Buddy::PhoneNumber >::iterator pns = contact->phoneNumbers.begin (); - std::list < MSN::Group * >::iterator g = contact->groups.begin (); - } - if (contact->lists & MSN::LST_AL) - { - allContacts[contact->userName.c_str ()] |= MSN::LST_AL; - } - - if (contact->lists & MSN::LST_BL) - { - allContacts[contact->userName.c_str ()] |= MSN::LST_BL; - } - - if (contact->lists & MSN::LST_RL) - { - //printf ("-RL %s \n", contact->userName.c_str ()); - } - if (contact->lists & MSN::LST_PL) - { - //printf ("-PL %s \n", contact->userName.c_str ()); - } - } - //printf ("Available Groups:\n"); - std::map < std::string, MSN::Group >::iterator g = info->groups.begin (); - - for (; g != info->groups.end (); g++) - { - //printf (" %s: %s\n", (*g).second.groupID.c_str (), - // (*g).second.name.c_str ()); - } - - // this will send the ADL command to the server - // It is necessary. Do not forget to add *all* your contacts to allContacts, - // (both Forward, allow and block lists) or you probably will - // loose someone. - // A contact cannot be present both on allow and block lists or the - // server will return an error, so you need to let your application - // choose the better list to put it in. - m_server->m_account->groupListReceivedFromServer (info->groups); - m_server->m_account->addressBookReceivedFromServer (info->contactList); - conn->completeConnection (allContacts, info); -} - -void -Callbacks::gotLatestListSerial (MSN::NotificationServerConnection * conn, - std::string lastChange) -{ - Q_UNUSED( conn ); - Q_UNUSED( lastChange ); -} - -void -Callbacks::gotGTC (MSN::NotificationServerConnection * conn, char c) -{ - Q_UNUSED( conn ); - Q_UNUSED( c ); -} - -void -Callbacks::gotOIMDeleteConfirmation (MSN::NotificationServerConnection * conn, - bool success, std::string id) -{ - Q_UNUSED( conn ); - - if (success) - { - emit deletedOIM (WlmUtils::latin1(id), success); - std::cout << "OIM " << id << " removed successfully." << std::endl; - } - else - std::cout << "OIM " << id << " not removed successfully." << std::endl; - -} - -void -Callbacks::gotOIMSendConfirmation (MSN::NotificationServerConnection * conn, - bool success, int id) -{ - Q_UNUSED( conn ); - - if (success) - std::cout << "OIM " << id << " sent successfully." << std::endl; - else - std::cout << "OIM " << id << " not sent successfully." << std::endl; -} - -void -Callbacks::gotOIM (MSN::NotificationServerConnection * conn, bool success, - std::string id, std::string message) -{ - Q_UNUSED( conn ); - - if (success) - emit receivedOIM(WlmUtils::latin1(id), WlmUtils::utf8(message)); - else - std::cout << "Error retreiving OIM " << id << std::endl; -} - -void -Callbacks::gotOIMList (MSN::NotificationServerConnection * conn, - std::vector < MSN::eachOIM > OIMs) -{ - Q_UNUSED( conn ); - emit receivedOIMList (OIMs); -} - -void -Callbacks::connectionReady (MSN::Connection * conn) -{ - Q_UNUSED( conn ); - emit connectionCompleted (); -} - -void -Callbacks::gotBLP (MSN::NotificationServerConnection * conn, char c) -{ - Q_UNUSED( conn ); - Q_UNUSED( c ); -} - -void -Callbacks::addedListEntry (MSN::NotificationServerConnection * conn, - MSN::ContactList list, MSN::Passport username, - std::string friendlyname) -{ - Q_UNUSED( conn ); - emit gotNewContact (list, WlmUtils::passport(username), WlmUtils::utf8(friendlyname)); - // after adding the user you need to delete it from the pending list. - // it will be added automatically by the msn service - - // on regular lists you'll never receive the contacts displayname - // it is not needed anyway -} - -void -Callbacks::removedListEntry (MSN::NotificationServerConnection * conn, - MSN::ContactList list, MSN::Passport username) -{ - Q_UNUSED( conn ); - emit gotRemovedContactFromList (list, WlmUtils::passport(username)); -} - -void -Callbacks::addedGroup (MSN::NotificationServerConnection * conn, bool added, - std::string groupName, std::string groupID) -{ - Q_UNUSED( conn ); -/* if (added) - printf ("A group named %s (%s) was added\n", groupName.c_str (), - groupID.c_str ()); - else - printf ("Group (%s) was NOT added\n", groupName.c_str ()); -*/ - emit gotAddedGroup (added, WlmUtils::utf8(groupName), WlmUtils::latin1(groupID)); -} - -void -Callbacks::removedGroup (MSN::NotificationServerConnection * conn, - bool removed, std::string groupID) -{ - Q_UNUSED( conn ); -/* - if (removed) - printf ("A group with ID %s was removed\n", groupID.c_str ()); - else - printf ("Group (%s) was NOT removed\n", groupID.c_str ()); -*/ - emit gotRemovedGroup (removed, WlmUtils::latin1(groupID)); -} - -void -Callbacks::renamedGroup (MSN::NotificationServerConnection * conn, - bool renamed, std::string newGroupName, - std::string groupID) -{ - Q_UNUSED( conn ); - Q_UNUSED( renamed ); - Q_UNUSED( newGroupName ); - Q_UNUSED( groupID ); -/* - if (renamed) - printf ("A group with ID %s was renamed to %s\n", groupID.c_str (), - newGroupName.c_str ()); - else - printf ("A group with ID %s was NOT renamed to %s\n", - groupID.c_str (), newGroupName.c_str ()); -*/ -} - -void -Callbacks::showError (MSN::Connection * conn, std::string msg) -{ - std::cout << "MSN: Error: " << msg.c_str () << std::endl; - QString a = WlmUtils::latin1(msg); - // FIXME This is really ugly the libmsn should send some error code instead of msg - if (a.contains("Wrong Password")) - emit mainConnectionError(WrongPassword); - else if (a.contains("You have logged onto MSN twice at once")) - emit mainConnectionError(OtherClient); - else if (conn == mainConnection) - emit mainConnectionError(Unknown); -} - -void -Callbacks::buddyChangedStatus (MSN::NotificationServerConnection * conn, - MSN::Passport buddy, std::string friendlyname, - MSN::BuddyStatus status, unsigned int clientID, - std::string msnobject) -{ - Q_UNUSED( conn ); - emit contactChangedStatus (WlmUtils::passport(buddy), WlmUtils::utf8(friendlyname), - status, clientID, WlmUtils::utf8(msnobject)); -} - -void -Callbacks::buddyOffline (MSN::NotificationServerConnection * conn, - MSN::Passport buddy) -{ - Q_UNUSED( conn ); - emit contactDisconnected(WlmUtils::passport(buddy)); -} - -void -Callbacks::gotSwitchboard (MSN::SwitchboardServerConnection * conn, - const void *tag) -{ - emit gotNewSwitchboard (dynamic_cast(conn), tag); -} - -void -Callbacks::buddyJoinedConversation (MSN::SwitchboardServerConnection * conn, - MSN::Passport username, - std::string friendlyname, int is_initial) -{ - Q_UNUSED( is_initial ); - - emit joinedConversation (conn, WlmUtils::passport(username), WlmUtils::utf8(friendlyname)); - const std::pair *ctx = static_cast *>(conn->auth.tag); - delete ctx; - conn->auth.tag = NULL; - -/* if (conn->auth.tag) - { - const std::pair *ctx = static_cast *>(conn->auth.tag); - // Example of sending a custom emoticon -// conn->myNotificationServer()->msnobj.addMSNObject("/tmp/emoticon.gif",2); -// std::string obj; -// conn->myNotificationServer()->msnobj.getMSNObjectXML("/tmp/emoticon.gif", 2, obj); -// conn->sendEmoticon("(EMOTICON)", obj); - - conn->sendMessage(ctx->second); - delete ctx; - conn->auth.tag = NULL; - - //Example of sending a file -// MSN::fileTransferInvite ft; -// ft.filename = "/tmp/filetosend.txt"; -// ft.friendlyname = "filetosend2.txt"; -// ft.sessionId = sessionID++; -// ft.type = MSN::FILE_TRANSFER_WITHOUT_PREVIEW; -// conn->sendFile(ft); - -// conn->sendNudge(); -// conn->sendAction("Action message here"); - - // Exemple of requesting a display picture. -// std::string filename2("/tmp/displayPicture.bin"+MSN::toStr(sessionID)); - // lastObject is the msnobject received on each contact status change - // you should generate a random sessionID -// conn->requestFile(sessionID++, filename2, lastObject); - - // Example of sending a voice clip -// conn->myNotificationServer()->msnobj.addMSNObject("/tmp/voiceclip.wav",11); -// std::string obj; -// conn->myNotificationServer()->msnobj.getMSNObjectXML("/tmp/voiceclip.wav", 11, obj); -// conn->sendVoiceClip(obj); - // exemple of sending an ink -// std::string ink("base64 data here..."); -// conn->sendInk(ink); - } - */ -} - -void -Callbacks::buddyLeftConversation (MSN::SwitchboardServerConnection * conn, - MSN::Passport username) -{ - emit leftConversation (conn, WlmUtils::passport(username)); - -} - -void -Callbacks::gotInstantMessage (MSN::SwitchboardServerConnection * conn, - MSN::Passport username, - std::string friendlyname, MSN::Message * msg) -{ - Q_UNUSED( friendlyname ); - - Kopete::Message kmsg; - kmsg.setPlainBody(WlmUtils::utf8(msg->getBody())); - QFont font (WlmUtils::latin1(msg->getFontName())); - if (msg->getFontEffects () & MSN::Message::BOLD_FONT) - font.setBold (true); - if (msg->getFontEffects () & MSN::Message::ITALIC_FONT) - font.setItalic (true); - if (msg->getFontEffects () & MSN::Message::UNDERLINE_FONT) - font.setUnderline (true); - if (msg->getFontEffects () & MSN::Message::STRIKETHROUGH_FONT) - font.setStrikeOut (true); - - QColor color (msg->getColor ()[0], msg->getColor ()[1], - msg->getColor ()[2]); - kmsg.setForegroundColor (color); - - kmsg.setFont (font); - emit messageReceived (conn, WlmUtils::passport(username), kmsg); -} - -void -Callbacks::gotEmoticonNotification (MSN::SwitchboardServerConnection * conn, - MSN::Passport username, std::string alias, - std::string msnobject) -{ - emit slotGotEmoticonNotification(conn, WlmUtils::passport(username), - WlmUtils::utf8(alias), WlmUtils::utf8(msnobject)); -} - -void -Callbacks::failedSendingMessage (MSN::Connection * conn) -{ - Q_UNUSED( conn ); - //printf ("**************************************************\n"); - //printf ("ERROR: Your last message failed to send correctly\n"); - //printf ("**************************************************\n"); -} - -void -Callbacks::buddyTyping (MSN::SwitchboardServerConnection * conn, - MSN::Passport username, std::string friendlyname) -{ - Q_UNUSED( friendlyname ); - emit receivedTypingNotification (conn, WlmUtils::passport(username)); - -} - -void -Callbacks::gotNudge (MSN::SwitchboardServerConnection * conn, - MSN::Passport username) -{ - emit receivedNudge (conn, WlmUtils::passport(username)); -} - -void -Callbacks::gotVoiceClipNotification (MSN::SwitchboardServerConnection * conn, - MSN::Passport username, std::string msnobject) -{ - emit slotGotVoiceClipNotification(conn, WlmUtils::passport(username), WlmUtils::utf8(msnobject)); -} - -void -Callbacks::gotWinkNotification (MSN::SwitchboardServerConnection * conn, - MSN::Passport username, std::string msnobject) -{ - emit slotGotWinkNotification(conn, WlmUtils::passport(username), WlmUtils::utf8(msnobject)); -} - -void -Callbacks::gotInk (MSN::SwitchboardServerConnection * conn, - MSN::Passport username, std::string image) -{ - emit slotGotInk(conn, WlmUtils::passport(username), QByteArray(image.c_str())); -} - -void -Callbacks::gotActionMessage (MSN::SwitchboardServerConnection * conn, - MSN::Passport username, std::string message) -{ - Q_UNUSED( conn ); - Q_UNUSED( username ); - Q_UNUSED( message ); -} - -void -Callbacks::gotInitialEmailNotification (MSN::NotificationServerConnection * - conn, int msgs_inbox, - int unread_inbox, int msgs_folders, - int unread_folders) -{ - Q_UNUSED( conn ); - Q_UNUSED( msgs_inbox ); - Q_UNUSED( msgs_folders ); - Q_UNUSED( unread_folders ); - - if (unread_inbox > 0) - emit initialEmailNotification (unread_inbox); -} - -void -Callbacks::gotNewEmailNotification (MSN::NotificationServerConnection * conn, - std::string from, std::string subject) -{ - Q_UNUSED( conn ); - emit newEmailNotification (WlmUtils::utf8(from), KMime::decodeRFC2047String(subject.c_str())); -} - -void -Callbacks::gotInboxUrl (MSN::NotificationServerConnection * conn, - MSN::hotmailInfo info) -{ - Q_UNUSED( conn ); - emit inboxUrl (info); -} - -void -Callbacks::fileTransferProgress (MSN::SwitchboardServerConnection * conn, - unsigned int sessionID, - unsigned long long transferred, - unsigned long long total) -{ - Q_UNUSED( total ); - emit gotFileTransferProgress (conn, sessionID, transferred); -} - -void -Callbacks::fileTransferFailed (MSN::SwitchboardServerConnection * conn, - unsigned int sessionID, MSN::fileTransferError error) -{ - emit gotFileTransferFailed (conn, sessionID, error); -} - -void -Callbacks::fileTransferSucceeded (MSN::SwitchboardServerConnection * conn, - unsigned int sessionID) -{ - //printf ("File transfer successfully completed. session: %d\n", sessionID); - emit gotFileTransferSucceeded (conn, sessionID); -} - -void -Callbacks::gotNewConnection (MSN::Connection * conn) -{ - if (dynamic_cast < MSN::NotificationServerConnection * >(conn)) - dynamic_cast (conn)->synchronizeContactList (); -} - -void -Callbacks::buddyChangedPersonalInfo (MSN::NotificationServerConnection * conn, - MSN::Passport fromPassport, - MSN::personalInfo pInfo) -{ - Q_UNUSED( conn ); - // MSN::personalInfo shows all the data you can grab from the contact - //printf ("User %s Personal Message: %s\n", fromPassport.c_str (), - // pInfo.PSM.c_str ()); - emit gotContactPersonalInfo (WlmUtils::passport(fromPassport), pInfo); -} - -void -Callbacks::closingConnection (MSN::Connection * conn) -{ - if (dynamic_cast < MSN::SwitchboardServerConnection * >(conn)) - emit SwitchboardServerConnectionTerminated ( - dynamic_cast (conn)); - if (dynamic_cast < MSN::NotificationServerConnection * >(conn)) - emit NotificationServerConnectionTerminated ( - dynamic_cast (conn)); -} - -void -Callbacks::changedStatus (MSN::NotificationServerConnection * conn, - MSN::BuddyStatus state) -{ - Q_UNUSED( conn ); - //printf ("Your state is now: %s\n", - // MSN::buddyStatusToString (state).c_str ()); - emit changedStatus (state); -/* MSN::personalInfo pInfo; - pInfo.PSM="my personal message"; - pInfo.mediaType="Music"; - pInfo.mediaIsEnabled=1; - pInfo.mediaFormat="{0} - {1}"; - pInfo.mediaLines.push_back("Artist"); - pInfo.mediaLines.push_back("Song"); - conn->setPersonalStatus(pInfo); -*/ -} - -size_t -Callbacks::getDataFromSocket (void *sock, char *data, size_t size) -{ - WlmSocket *a = (WlmSocket*)sock; - if (!a) - return 0; - - return a->read(data, size); -} - -size_t -Callbacks::writeDataToSocket (void *sock, char *data, size_t size) -{ - WlmSocket *a = (WlmSocket*)sock; - if (!a) - return 0; - - return a->write(data, size); -} - -void * -Callbacks::connectToServer (std::string hostname, int port, bool * connected, bool isSSL) -{ - WlmSocket *a = new WlmSocket (mainConnection, isSSL, m_server); - if(!a) - return NULL; - - connect( a, SIGNAL(sslErrors(QList)), a, SLOT(ignoreSslErrors()) ); - connect( a, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(emitSocketError(QAbstractSocket::SocketError)) ); - - if(!isSSL) - a->connectToHost (WlmUtils::latin1(hostname), port); - else - a->connectToHostEncrypted (WlmUtils::latin1(hostname), port); - - *connected = false; - socketList.append (a); - return (void*)a; -} - -int -Callbacks::listenOnPort (int port) -{ - Q_UNUSED( port ); - // this callback is not used yet, - // so, for now we are returning a dummy - // value to avoid compiling issues - return 0; -} - -std::string Callbacks::getOurIP (void) -{ - // this callback is not used yet, - // so, for now we are returning a dummy - // value to avoid compiling issues - return ""; -} - -void -Callbacks::log (int i, const char *s) -{ - Q_UNUSED( i ); - Q_UNUSED( s ); -} - -int -Callbacks::getSocketFileDescriptor (void *sock) -{ - WlmSocket *a = (WlmSocket*)sock; - if(!a) - return -1; - return a->socketDescriptor(); -} - -std::string Callbacks::getSecureHTTPProxy () -{ - return ""; -} - -void -Callbacks::askFileTransfer (MSN::SwitchboardServerConnection * conn, - MSN::fileTransferInvite ft) -{ - emit incomingFileTransfer (conn, ft); -/* - switch(ft.type) - { - case MSN::FILE_TRANSFER_BACKGROUND_SHARING: - printf("User %s wants to share with you a background file named %s. Size: %llu. Accepting..\n", ft.userPassport.c_str(), ft.filename.c_str(), ft.filesize); - break; - case MSN::FILE_TRANSFER_BACKGROUND_SHARING_CUSTOM: - printf("User %s wants to share with you a *custom background file named %s. Size: %llu. Accepting..\n", ft.userPassport.c_str(), ft.filename.c_str(), ft.filesize); - break; - case MSN::FILE_TRANSFER_WITH_PREVIEW: - printf("User %s wants to send you a file *with preview named %s. Size: %llu. Accepting..\n", ft.userPassport.c_str(), ft.filename.c_str(), ft.filesize); - // ft.preview has the base64 encoded png file - break; - case MSN::FILE_TRANSFER_WITHOUT_PREVIEW: - printf("User %s wants to send you a file *without preview named %s. Size: %llu. Accepting..\n", ft.userPassport.c_str(), ft.filename.c_str(), ft.filesize); - break; - default: - printf("Unknown filetransfer type from %s..\n", ft.userPassport.c_str()); - - } - conn->fileTransferResponse(ft.sessionId, filename2, true); -*/ -} - -void -Callbacks::addedContactToGroup (MSN::NotificationServerConnection * conn, - bool added, std::string groupId, - std::string contactId) -{ - Q_UNUSED( conn ); -/* - if (added) - printf ("User Id (%s) added to group Id (%s)\n", contactId.c_str (), - groupId.c_str ()); - else - printf ("User Id (%s) NOT added to group Id (%s)\n", - contactId.c_str (), groupId.c_str ()); -*/ - emit gotAddedContactToGroup (added, WlmUtils::latin1(groupId), - WlmUtils::latin1(contactId)); -} - -void -Callbacks::removedContactFromGroup (MSN::NotificationServerConnection * conn, - bool removed, std::string groupId, - std::string contactId) -{ - Q_UNUSED( conn ); -/* - if (removed) - printf ("User Id (%s) removed from group Id (%s)\n", - contactId.c_str (), groupId.c_str ()); - else - printf ("User Id (%s) NOT removed from group Id (%s)\n", - contactId.c_str (), groupId.c_str ()); -*/ - emit gotRemovedContactFromGroup (removed, WlmUtils::latin1(groupId), - WlmUtils::latin1(contactId)); -} - -void -Callbacks::addedContactToAddressBook (MSN::NotificationServerConnection * - conn, bool added, std::string passport, - std::string displayName, - std::string guid) -{ - Q_UNUSED( conn ); -/* - if (added) - printf ("User (%s - %s) added to AddressBook. Guid (%s)\n", - passport.c_str (), displayName.c_str (), guid.c_str ()); - else - printf ("User (%s - %s) NOT added to AddressBook.\n", - passport.c_str (), displayName.c_str ()); -*/ - emit gotAddedContactToAddressBook (added, WlmUtils::passport(passport), - WlmUtils::utf8(displayName), WlmUtils::latin1(guid)); -} - -void -Callbacks::removedContactFromAddressBook (MSN::NotificationServerConnection * - conn, bool removed, - std::string contactId, - std::string passport) -{ - Q_UNUSED( conn ); -/* - if (removed) - printf ("User %s removed from AddressBook. Guid (%s)\n", - passport.c_str (), contactId.c_str ()); - else - printf ("User %s NOT removed from AddressBook. Guid (%s)\n", - passport.c_str (), contactId.c_str ()); -*/ - emit gotRemovedContactFromAddressBook (removed, WlmUtils::passport(passport), - WlmUtils::latin1(contactId)); -} - -void -Callbacks::enabledContactOnAddressBook (MSN::NotificationServerConnection * - conn, bool enabled, - std::string contactId, - std::string passport) -{ - Q_UNUSED( conn ); - Q_UNUSED( enabled ); - Q_UNUSED( contactId ); - Q_UNUSED( passport ); -/* - // this is used to enable a contact previously disabled from msn, but not fully removed - if (enabled) - printf ("User (%s) enabled on AddressBook. Guid (%s)\n", - passport.c_str (), contactId.c_str ()); - else - printf ("User (%s) NOT enabled on AddressBook. Guid (%s)\n", - passport.c_str (), contactId.c_str ()); -*/ -} - -void -Callbacks::disabledContactOnAddressBook (MSN::NotificationServerConnection * - conn, bool disabled, - std::string contactId) -{ - Q_UNUSED( conn ); - Q_UNUSED( disabled ); - Q_UNUSED( contactId ); - // this is used when you have disabled this user from msn, but not deleted from hotmail - // I suggest to delete the contact instead of disable, since I haven't tested this too much yet -/* - if (disabled) - printf ("User disabled on AddressBook. Guid (%s)\n", - contactId.c_str ()); - else - printf ("User NOT disabled on AddressBook. Guid (%s)\n", - contactId.c_str ()); -*/ -} - -void Callbacks::gotVoiceClipFile(MSN::SwitchboardServerConnection * conn, unsigned int sessionID, std::string file) -{ - emit slotGotVoiceClipFile(conn, sessionID, WlmUtils::utf8(file)); -} - -void Callbacks::gotEmoticonFile(MSN::SwitchboardServerConnection * conn, unsigned int sessionID, std::string alias, std::string file) -{ - emit slotGotEmoticonFile(conn, sessionID, WlmUtils::utf8(alias), WlmUtils::utf8(file)); -} - -void Callbacks::gotWinkFile(MSN::SwitchboardServerConnection * conn, unsigned int sessionID, std::string file) -{ - emit slotGotWinkFile(conn, sessionID, WlmUtils::utf8(file)); -} - -void Callbacks::emitSocketError( QAbstractSocket::SocketError error ) -{ - if ( !mainConnection ) - return; - - WlmSocket* socket = qobject_cast(sender()); - Q_ASSERT( socket ); - - MSN::Connection *c = mainConnection->connectionWithSocket((void*)socket); - if ( !c ) - return; - - if ( c == mainConnection ) - emit socketError( error ); - else - c->disconnect(); -} - diff --git a/protocols/wlm/wlmprotocol.h b/protocols/wlm/wlmprotocol.h deleted file mode 100644 --- a/protocols/wlm/wlmprotocol.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - wlmprotocol.h - Kopete Wlm Protocol - - Copyright (c) 2008 by Tiago Salem Herrmann - Kopete (c) 2002-2003 by the Kopete developers - - ************************************************************************* - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the 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 WLMPROTOCOL_H -#define WLMPROTOCOL_H - -#include -#include "kopeteproperty.h" - -/** - * Encapsulates the generic actions associated with this protocol - * @author Will Stephenson - */ -class WlmProtocol: public Kopete::Protocol -{ - Q_OBJECT - public: - WlmProtocol (QObject * parent, const QVariantList & args); - ~WlmProtocol (); - /** - * Convert the serialised data back into a WlmContact and add this - * to its Kopete::MetaContact - */ - virtual Kopete::Contact * deserializeContact (Kopete::MetaContact * metaContact, - const QMap < QString, QString > &serializedData, - const QMap < QString, QString > &addressBookData); - /** - * Generate the widget needed to add WlmContacts - */ - virtual AddContactPage * - createAddContactWidget (QWidget * parent, Kopete::Account * account); - /** - * Generate the widget needed to add/edit accounts for this protocol - */ - virtual KopeteEditAccountWidget * - createEditAccountWidget (Kopete::Account * account, QWidget * parent); - /** - * Generate a WlmAccount - */ - virtual Kopete::Account *createNewAccount (const QString & accountId); - /** - * Access the instance of this protocol - */ - static WlmProtocol * protocol (); - - static bool validContactId(const QString&); - - /** - * Represents contacts that are Online - */ - const Kopete::OnlineStatus wlmOnline; - /** - * Represents contacts that are Away - */ - const Kopete::OnlineStatus wlmAway; - /** - * Represents contacts that are Offline - */ - const Kopete::OnlineStatus wlmBusy; - - const Kopete::OnlineStatus wlmBeRightBack; - - const Kopete::OnlineStatus wlmOnThePhone; - - const Kopete::OnlineStatus wlmOutToLunch; - - const Kopete::OnlineStatus wlmInvisible; - - const Kopete::OnlineStatus wlmOffline; - - const Kopete::OnlineStatus wlmIdle; - - const Kopete::OnlineStatus wlmUnknown; - - const Kopete::OnlineStatus wlmConnecting; - - const Kopete::PropertyTmpl currentSong; - - const Kopete::PropertyTmpl contactCapabilities; - - const Kopete::PropertyTmpl displayPhotoSHA1; - - protected: - static WlmProtocol * s_protocol; -}; - -#endif diff --git a/protocols/wlm/wlmprotocol.cpp b/protocols/wlm/wlmprotocol.cpp deleted file mode 100644 --- a/protocols/wlm/wlmprotocol.cpp +++ /dev/null @@ -1,165 +0,0 @@ -/* - wlmprotocol.cpp - Kopete Wlm Protocol - - Copyright (c) 2008 by Tiago Salem Herrmann - Kopete (c) 2002-2003 by the Kopete developers - - ************************************************************************* - * * - * This 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 of the License, or (at your option) any later version. * - * * - ************************************************************************* -*/ - -#include "wlmprotocol.h" -#include "wlmaccount.h" -#include "wlmcontact.h" -#include "wlmaddcontactpage.h" -#include "wlmeditaccountwidget.h" - -#include -#include -#include -#include "kopeteaccountmanager.h" -#include "kopeteonlinestatusmanager.h" -#include "kopeteappearancesettings.h" -#include "kopeteidentity.h" -#include "kopeteavatarmanager.h" - -static const KAboutData aboutdata ("kopete_wlm", 0, ki18n ("WLM"), "1.0"); - -WlmProtocol * - WlmProtocol::s_protocol = 0L; -K_PLUGIN_FACTORY (WlmProtocolFactory, registerPlugin < WlmProtocol > (); - )K_EXPORT_PLUGIN (WlmProtocolFactory ("kopete_wlm")) - WlmProtocol::WlmProtocol (QObject * parent, - const QVariantList & /*args */ ) - : -Kopete::Protocol(WlmProtocolFactory::componentData (), parent, true), -wlmOnline (Kopete::OnlineStatus::Online, 25, this, 1, QStringList (), - i18n ("Online"), i18n ("O&nline"), - Kopete::OnlineStatusManager::Online), -wlmAway (Kopete::OnlineStatus::Away, 18, this, 2, QStringList ("contact_away_overlay"), - i18n ("Away"), i18n ("&Away"), Kopete::OnlineStatusManager::Away), -wlmBusy (Kopete::OnlineStatus::Busy, 20, this, 3, QStringList ("wlm_busy"), - i18n ("Busy"), i18n ("&Busy"), Kopete::OnlineStatusManager::Busy), -wlmBeRightBack (Kopete::OnlineStatus::Away, 22, this, 4, - QStringList ("wlm_brb"), i18n ("Be Right Back"), - i18n ("Be &Right Back"), 0), -wlmOnThePhone (Kopete::OnlineStatus::Busy, 12, this, 5, - QStringList ("contact_phone_overlay"), i18n ("On the Phone"), - i18n ("On The &Phone"), 0), -wlmOutToLunch (Kopete::OnlineStatus::Away, 15, this, 6, - QStringList ("contact_food_overlay"), i18n ("Out to Lunch"), - i18n ("Out To &Lunch"), 0), -wlmInvisible (Kopete::OnlineStatus::Invisible, 3, this, 7, - QStringList ("contact_invisible_overlay"), i18n ("Invisible"), - i18n ("&Invisible"), Kopete::OnlineStatusManager::Invisible), -wlmOffline (Kopete::OnlineStatus::Offline, 0, this, 8, - QStringList (QString ()), i18n ("Offline"), i18n ("O&ffline"), - Kopete::OnlineStatusManager::Offline, - Kopete::OnlineStatusManager::DisabledIfOffline), -wlmIdle (Kopete::OnlineStatus::Away, 10, this, 9, - QStringList ("contact_away_overlay"), i18n ("Idle"), i18n ("&Idle"), - Kopete::OnlineStatusManager::Idle), -wlmUnknown (Kopete::OnlineStatus::Unknown, 25, this, 0, - QStringList ("status_unknown"), i18n ("Status not available")), -wlmConnecting (Kopete::OnlineStatus::Connecting, 2, this, 10, - QStringList ("wlm_connecting"), i18n ("Connecting")), -currentSong ("currentSong", i18nc ("This is used in the tooltip of a contact", "Listening To")), -contactCapabilities ("contactCapabilities", "Used to keep track of the contact capabilities", QString(), - Kopete::PropertyTmpl::PrivateProperty), -displayPhotoSHA1("displayPhotoSHA1", "Display Photo SHA-1 Hash", QString(), - Kopete::PropertyTmpl::PersistentProperty | Kopete::PropertyTmpl::PrivateProperty) -{ - kDebug (14210) << k_funcinfo; - - s_protocol = this; - - //TODO FIXME - QStringList shownProps = - Kopete::AppearanceSettings::self ()->toolTipContents (); - - if (!shownProps.contains ("currentSong")) - shownProps << QString::fromLatin1 ("currentSong"); - Kopete::AppearanceSettings::self ()->setToolTipContents (shownProps); - - setCapabilities (Kopete::Protocol::BaseFgColor | - Kopete::Protocol::BaseFont | - Kopete::Protocol::BaseFormatting); -} - -WlmProtocol::~WlmProtocol () -{ -} - -Kopete::Contact * WlmProtocol::deserializeContact (Kopete::MetaContact * - metaContact, const QMap &serializedData, - const QMap < QString, QString > & ) -{ - QString contactId = serializedData["contactId"]; - QString contactSerial = serializedData["contactSerial"]; - QString accountId = serializedData["accountId"]; - QString dontShowEmoticons = serializedData["dontShowEmoticons"]; - Kopete::Contact::NameType nameType = Kopete::Contact::nameTypeFromString(serializedData[ "preferredNameType" ]); - - QList accounts = - Kopete::AccountManager::self ()->accounts (this); - Kopete::Account * account = 0; - foreach (Kopete::Account * acct, accounts) - { - if (acct->accountId () == accountId) - account = acct; - } - - if (!account) - { - kDebug (14210) << "Account doesn't exist, skipping"; - return 0; - } - WlmContact * c = new WlmContact (account, contactId, contactSerial, metaContact); - - if(dontShowEmoticons == "true") - c->slotDontShowEmoticons(true); - - c->setPreferredNameType(nameType); - - return c; -} - -AddContactPage * -WlmProtocol::createAddContactWidget (QWidget * parent, Kopete::Account *account) -{ - kDebug (14210) << "Creating Add Contact Page"; - return new WlmAddContactPage(account, parent); -} - -KopeteEditAccountWidget * -WlmProtocol::createEditAccountWidget (Kopete::Account * account, - QWidget * parent) -{ - kDebug (14210) << "Creating Edit Account Page"; - return new WlmEditAccountWidget (parent, account); -} - -Kopete::Account * WlmProtocol::createNewAccount (const QString & accountId) -{ - return new WlmAccount (this, accountId); -} - -WlmProtocol * -WlmProtocol::protocol () -{ - return s_protocol; -} - -bool WlmProtocol::validContactId (const QString& contactId) -{ - QRegExp rx("[^@\\s]+@([^@\\.\\s]+\\.)+[^@\\.\\s]+"); - return ( rx.exactMatch( contactId ) ); -} - -#include "wlmprotocol.moc" diff --git a/protocols/wlm/wlmserver.h b/protocols/wlm/wlmserver.h deleted file mode 100644 --- a/protocols/wlm/wlmserver.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - wlmserver.h - Kopete Wlm Protocol - - Copyright (c) 2008 by Tiago Salem Herrmann - Kopete (c) 2002-2003 by the Kopete developers - - ************************************************************************* - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the 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 WLMSERVER_H -#define WLMSERVER_H -#include -#include "wlmlibmsn.h" - -class WlmAccount; - -class WlmServer : public QObject -{ - Q_OBJECT -public: - WlmServer( WlmAccount * account, const QString & m_accountID, const QString & m_password ); - ~WlmServer (); - - void WlmConnect( const QString& server, uint port ); - void WlmDisconnect(); - - WlmAccount * m_account; - QString m_accountID; - QString m_password; - Callbacks cb; - - MSN::NotificationServerConnection * mainConnection; - std::string myFriendlyName; - std::string myUsername; -}; - -#endif diff --git a/protocols/wlm/wlmserver.cpp b/protocols/wlm/wlmserver.cpp deleted file mode 100644 --- a/protocols/wlm/wlmserver.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - wlmserver.cpp - Kopete Wlm Protocol - - Copyright (c) 2008 by Tiago Salem Herrmann - Kopete (c) 2002-2003 by the Kopete developers - - ************************************************************************* - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the 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 "wlmserver.h" -#include "wlmsocket.h" - -WlmServer::WlmServer (WlmAccount * account, const QString & accountID, const QString & password): -m_account (account), -m_accountID (accountID), m_password (password), mainConnection (NULL) -{ -} - -WlmServer::~WlmServer () -{ - qDeleteAll(cb.socketList); - delete mainConnection; -} - -void -WlmServer::WlmConnect ( const QString& server, uint port ) -{ - cb.m_server = this; - mainConnection = - new MSN::NotificationServerConnection (m_accountID.toLatin1 ().constData (), - m_password.toUtf8().constData (), - cb); - cb.mainConnection = mainConnection; - - if (mainConnection) - mainConnection->connect (server.toLatin1().constData(), port); -} - -void -WlmServer::WlmDisconnect () -{ - WlmSocket *a = 0; - - if (mainConnection) - { - QListIterator i(cb.socketList); - while (i.hasNext()) - { - a = i.next(); - QObject::disconnect (a, 0, 0, 0); - cb.socketList.removeAll (a); - } - cb.socketList.clear (); - - if ( mainConnection->connectionState() != MSN::NotificationServerConnection::NS_DISCONNECTED ) - mainConnection->disconnect(); - } -} - diff --git a/protocols/wlm/wlmsocket.h b/protocols/wlm/wlmsocket.h deleted file mode 100644 --- a/protocols/wlm/wlmsocket.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - wlmsocket.h - Kopete Wlm Protocol - - Copyright (c) 2008 by Tiago Salem Herrmann - Kopete (c) 2002-2003 by the Kopete developers - - ************************************************************************* - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the 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 WLMSOCKET_H -#define WLMSOCKET_H - -#include - -#include - -class QTimer; -class WlmServer; - -class WlmSocket : public QSslSocket -{ - Q_OBJECT -public: - explicit WlmSocket( MSN::NotificationServerConnection * mainConnection, bool isSSL = false, WlmServer* server = NULL ); - ~WlmSocket(); - - bool isSSL() const { return mIsSSL; } - -public slots: - void incomingData(); - void connectionReady(); - void connectionFinished(); - void connectionEncryptedReady(); - -private slots: - void resetPing(); - void pingTimeout(); - -private: - void initPingTimer(); - - MSN::NotificationServerConnection * mMainConnection; - bool mIsSSL; - QTimer* mPingTimer; -}; -#endif diff --git a/protocols/wlm/wlmsocket.cpp b/protocols/wlm/wlmsocket.cpp deleted file mode 100644 --- a/protocols/wlm/wlmsocket.cpp +++ /dev/null @@ -1,173 +0,0 @@ -/* - wlmsocket.cpp - Kopete Wlm Protocol - - Copyright (c) 2008 by Tiago Salem Herrmann - Kopete (c) 2002-2003 by the Kopete developers - - ************************************************************************* - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the 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 "wlmsocket.h" - -#include -#include - -#include "kopetesockettimeoutwatcher.h" -#include "kopeteaccount.h" -#include "wlmaccount.h" -#include "wlmserver.h" -#include -#include - -WlmSocket::WlmSocket(MSN::NotificationServerConnection * mainConnection, bool isSSL, WlmServer* server) -: mMainConnection(mainConnection), mIsSSL(isSSL), mPingTimer(0) -{ - QObject::connect( this, SIGNAL(connected()), this, SLOT(connectionReady()) ); - QObject::connect( this, SIGNAL(disconnected()), this, SLOT(connectionFinished()) ); - QObject::connect( this, SIGNAL(encrypted()), this, SLOT(connectionEncryptedReady()) ); - QObject::connect( this, SIGNAL(bytesWritten(qint64)), this, SLOT(resetPing()) ); - - Kopete::SocketTimeoutWatcher* timeoutWatcher = Kopete::SocketTimeoutWatcher::watch( this ); - if ( timeoutWatcher ) - connect( timeoutWatcher, SIGNAL(error(QAbstractSocket::SocketError)), this, SIGNAL(error(QAbstractSocket::SocketError)) ); - - if (server && server->m_account) - { - WlmAccount *acc= server->m_account; - if(acc->isProxyEnabled()) - { - QString proxyHost = acc->proxyHost(); - uint proxyPort = acc->proxyPort(); - QNetworkProxy::ProxyType proxyType = (QNetworkProxy::ProxyType) acc->proxyType(); - QString proxyUsername = acc->proxyUsername(); - QString proxyPassword = acc->proxyPassword(); - setProxy(QNetworkProxy(proxyType, proxyHost, proxyPort, proxyUsername, proxyPassword)); - } - } -} - -WlmSocket::~WlmSocket() -{ - delete mPingTimer; -} - -void WlmSocket::connectionEncryptedReady() -{ - MSN::Connection * c; - - if ( !mMainConnection ) - return; - // Retrieve the connection associated with the - // socket's file handle on which the event has - // occurred. - c = mMainConnection->connectionWithSocket( (void*)this ); - - // if this is a libmsn socket - if (c != NULL) - { - if ( c->isConnected() == false ) - { - c->socketConnectionCompleted(); - } - // If this event is due to new data becoming available - c->socketIsWritable(); - } - - if ( c == mMainConnection ) - initPingTimer(); -} - -void WlmSocket::connectionReady() -{ - MSN::Connection * c; - - // ssl is connected when encrypted() is raised - if( isSSL() ) - return; - - if ( !mMainConnection ) - return; - // Retrieve the connection associated with the - // socket's file handle on which the event has - // occurred. - c = mMainConnection->connectionWithSocket( (void*)this ); - - // if this is a libmsn socket - if (c != NULL) - { - if (c->isConnected() == false) - { - c->socketConnectionCompleted(); - } - // If this event is due to new data becoming available - c->socketIsWritable(); - } - - if ( c == mMainConnection ) - initPingTimer(); -} - -void WlmSocket::connectionFinished() -{ - delete mPingTimer; - mPingTimer = 0; -} - -void WlmSocket::incomingData() -{ - MSN::Connection * c; - - if ( !mMainConnection ) - return; - - // Retrieve the connection associated with the - // socket's file handle on which the event has - // occurred. - c = mMainConnection->connectionWithSocket((void*)this); - - // if this is a libmsn socket - if (c != NULL) - { - if (c->isConnected() == false) - { - c->socketConnectionCompleted(); - } - // If this event is due to new data becoming available - c->dataArrivedOnSocket(); - } -} - -void WlmSocket::resetPing() -{ - if ( mPingTimer ) - mPingTimer->start(); -} - -void WlmSocket::pingTimeout() -{ - if ( !mMainConnection || (mMainConnection->connectionState() < MSN::NotificationServerConnection::NS_CONNECTED) ) - return; - - MSN::Connection *c = mMainConnection->connectionWithSocket((void*)this); - if ( c == mMainConnection ) - mMainConnection->sendPing(); -} - -void WlmSocket::initPingTimer() -{ - if ( !mPingTimer ) - { - mPingTimer = new QTimer(); - QObject::connect( mPingTimer, SIGNAL(timeout()), this, SLOT(pingTimeout()) ); - mPingTimer->setInterval( 50000 ); - } - mPingTimer->start(); -} - diff --git a/protocols/wlm/wlmtransfermanager.h b/protocols/wlm/wlmtransfermanager.h deleted file mode 100644 --- a/protocols/wlm/wlmtransfermanager.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - wlmtransfermanager.h - Kopete Wlm Protocol - - Copyright (c) 2008 by Tiago Salem Herrmann - Kopete (c) 2002-2003 by the Kopete developers - - ************************************************************************* - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the 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 WLMTRANSFERMANAGER_H -#define WLMTRANSFERMANAGER_H - -#include - -#include "wlmaccount.h" -#include - -namespace Kopete -{ - class Transfer; - class FileTransferInfo; -} - -class WlmTransferManager:public QObject -{ - Q_OBJECT - public: - struct transferSessionData - { - QString from; - QString to; - bool incoming; - Kopete::Transfer * ft; - unsigned int internalID; - }; - - WlmTransferManager (WlmAccount * account); - ~WlmTransferManager (); - WlmAccount *account () - { - return m_account; - } - QMap < unsigned int, - transferSessionData > *getTransferSessions () - { - return &transferSessions; - } - void addTransferSession (unsigned int sessionID, Kopete::Transfer * ft, - QString from, QString to) - { - transferSessionData tsd; - tsd.from = from; - tsd.to = to; - tsd.ft = ft; - tsd.internalID = 0; - transferSessions[sessionID] = tsd; - } - - public slots: - - void incomingFileTransfer (MSN::SwitchboardServerConnection * conn, - const MSN:: - fileTransferInvite & ft); - - void gotFileTransferProgress (MSN::SwitchboardServerConnection * conn, - const unsigned int &sessionID, - const unsigned long long &transferred); - - void gotFileTransferFailed (MSN::SwitchboardServerConnection * conn, - const unsigned int &sessionID, - const MSN::fileTransferError &error); - - void gotFileTransferSucceeded (MSN::SwitchboardServerConnection * conn, - const unsigned int &sessionID); - - void slotAccepted (Kopete::Transfer * ft, const QString & filename); - - void slotRefused (const Kopete::FileTransferInfo & fti); - - void slotCanceled (); - - void fileTransferInviteResponse (MSN::SwitchboardServerConnection * conn, - const unsigned int &sessionID, - const bool & response); - - private: - QMap < unsigned int, transferSessionData > transferSessions; - WlmAccount *m_account; - unsigned int nextID; -}; -#endif diff --git a/protocols/wlm/wlmtransfermanager.cpp b/protocols/wlm/wlmtransfermanager.cpp deleted file mode 100644 --- a/protocols/wlm/wlmtransfermanager.cpp +++ /dev/null @@ -1,329 +0,0 @@ -/* - wlmtransfermanager.cpp - Kopete Wlm Protocol - - Copyright (c) 2008 by Tiago Salem Herrmann - Kopete (c) 2002-2003 by the Kopete developers - - ************************************************************************* - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the 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 "wlmtransfermanager.h" -#include "wlmcontact.h" -#include "kopetecontact.h" -#include "kopeteuiglobal.h" -#include "kopetetransfermanager.h" - -#include -#include -#include -#include - -#include - -WlmTransferManager::WlmTransferManager (WlmAccount * account1) : -m_account (account1), -nextID (1) -{ - QObject::connect (&account ()->server ()->cb, - SIGNAL (incomingFileTransfer - (MSN::SwitchboardServerConnection *, - const MSN::fileTransferInvite &)), this, - SLOT (incomingFileTransfer - (MSN::SwitchboardServerConnection *, - const MSN::fileTransferInvite &))); - - QObject::connect (&account ()->server ()->cb, - SIGNAL (gotFileTransferProgress - (MSN::SwitchboardServerConnection *, - const unsigned int &, - const unsigned long long &)), this, - SLOT (gotFileTransferProgress - (MSN::SwitchboardServerConnection *, - const unsigned int &, - const unsigned long long &))); - - QObject::connect (&account ()->server ()->cb, - SIGNAL (gotFileTransferFailed (MSN::SwitchboardServerConnection *, - const unsigned int &, const MSN::fileTransferError&)), - this, - SLOT (gotFileTransferFailed (MSN::SwitchboardServerConnection *, - const unsigned int &, const MSN::fileTransferError&))); - - QObject::connect (&account ()->server ()->cb, - SIGNAL (gotFileTransferSucceeded - (MSN::SwitchboardServerConnection *, - const unsigned int &)), this, - SLOT (gotFileTransferSucceeded (MSN::SwitchboardServerConnection *, - const unsigned int &))); - - QObject::connect (&account ()->server ()->cb, - SIGNAL (slotfileTransferInviteResponse - (MSN::SwitchboardServerConnection *, - const unsigned int &, const bool &)), this, - SLOT (fileTransferInviteResponse - (MSN::SwitchboardServerConnection * , - const unsigned int &, const bool &))); - - connect (Kopete::TransferManager::transferManager (), - SIGNAL (accepted(Kopete::Transfer*,QString)), - this, SLOT (slotAccepted(Kopete::Transfer*,QString))); - connect (Kopete::TransferManager::transferManager (), - SIGNAL (refused(Kopete::FileTransferInfo)), - this, SLOT (slotRefused(Kopete::FileTransferInfo))); -} - -void -WlmTransferManager::fileTransferInviteResponse (MSN::SwitchboardServerConnection * /*conn*/, - const unsigned int &sessionID, - const bool & response) -{ - if(!transferSessions.count(sessionID)) - return; - - if (response) - { - transferSessionData tfd = transferSessions[sessionID]; - Kopete::ContactPtrList chatmembers; - chatmembers.append (account ()->contacts().value(tfd.to)); - WlmChatSession *_manager = - qobject_cast (Kopete::ChatSessionManager::self ()-> - findChatSession (account ()->myself (), chatmembers, - account ()->protocol ())); - if (!_manager) - { - _manager = - new WlmChatSession (account ()->protocol (), - account ()->myself (), chatmembers); - } - } - else - { - transferSessionData tfd = transferSessions[sessionID]; - if(tfd.internalID) - Kopete::TransferManager::transferManager()-> - cancelIncomingTransfer(tfd.internalID); - else - tfd.ft->slotError(KIO::ERR_ABORTED, i18n("File transfer cancelled.")); - } -} - -WlmTransferManager::~WlmTransferManager () -{ -} - -void -WlmTransferManager::incomingFileTransfer (MSN::SwitchboardServerConnection * conn, - const MSN::fileTransferInvite & ft) -{ - QString passport = WlmUtils::passport(ft.userPassport); - Kopete::Contact * contact = account ()->contacts().value(passport); - - if(!contact) - return; - - if (ft.type == MSN::FILE_TRANSFER_WITH_PREVIEW - || ft.type == MSN::FILE_TRANSFER_WITHOUT_PREVIEW) - { - QPixmap preview; - if (ft.type == MSN::FILE_TRANSFER_WITH_PREVIEW) - { - preview.loadFromData (KCodecs::base64Decode (ft.preview.c_str())); - } - transferSessionData tsd; - tsd.from = passport; - tsd.to = account ()->myself ()->contactId (); - tsd.ft = NULL; - tsd.internalID = 0; - account ()->chatManager ()->createChat (conn); - WlmChatSession *chat = account ()->chatManager ()->chatSessions[conn]; - if(chat) - chat->setCanBeDeleted (false); - - tsd.internalID = Kopete::TransferManager::transferManager()->askIncomingTransfer(contact, - WlmUtils::utf8(ft.filename), ft.filesize, "", QString::number (ft.sessionId), preview); - transferSessions[ft.sessionId] = tsd; - } -} - -void -WlmTransferManager::gotFileTransferProgress (MSN::SwitchboardServerConnection * /*conn*/, - const unsigned int &sessionID, - const unsigned long long - &transferred) -{ - if(!transferSessions.count(sessionID)) - return; - - Kopete::Transfer * transfer = transferSessions[sessionID].ft; - if (transfer) - transfer->slotProcessed (transferred); -} - -void -WlmTransferManager::slotAccepted (Kopete::Transfer * ft, - const QString & filename) -{ - Kopete::ContactPtrList chatmembers; - - // grab contactId from the sender - unsigned int sessionID = ft->info ().internalId ().toUInt (); - - if(!transferSessions.count(sessionID)) - return; - - QString from = transferSessions[sessionID].from; - - if (from.isEmpty ()) - return; - - // find an existent session, or create a new one - chatmembers.append (account ()->contacts().value(from)); - WlmChatSession *_manager = qobject_cast - (Kopete::ChatSessionManager::self ()-> - findChatSession (account ()->myself (), chatmembers, - account ()->protocol ())); - - if (!_manager) - { - _manager = - new WlmChatSession (account ()->protocol (), - account ()->myself (), chatmembers); - } - - MSN::SwitchboardServerConnection * conn = _manager->getChatService (); - if (!conn) - return; - - _manager->setCanBeDeleted (false); - transferSessions[sessionID].ft = ft; - - connect (ft, SIGNAL (transferCanceled()), this, SLOT (slotCanceled())); - - conn->fileTransferResponse (sessionID, QFile::encodeName(filename).constData (), true); -} - -void -WlmTransferManager::slotRefused (const Kopete::FileTransferInfo & fti) -{ - Kopete::ContactPtrList chatmembers; - chatmembers.append (fti.contact ()); - WlmChatSession *_manager = qobject_cast - (Kopete::ChatSessionManager::self ()-> - findChatSession (account ()->myself (), chatmembers, - account ()->protocol ())); - - if (!_manager) - return; - - MSN::SwitchboardServerConnection * conn = _manager->getChatService (); - if (!conn) - return; - - conn->fileTransferResponse (fti.internalId ().toUInt (), "", false); -} - -void -WlmTransferManager::gotFileTransferFailed (MSN::SwitchboardServerConnection * /*conn*/, - const unsigned int &sessionID, - const MSN::fileTransferError & /*error*/) -{ - if(!transferSessions.count(sessionID)) - return; - - transferSessionData tsd = transferSessions[sessionID]; - if (tsd.internalID) - { - Kopete::TransferManager::transferManager ()-> - cancelIncomingTransfer(tsd.internalID); - if(tsd.ft) - tsd.ft->slotError(KIO::ERR_ABORTED, i18n("File transfer cancelled.")); - } - else - { - if (tsd.ft) - { - tsd.ft->slotError(KIO::ERR_ABORTED, i18n("File transfer cancelled.")); - } - } - transferSessions.remove (sessionID); - -} - -void -WlmTransferManager::gotFileTransferSucceeded (MSN::SwitchboardServerConnection * /*conn*/, - const unsigned int &sessionID) -{ - Kopete::Transfer * transfer = transferSessions[sessionID].ft; - if (transfer) - { - Kopete::ContactPtrList chatmembers; - if (transfer->info ().direction () == - Kopete::FileTransferInfo::Incoming) - chatmembers.append (account ()->contacts().value(transferSessions[sessionID].from)); - else - chatmembers.append (account ()->contacts().value(transferSessions[sessionID].to)); - - WlmChatSession *_manager = qobject_cast - (Kopete::ChatSessionManager::self ()-> - findChatSession (account ()->myself (), chatmembers, - account ()->protocol ())); - if (_manager) - _manager->raiseView (); - transfer->slotComplete (); - transferSessions.remove (sessionID); - } -} - -void -WlmTransferManager::slotCanceled () -{ - kDebug (14210) << k_funcinfo; - Kopete::Transfer * ft = qobject_cast < Kopete::Transfer * >(sender ()); - if (!ft) - return; - unsigned int sessionID = 0; - QMap < unsigned int, transferSessionData >::iterator i = - transferSessions.begin (); - for (; i != transferSessions.end (); ++i) - if (i.value ().ft == ft) - sessionID = i.key (); - - if (!sessionID) - return; - - transferSessionData session = transferSessions[sessionID]; - - Kopete::ContactPtrList chatmembers; - if (ft->info ().direction () == Kopete::FileTransferInfo::Incoming) - chatmembers.append (account ()->contacts().value(session.from)); - else - chatmembers.append (account ()->contacts().value(session.to)); - - WlmChatSession *_manager = qobject_cast - (Kopete::ChatSessionManager::self ()-> - findChatSession (account ()->myself (), chatmembers, - account ()->protocol ())); - - if (!_manager) - return; - _manager->raiseView (); - - MSN::SwitchboardServerConnection * conn = _manager->getChatService (); - - if (!conn) - return; - - if (sessionID) - { - transferSessions.remove (sessionID); - conn->cancelFileTransfer (sessionID); - } -} -